Skip to content

Instantly share code, notes, and snippets.

@hugsy
Created September 6, 2016 01:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hugsy/edb4bbbb63fde3a2a49ec52845b372c4 to your computer and use it in GitHub Desktop.
Save hugsy/edb4bbbb63fde3a2a49ec52845b372c4 to your computer and use it in GitHub Desktop.
TWCTF 2016 - reverse_box
#!/usr/bin/python
#
# @_hugsy_
#
# $ python /tmp/uni.py
# >>> init randint is d6
# The flag is TWCTF{5UBS717U710N_C1PH3R_W17H_R4ND0M123D_5-B0X}
#
import unicorn
def emulate(eax):
emu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32 + unicorn.UC_MODE_LITTLE_ENDIAN)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EAX, eax)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0)
emu.reg_write(unicorn.x86_const.UC_X86_REG_ECX, 0x14d4e658)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EDX, 0xf7fa63e4)
emu.reg_write(unicorn.x86_const.UC_X86_REG_ESP, 0xffffd220)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EBP, 0xffffd248)
emu.reg_write(unicorn.x86_const.UC_X86_REG_ESI, 0xf7fa6000)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EDI, 0xf7fa6000)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EIP, 0x80485b1)
emu.reg_write(unicorn.x86_const.UC_X86_REG_EFLAGS, 0x202)
emu.mem_map(0x0, 4096, 3)
emu.mem_map(0x1000, 4096, 3)
emu.mem_map(0x8048000, 4096, 5)
# Importing /home/hugsy/ctf/tokyo_western_ctf_2016/reverse_box: 0x8048000-0x8049000
data=open('/tmp/gef-0x8048000.raw', 'r').read()
emu.mem_write(0x8048000, data)
emu.mem_map(0x8049000, 4096, 1)
# Importing /home/hugsy/ctf/tokyo_western_ctf_2016/reverse_box: 0x8049000-0x804a000
data=open('/tmp/gef-0x8049000.raw', 'r').read()
emu.mem_write(0x8049000, data)
emu.mem_map(0x804a000, 4096, 3)
# Importing /home/hugsy/ctf/tokyo_western_ctf_2016/reverse_box: 0x804a000-0x804b000
data=open('/tmp/gef-0x804a000.raw', 'r').read()
emu.mem_write(0x804a000, data)
emu.mem_map(0xf7df7000, 1757184, 5)
# Importing /lib/i386-linux-gnu/libc-2.23.so: 0xf7df7000-0xf7fa4000
data=open('/tmp/gef-0xf7df7000.raw', 'r').read()
emu.mem_write(0xf7df7000, data)
emu.mem_map(0xf7fa4000, 8192, 1)
# Importing /lib/i386-linux-gnu/libc-2.23.so: 0xf7fa4000-0xf7fa6000
data=open('/tmp/gef-0xf7fa4000.raw', 'r').read()
emu.mem_write(0xf7fa4000, data)
emu.mem_map(0xf7fa6000, 4096, 3)
# Importing /lib/i386-linux-gnu/libc-2.23.so: 0xf7fa6000-0xf7fa7000
data=open('/tmp/gef-0xf7fa6000.raw', 'r').read()
emu.mem_write(0xf7fa6000, data)
emu.mem_map(0xf7fa7000, 12288, 3)
# Importing : 0xf7fa7000-0xf7faa000
data=open('/tmp/gef-0xf7fa7000.raw', 'r').read()
emu.mem_write(0xf7fa7000, data)
emu.mem_map(0xf7fd2000, 8192, 3)
# Importing : 0xf7fd2000-0xf7fd4000
data=open('/tmp/gef-0xf7fd2000.raw', 'r').read()
emu.mem_write(0xf7fd2000, data)
emu.mem_map(0xf7fd4000, 12288, 1)
emu.mem_map(0xf7fd7000, 8192, 5)
# Importing [vdso]: 0xf7fd7000-0xf7fd9000
data=open('/tmp/gef-0xf7fd7000.raw', 'r').read()
emu.mem_write(0xf7fd7000, data)
emu.mem_map(0xf7fd9000, 139264, 5)
# Importing /lib/i386-linux-gnu/ld-2.23.so: 0xf7fd9000-0xf7ffb000
data=open('/tmp/gef-0xf7fd9000.raw', 'r').read()
emu.mem_write(0xf7fd9000, data)
emu.mem_map(0xf7ffb000, 4096, 3)
# Importing : 0xf7ffb000-0xf7ffc000
data=open('/tmp/gef-0xf7ffb000.raw', 'r').read()
emu.mem_write(0xf7ffb000, data)
emu.mem_map(0xf7ffc000, 4096, 1)
# Importing /lib/i386-linux-gnu/ld-2.23.so: 0xf7ffc000-0xf7ffd000
data=open('/tmp/gef-0xf7ffc000.raw', 'r').read()
emu.mem_write(0xf7ffc000, data)
emu.mem_map(0xf7ffd000, 4096, 3)
# Importing /lib/i386-linux-gnu/ld-2.23.so: 0xf7ffd000-0xf7ffe000
data=open('/tmp/gef-0xf7ffd000.raw', 'r').read()
emu.mem_write(0xf7ffd000, data)
emu.mem_map(0xfffdd000, 135168, 3)
# Importing [stack]: 0xfffdd000-0xffffe000
data=open('/tmp/gef-0xfffdd000.raw', 'r').read()
emu.mem_write(0xfffdd000, data)
emu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
try:
emu.emu_start(0x80485b1, 0x80486e0)
except Exception as e:
emu.emu_stop()
print('Error: {}'.format(e))
return emu
def find_init_randint():
for i in range(256):
emu = emulate(i)
mem = emu.mem_read(0xffffd26c, 0x100)
if mem[ord('T')]==0x95 and mem[ord('W')]==0xee:
return i
return None
init = find_init_randint()
if init is None:
sys.exit(1)
print ">>> init randint is %x" % init
t = "95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a".decode("hex")
emu = emulate(init)
c = emu.mem_read(0xffffd26c, 0x100)
b = ""
for i in range(len(t)):
j = c.find(t[i])
b+= chr(j)
print "The flag is", b
# Unicorn script generated by gef
@pwntester
Copy link

Thanks for the post! It is a very useful approach! Tried to use gef/unicorn to reproduce your solution but got segmentation faults when the generated code is writing to CS,SS,DS,ES,FS,GS and UC_X86_REG_GS. eg:

emu.reg_write(unicorn.x86_const.UC_X86_REG_GS, 0x1000)

Commented out these writes since they should not be critical for this procedure and got it working. But wondering why Im getting a segfault when writing to these emulated registers. Any ideas?

@hugsy
Copy link
Author

hugsy commented Sep 6, 2016

Oh yeah you're right, I forgot to mention that in the post.
gef will export all the registers it knows to the unicorn script, including the segmentation selectors (CS,DS,SS,etc.) which afaik unicorn does not support segmentation properly. The problem is that CS, DS, etc. are not GPR registers but selectors, and unicorn does not define a base or limit for them by default. This only affects x86-32.

A quick (but very bad) hack to have those running would be to assign the values of those registers to a fake mmaped area.
Or better, as you said, simply commenting/removing those does the trick since no address in the function depends on the value of any of the segment selectors (like for example when the stack canary is stored in GS).

@pwntester
Copy link

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment