본문 바로가기

WARGAME/hackerschool ftz,lob

[LOB 페도라 FC3] iron_golem -> dark_eyes

소스는 다음과 같다.

int main ( int argc, char *argv[])

{

char buffer[256];

char saved_sfp[4];


if(argc<2) {

printf("argv error\n");

exit(0);

}


memcpy(saved_sfp, buffer+264, 4);


strcpy(buffer, argv[1]);


memcpy(buffer+264, saved_sfp, 4);

printf("%s\n", buffer);

}



이번 문제는 소스를 보면 실행 되었을 때 정상적인 sfp 값을 저장해 놨다가 사용자에게 어떤 값을 입력 받고 다시 sfp값을 돌려 놓는 부분이 추가 되었다.

이전 문제에서는 fake ebp 방법을 사용해서 esp를 우리가 사용하고자 하는 execl()함수의 인자 부분으로 돌려 놓았는데, 이번에는 이게 불가능하다. 

hint는 RET썰매를 이용하면 된다고 하는데, 검색해보니 어셈블리어의 ret을 계속 써줘서 esp를 움직일 수 있다고 한다.

파일을 디스어셈블해서 하단부를 보면 leave, ret으로 마치게 되는데, 여기서 leave, ret은 다음과 같다.




leave 

     mov ebp, esp

     pop ebp


ret

pop esp



leave에서는 ebp가 가르키는 값을 esp에 넣고 스택에서 ebp로 빼서 esp를 이동 시킨다.

그 다음 ret에서는 현재 esp가 가르키고 있는 값을 eip에 넣고 (eip는 다음 실행될 명령어를 가지는 레지스터) pop esp하여 스택에서 ret값을 제거한다.



여기까지 알아보면 이전 문제에서는 fake ebp를 이용하여 esp 값을 조종했는데, 이번 문제는 스택의 위치에 어셈블리어 ret 주소를 계속 써줘서 pop esp를 계속 읽어 esp값을 원하는 위치로 조종하는 것이라고 할 수 있을 것 같다.


그렇다면 이번 문제의 접근은 이전 문제와는 다르게 execve() 함수를 이용하여 풀도록 하고 스택의 ret 위치에 어셈블리어 ret의 주소를 원하는 만큼 써주어 esp+8위치에 execve() 함수의 매개변수들로 사용할 값들을 찾으면 될 것 같다.


(이미 풀이 후 작성하는 write-up이라 execl()함수로 시도를 했었는데, 자꾸 segmentation default가 떠서 검색해보니 execl()함수의 두 번째 인자로 들어가는 값이 0x00000000인 경우엔 segmentation default가 뜬다고 하여 execve()로 풀이 하였다.)


요약하면 다음과 같다.

1. 스택 구조 확인

2. 어셈블리어 ret 주소 확인

3. execve()함수 주소 확인

4. leave를 읽은 다음의 스택 구조에서 execl()의 매개변수로 쓸만한 주소 확인

5. 쉘 권한을 주는 소스 작성 후 4번에서 얻은 값으로 심볼릭 링크

6. 공격 파라미터 작성 [Ax268][&ret][&ret]...... [execl()]






먼저 스택 구조를 확인해 본다.



buffer[256]과 saved_sfp[4]는 총 260 바이트이고 gdb로 확인해보면 실제로는 280바이트를 할당하고 있어 20바이트의 더미가 있다는 것을 알 수 있다.


그렇다면 스택 구조는 다음과 같다고 예측해볼 수 있다.


low address ... | saved_sfp | dummy | buffer | dummy | sfp | ret | ... high address



overflow가 일어나는 변수인 buffer부터 sfp까지의 크기는 소스에서 볼 수 있듯이 264의 크기를 가지고 있다. 그렇다면 dummy의 크기를 예측해볼 수 있다.


low address ... | saved_sfp(4) | dummy(12) | buffer(256) | dummy(8) | sfp | ret | ... high address


그리고 ret의 주소는 다음과 같다.




세 번째로 execve()함수의 주소를 알아보도록 한다. 주소는 다음과 같다.








이제 네 번째로 execl() 함수의 매개변수로 쓸만한 인자들의 위치를 찾아야 하는데, 세 번째 인자로는 0x00000000 이 와야 하고, 프로그램 실행 초기에 설정되어 있는 ebp의 주소보다 높은 위치에서 찾아야 한다. 


그러기 위해서 leave가 끝나고 초기에 설정되어있는 ebp의 주소값으로 esp를 이동한 다음에 찾기 위해 leave 다음에 브레이크 포인트를 걸어주고 찾도록 해본다




위 사진을 보면 leave다음에 브레이크 포인트를 걸었고, 현재 esp부터 16개 주소를 출력해 보았다. 

그렇다면 맨 처음에 보이는 0x00730e33이 ret이 될 것이고 그다음의 0x00000002가 argc이고 뒤이어서 argv가 나올 것이다. 


이제 execl()함수의 매개변수로 쓸만한 값을 찾아야 하는데 매개변수로 이용될 때 esp+8로 이용되므로 위 사진에서는 0xfeeed9d4부터 찾아야 한다.


.... 찾아서 공격해본 결과 0xfeeed9d4는 스택 공간이라서 랜덤 스택이 적용되어서 계속 값이 바뀌게 되고, 이렇게 되면 심볼링 링크로 걸 파일의 파일명이 계속바뀌게 되어 공격이 실패할 수 밖에 없다.......


그래서 스택 공간의 주소는 제외하고 다시 찾아 보았다.








그 다음 주소로 0x0070eab6을 보면 16번째 주소에 0x00000188(화살표한 부분)로 끝나서 이를 파일명으로 쓰려면 0x83f0558b부터 다적어야 되기 때문에 일단 보류하기로 하고 다음 주소를 보면 0x0083eb3c로 적당하게 파일명으로 사용 할 수 있을 것 같다. 


이제 shell.c를 작성하고 컴파일 후 다음과 같이 "\x3c\xed\x83"으로 심볼릭 링크를 걸어준다.






마지막으로 공격 파라미터를 작성해야 한다.

./dark_eyes `perl -e 'print "A"x268, "\xb9\x84\x04\x08"x3, "\x90\x54\x7a"'`


구조는 다음과 같다.

A를 buffer(256)+dummy(8)+sfp(4) 만큼 덮어주고 ret위치에 &ret을 세번 넣는다. 

이렇게 되면 다음 사진에서 화살표 위치에 esp가 위치하게 된다.




그리고 execve()함수가 실행되면 push $ebp      mov $esp, $ebp 가 실행되면서 스택 구조는 아래와 같아 진다.


이제 execve()함수에서 매개변수를 참조 할 때 첫 번쨰 매개변수로 ebp+8, 두 번째 매개변수로 ebp+c ... 를 참조하기 때문에

첫 번째 매개변수로 0x0083eff4를 참조하고 두번째 매개변수로 0x00000000 .... 을 참조하여 execve()함수가 실행되고 쉘이 떨어진다.










이전 문제와 같이 execl, execv 함수로도 풀이해봤는데, 이상없이 쉘이 떨어진다. 

(단, execl함수의 경우엔 주소에 \x20이 포함되어 있는데, \x00으로 인식하므로 ""로 한번 더 덮어줘야 함)