본문으로 바로가기

해커스쿨 LOB assassin 풀이, write up

category Wargame/LOB 2018. 9. 17. 01:32

assassin --- pushing me away



문제 풀기 전에 아래의 명령어를 반드시 쳐야한다.


$export SHELL=/bin/bash2

$/bin/bash2



우선 assassin의 디렉터리를 확인한다.






zombie_assassin이라는 의심스러운 파일이 존재한다. zomebie_assassin은 zombie_assassin의 권한을 가지고 있고, setuid가 걸려있는 파일이다.



zombie_assassin.c를 가지고 zombie_assassin elf 파일을 만들었을 가능성이 있기 때문에, zombie_assassin 파일을 본 뒤 어떤 취약점을 가지고 있는지 확인해보자.





지역 변수를 선언한다.



1
char buffer[40];                                                                    
cs




인자의 개수가 없으면 "argv error\n"를 출력하고 종료한다.



1
2
3
4
5
if(argc < 2)
{
    printf("argv error\n");                                                            
    exit(0);
}
cs




첫 번째 인자의 48번째 문자가 '\xbf'이면 "stack retbayed you!\n"를 출력하고 종료한다.



1
2
3
4
5
if(argv[1][47== '\xbf')
{
    printf("stack retbayed you!\n");                                                
    exit(0);
}
cs


 

첫 번째 인자의 48번째 문자가 '\x40'이면 "library retbayed you, too!\n"를 출력하고 종료한다.



1
2
3
4
5
if(argv[1][47== '\x40')
{
    printf("library retbayed you, too!!\n");                                        
    exit(0);
}
cs



첫 번째 인자 중 최대 48 byte만 buffer에 저장하고 출력한다.



1
2
strncpy(buffer, argv[1], 48);                                                        
pritnf(*%s\n", buffer);
cs




zombie_assassin의 메모리 구조를 예상해보면 아래와 같다.





실제 변수가 할당될 때, gcc가 최적화를 위해 자동적으로 dummy를 생성할 수 있다.


gdb를 이용해여 zombie_assassin을 분석해보자. zombie_assassin을 gdb로 실행하는 도중 permission denied가 발생하면 cp 명령을 이용하여 파일을 복사하면 된다. 현재 user의 권한으로 똑같은 파일을 가질 수 있기 때문이다.





위와 같이 zombie_assassin가 assassin의 권한으로 복사된 것을 확인할 수 있다.



dummy가 생성되었는지  gdb를 통해 확인해보자.







dummy가 추가적으로 생성되지 않고 정확히 40(0x28) byte가 생성된 것을 확인할 수 있다.



zombie_assassin을 보면 FEBP를 힌트로 주었다.

FEBP는 Fake EBP라는 뜻이므로 FEBP에 대해 공부 해야 한다.


Stack 영역과 shared library 영역을 사용할 수 없고 strncpy() 함수로 인해, 최대 48 byte를 복사할 수 있다.



이번에도 중요한 개념은 에필로그에 대한 개념이다.


함수의 에필로그는 두 개의 어셈블리 명령어로 이루어져 있다.


leave

ret


leave와 ret은 각각 두 개의 어셈블리 명령을 수행하는 명령어이다.


leave


move esp, ebp

pop ebp


ret


pop eip

jmp eip



FEBP의 공격은 아래와 같은 payload로 진행된다.



40byte의 더미 + 공격하고 싶은 주소 - 4 + leave







첫 leave 명령어를 만나면 mov esp, ebp를 하고 나서, pop ebp를 한다.

leave 명령어의 mov esp, ebp는 딱히 의미가 없고 pop ebp를 하면 ebp에 (&주소-4)이 저장된다.

ret 명령어를 통해 EIP에 leave의 주소가 저장되어있기 때문에 leave가 한 번 더 실행된다.


두 번째 leave 명령어를 만나면 mov esp, ebp를 하고 나서, pop ebp를 한다.

여기서 ebp에 (&주소-4)이 저장되어 있기 때문에 esp는 (&주소-4)가 저장된다.

pop ebp를 통해 어떠한 값이 ebp에 저장되고, esp가 +4증가(esp = &주소)한다.

ret 명령어를 통해 &주소를 실행한다.



우리는 쉘코드를 buffer에 삽입할 것이다. buffer의 주소는 아래와 같이 구할 수 찾을 수 있다.





buffer의 시작주소는 0xbffffa90이다. leave의 주소는 0x80484df이다.




약간의 조정과 함께 clear할 수 있다.