def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True): pkt = smb.NewSMBPacket() pkt['Tid'] = tid command = pack('<H', setup) transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() transCommand['Parameters']['MaxSetupCount'] = 1 transCommand['Parameters']['MaxParameterCount'] = len(param) transCommand['Parameters']['MaxDataCount'] = 0 transCommand['Data'] = smb.SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) fixedOffset = 32 + 3 + 38 + len(command) if len(param) > 0: padLen = (4 - fixedOffset % 4) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen if len(data) > 0: pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = firstDataFragmentSize transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize] pkt.addCommand(transCommand) conn.sendSMB(pkt) conn.recvSMB() # must be success i = firstDataFragmentSize while i < len(data): sendSize = min(4096, len(data) - i) if len(data) - i <= 4096: if not sendLastChunk: break send_trans2_second(conn, tid, data[i:i + sendSize], i) i += sendSize if sendLastChunk: conn.recvSMB() return i
def smbTransaction2(packet, packetNum, SMBCommand, questions, replies): # Test return code is always 0, otherwise leave before doing anything if packet['ErrorCode'] != 0: return False print "SMB_COM_TRANSACTION2 ", try: if (packet['Flags1'] & smb.SMB.FLAGS1_REPLY) == 0: # Query trans2Parameters = smb.SMBTransaction2_Parameters( SMBCommand['Parameters']) # Do the stuff if trans2Parameters['ParameterCount'] != trans2Parameters[ 'TotalParameterCount']: # TODO: Handle partial parameters #print "Unsupported partial parameters in TRANSACT2!" raise Exception("Unsupported partial parameters in TRANSACT2!") else: trans2Data = smb.SMBTransaction2_Data() # Standard says servers shouldn't trust Parameters and Data comes # in order, so we have to parse the offsets, ugly paramCount = trans2Parameters['ParameterCount'] trans2Data['Trans_ParametersLength'] = paramCount dataCount = trans2Parameters['DataCount'] trans2Data['Trans_DataLength'] = dataCount if trans2Parameters['ParameterOffset'] > 0: paramOffset = trans2Parameters[ 'ParameterOffset'] - 63 - trans2Parameters[ 'SetupLength'] trans2Data['Trans_Parameters'] = SMBCommand['Data'][ paramOffset:paramOffset + paramCount] else: trans2Data['Trans_Parameters'] = '' if trans2Parameters['DataOffset'] > 0: dataOffset = trans2Parameters[ 'DataOffset'] - 63 - trans2Parameters['SetupLength'] trans2Data['Trans_Data'] = SMBCommand['Data'][ dataOffset:dataOffset + dataCount] else: # Response # ToDo not implemented yet a = 1 except Exception, e: print "ERROR: %s" % e print "Command: 0x%x" % packet['Command'] print "Packet: %d %r" % (packetNum, packet.getData()) return True
def send_nt_trans(tid, setup, data, param, firstDataCnt): pkt = smb.NewSMBPacket() pkt['Tid'] = tid command = pack('<H', setup) transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() transCommand['Parameters']['MaxSetupCount'] = 1 transCommand['Parameters']['MaxParameterCount'] = len(param) transCommand['Parameters']['MaxDataCount'] = 0 transCommand['Data'] = smb.SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) fixedOffset = 32+3+38 + len(command) if len(param) > 0: padLen = (4 - fixedOffset % 4 ) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen if len(data) > 0: pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = firstDataCnt transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data[:firstDataCnt] pkt.addCommand(transCommand) conn.sendSMB(pkt) i = firstDataCnt while i < len(data): sendSize = min(4096, len(data) - i) send_trans2_second(tid, data[i:i+sendSize], i) i += sendSize conn.recvSMB()
def send_trans2(conn, tid, setup, name, param, data): pkt = smb.NewSMBPacket() pkt['Tid'] = tid command = pack('<H', setup) transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2) transCommand['Parameters'] = smb.SMBTransaction2_Parameters() transCommand['Parameters']['MaxDataCount'] = len(data) transCommand['Data'] = smb.SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) if len(param) > 0: padLen = (4 - (32 + 2 + 28 + len(command)) % 4) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = 32 + 2 + 28 + len( command) + len(name) + padLen if len(data) > 0: pad2Len = (4 - (32 + 2 + 28 + len(command) + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = len(data) transCommand['Parameters']['DataOffset'] = transCommand['Parameters'][ 'ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Name'] = name transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data pkt.addCommand(transCommand) conn.sendSMB(pkt)
def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True): pkt = smb.NewSMBPacket() pkt['Tid'] = tid command = pack('<H', setup) # Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug. transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() transCommand['Parameters']['MaxSetupCount'] = 1 transCommand['Parameters']['MaxParameterCount'] = len(param) transCommand['Parameters']['MaxDataCount'] = 0 transCommand['Data'] = smb.SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) fixedOffset = 32+3+38 + len(command) if len(param) > 0: padLen = (4 - fixedOffset % 4 ) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen if len(data) > 0: pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = firstDataFragmentSize transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize] pkt.addCommand(transCommand) conn.sendSMB(pkt) recvPkt = conn.recvSMB() # must be success if recvPkt.getNTStatus() == 0: module.log('got good NT Trans response') else: module.log('got bad NT Trans response: 0x{:x}'.format(recvPkt.getNTStatus()), 'error') sys.exit(1) # Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data i = firstDataFragmentSize while i < len(data): sendSize = min(4096, len(data) - i) if len(data) - i <= 4096: if not sendLastChunk: break send_trans2_second(conn, tid, data[i:i+sendSize], i) i += sendSize if sendLastChunk: conn.recvSMB() return i
def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True): # Here is another bug in MS17-010. # To call transaction subcommand, normally a client need to use correct SMB commands as documented in # https://msdn.microsoft.com/en-us/library/ee441514.aspx # If a transaction message is larger than SMB message (MaxBufferSize in session parameter), a client # can use *_SECONDARY command to send transaction message. When sending a transaction completely with # *_SECONDARY command, a server uses the last command that complete the transaction. # For example: # - if last command is SMB_COM_NT_TRANSACT_SECONDARY, a server executes subcommand as NT_TRANSACT_*. # - if last command is SMB_COM_TRANSACTION2_SECONDARY, a server executes subcommand as TRANS2_*. # # Without MS17-010 patch, a client can mix a transaction command if TID, PID, UID, MID are the same. # For example: # - a client start transaction with SMB_COM_NT_TRANSACT command # - a client send more transaction data with SMB_COM_NT_TRANSACT_SECONDARY and SMB_COM_TRANSACTION2_SECONDARY # - a client sned last transactino data with SMB_COM_TRANSACTION2_SECONDARY # - a server executes transaction subcommand as TRANS2_* (first 2 bytes of Setup field) # From https://msdn.microsoft.com/en-us/library/ee442192.aspx, a maximum data size for sending a transaction # with SMB_COM_TRANSACTION2 is 65535 because TotalDataCount field is USHORT # While a maximum data size for sending a transaction with SMB_COM_NT_TRANSACT is >65536 because TotalDataCount # field is ULONG (see https://msdn.microsoft.com/en-us/library/ee441534.aspx). # Note: a server limit SetupCount+TotalParameterCount+TotalDataCount to 0x10400 (in SrvAllocationTransaction) pkt = smb.NewSMBPacket() pkt['Tid'] = tid command = pack('<H', setup) # Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug. transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() transCommand['Parameters']['MaxSetupCount'] = 1 transCommand['Parameters']['MaxParameterCount'] = len(param) transCommand['Parameters']['MaxDataCount'] = 0 transCommand['Data'] = smb.SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) fixedOffset = 32+3+38 + len(command) if len(param) > 0: padLen = (4 - fixedOffset % 4 ) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen if len(data) > 0: pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = firstDataFragmentSize transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize] pkt.addCommand(transCommand) conn.sendSMB(pkt) conn.recvSMB() # must be success # Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data i = firstDataFragmentSize while i < len(data): # limit data to 4096 bytes per SMB message because this size can be used for all Windows version sendSize = min(4096, len(data) - i) if len(data) - i <= 4096: if not sendLastChunk: break send_trans2_second(conn, tid, data[i:i+sendSize], i) i += sendSize if sendLastChunk: conn.recvSMB() return i
def send_big_transfer(connection, tid, setup, data, params, first_fragment, send_last=True): packet = smb.NewSMBPacket() packet['Tid'] = tid command = struct.pack('<H', setup) # Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug. transfer_command = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transfer_command['Parameters'] = smb.SMBNTTransaction_Parameters() transfer_command['Parameters']['MaxSetupCount'] = 1 transfer_command['Parameters']['MaxParameterCount'] = len(params) transfer_command['Parameters']['MaxDataCount'] = 0 transfer_command['Data'] = smb.SMBTransaction2_Data() transfer_command['Parameters']['Setup'] = command transfer_command['Parameters']['TotalParameterCount'] = len(params) transfer_command['Parameters']['TotalDataCount'] = len(data) fixed_offset = 32 + 3 + 38 + len(command) if len(params) > 0: pad_len = (4 - fixed_offset % 4) % 4 pad_bytes = '\xFF' * pad_len transfer_command['Data']['Pad1'] = pad_bytes else: transfer_command['Data']['Pad1'] = '' pad_len = 0 transfer_command['Parameters']['ParameterCount'] = len(params) transfer_command['Parameters'][ 'ParameterOffset'] = fixed_offset + pad_len if len(data) > 0: pad_to_len = (4 - (fixed_offset + pad_len + len(params)) % 4) % 4 transfer_command['Data']['Pad2'] = '\xFF' * pad_to_len else: transfer_command['Data']['Pad2'] = '' pad_to_len = 0 transfer_command['Parameters']['DataCount'] = first_fragment transfer_command['Parameters']['DataOffset'] = transfer_command['Parameters']['ParameterOffset'] + \ len(params) + pad_to_len transfer_command['Data']['Trans_Parameters'] = params transfer_command['Data']['Trans_Data'] = data[:first_fragment] packet.addCommand(transfer_command) connection.sendSMB(packet) connection.recvSMB() # must be success i = first_fragment while i < len(data): send_size = min(4096, len(data) - i) if len(data) - i <= 4096: if not send_last: break send_transfer_second(connection, tid, data[i:i + send_size], i) i += send_size if send_last: connection.recvSMB() return i