Example #1
0
    def attack(self, user, cryptPwd):
        # By default 500 most famous passwords are used for the dictionary attack
        dic = get_dico()
        # add the user on the list to found weak password (login equal password)
        dic.insert(0, user)

        # file for dictionary attack entered
        if constant.path:
            if os.path.exists(constant.path):
                dic = self.get_dic(constant.path)
            else:
                print_debug('WARNING',
                            'The file does not exist: %s' % str(constant.path))

        # 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)

        hashType = cryptPwd.split("$")[1]
        values = {'Category': 'System Account'}

        if hashType == '1':  # MD5
            print_debug('INFO', '[+] Hash type MD5 detected ...')
        elif hashType == '2':
            print_debug('INFO', '[+] Hash type Blowfish detected ...')
        elif hashType == '5':
            print_debug('INFO', '[+] Hash type SHA-256 detected ...')
        elif hashType == '6':  # ShA-512 => used by all modern computers
            print_debug('INFO', '[+] Hash type SHA-512 detected ...')

        salt = cryptPwd.split("$")[2]
        realSalt = "$" + hashType + "$" + salt + "$"

        # -------------------------- Dictionary attack --------------------------
        print_debug('INFO', 'Dictionary Attack on the hash !!! ')
        try:
            for word in dic:
                try:
                    cryptWord = crypt.crypt(word, realSalt)
                except Exception, e:
                    print_debug('DEBUG', '{0}'.format(e))
                    cryptWord = ''

                if cryptWord == cryptPwd:
                    values['User'] = user
                    values['password'] = word
                    self.pwdFound.append(values)
                    return
        except (KeyboardInterrupt, SystemExit):
            print 'INTERRUPTED!'
            print_debug('DEBUG', 'Dictionary attack interrupted')
        except Exception, e:
            print_debug('DEBUG', '{0}'.format(e))
Example #2
0
	def attack(self, user, cryptPwd):
		# By default 500 most famous passwords are used for the dictionary attack 
		dic = get_dico()
		# add the user on the list to found weak password (login equal password)
		dic.insert(0, user)

		# file for dictionary attack entered 
		if constant.path:
			if os.path.exists(constant.path):
				dic = self.get_dic(constant.path)
			else:
				print_debug('WARNING', 'The file does not exist: %s' %  str(constant.path))
		
		# 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)
		
		hashType = cryptPwd.split("$")[1]
		values = {'Category': 'System Account'}
		
		if hashType == '1': # MD5
			print_debug('INFO', '[+] Hash type MD5 detected ...')
		elif hashType == '2':
			print_debug('INFO', '[+] Hash type Blowfish detected ...')
		elif hashType == '5':
			print_debug('INFO', '[+] Hash type SHA-256 detected ...')
		elif hashType == '6': # ShA-512 => used by all modern computers
			print_debug('INFO', '[+] Hash type SHA-512 detected ...')

		salt = cryptPwd.split("$")[2]
		realSalt = "$" + hashType + "$" + salt + "$"
		
		# -------------------------- Dictionary attack --------------------------
		print_debug('INFO', 'Dictionary Attack on the hash !!! ')
		try:
			for word in dic:
				try:
					cryptWord = crypt.crypt(word, realSalt)
				except Exception,e:
					print_debug('DEBUG', '{0}'.format(e))
					cryptWord = ''

				if cryptWord == cryptPwd:
					values['User'] = user
					values['password'] = word
					self.pwdFound.append(values)
					return
		except (KeyboardInterrupt, SystemExit):
			print 'INTERRUPTED!'
			print_debug('DEBUG', 'Dictionary attack interrupted')
		except Exception,e:
			print_debug('DEBUG', '{0}'.format(e))
Example #3
0
	def dictionary_attack(self, login, md5):
		wordlist = get_dico()
		
		# if the user specify the file path
		if constant.path:
			wordlist += self.get_dic_file(constant.path)

		for word in wordlist:
			hash = hashlib.md5('%s\nskyper\n%s' % (login, word)).hexdigest()
			if hash == md5:
				return word
		return False
Example #4
0
	def dictionary_attack(self, login, md5):
		wordlist = get_dico()
		
		# if the user specify the file path
		if constant.path:
			wordlist += self.get_dic_file(constant.path)

		for word in wordlist:
			hash = hashlib.md5('%s\nskyper\n%s' % (login, word)).hexdigest()
			if hash == md5:
				return word
		return False
 def __init__(self):
     self.wordlist = get_dico() + constant.passwordFound
     options = {
         'command': '--hashes',
         'action': 'store_true',
         'dest': 'hashes',
         'help': 'retrieve system hashes'
     }
     ModuleInfo.__init__(self,
                         'hashes',
                         'windows',
                         options,
                         need_system_privileges=True)
Example #6
0
	def found_masterpassword(self):
		
		# 500 most used passwords
		wordlist = get_dico() + constant.passwordFound
		num_lines = (len(wordlist)-1)
		print_debug('ATTACK', u'%d most used passwords !!! ' % num_lines)

		for word in wordlist:
			if self.is_masterpassword_correct(word)[0]:
				print_debug('FIND', u'Master password found: {master_password}'.format(master_password=word.strip()))
				return word
			
		print_debug('WARNING', u'No password has been found using the default list')
		return False
Example #7
0
    def run(self, software_name=None):
        userhashes = []

        if self.root_access():
            major, minor = self.check_version()
            if major == 10 and (minor == 3 or minor == 4):
                for user in self.list_users():
                    print_debug('INFO', 'User found: %s' % user)
                    userhash = self.get_user_hash_using_niutil(user)
                    if userhash:
                        userhashes.append(userhash)

            if major == 10 and (minor == 5 or minor == 6):
                for user in self.list_users():
                    print_debug('INFO', 'User found: %s' % user)
                    userhash = self.get_user_hash_using_dscl(user)
                    if userhash:
                        userhashes.append(userhash)

            # TO DO: manage version 10.7

            elif major == 10 and minor >= 8:
                usernames = [
                    plist.split(".")[0] for plist in os.listdir(
                        u'/var/db/dslocal/nodes/Default/users/')
                    if not plist.startswith(u'_')
                ]
                for username in usernames:
                    userhash = self.get_user_hash_from_plist(username)
                    if userhash:
                        userhashes.append(userhash)

                        # try to get the password in cleartext
                        passwords = constant.passwordFound  # check if passwords found in other applications are also used as system password
                        passwords.insert(
                            0, username
                        )  # add the user on the list to found weak password (login equal password)
                        if constant.user_password:
                            passwords.insert(0, constant.user_password)

                        found = self.dictionary_attack(username, passwords)

                        # realize a dictionary attack using the 500 most famous passwords
                        if constant.dictionary_attack and not found:
                            dic = get_dico()
                            dic.insert(0, self.username)
                            self.dictionary_attack(username, dic)

        return ['__SYSTEM__', userhashes]
Example #8
0
    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 as e:
                    pass

        except (KeyboardInterrupt, SystemExit):
            print_debug('DEBUG', u'Dictionary attack interrupted')

        return False
Example #9
0
	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 ('', '', '')
Example #10
0
    def brute_master_password(self, key_data, new_version=True):
        """
        Try to find master_password doing a dictionary attack using the 500 most used passwords
        """
        wordlist = constant.passwordFound + get_dico()
        num_lines = (len(wordlist) - 1)
        self.info(u'%d most used passwords !!! ' % num_lines)

        for word in wordlist:
            global_salt, master_password, entry_salt = self.is_master_password_correct(
                key_data=key_data,
                master_password=word.strip(),
                new_version=new_version)
            if master_password:
                self.debug(
                    u'Master password found: {}'.format(master_password))
                return global_salt, master_password, entry_salt

        self.warning(u'No password has been found using the default list')
        return '', '', ''
Example #11
0
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')
Example #12
0
                            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!?'
Example #13
0
 def dictionary_attack(self, login, md5):
     for word in get_dico():
         hash_ = hashlib.md5('%s\nskyper\n%s' % (login, word)).hexdigest()
         if hash_ == md5:
             return word
     return False
Example #14
0
class Mozilla(ModuleInfo):
    # b = brute force attack
    # d = default list
    # a = dictionary attack

    def __init__(self, isThunderbird=False):

        # Default attack
        self.toCheck = ['b', 'd'] if not constant.path else ['a']
        self.dictionary_path = constant.path
        self.number_toStop = 3 if not constant.bruteforce else int(
            constant.bruteforce) + 1
        self.key3 = ''
        name = 'thunderbird' if isThunderbird else 'firefox'

        ModuleInfo.__init__(self, name=name, category='browsers')

    # --------------------------------------------

    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: {key}'.format(key=repr(key)))
        return key

    # ------------------------------ 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):

        # 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: {file_path}'.format(
                        file_path=str(self.dictionary_path)))
                return False
            pass_file.close()

            print_debug(
                'ATTACK', 'Dictionary Attack !!! ({nb_lines} words)'.format(
                    nb_lines=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', '{exception}'.format(exception=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: {master_password}'.format(
                            master_password=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 !!! ({nb_characters} characters)'.format(
                    nb_characters=str(constant.bruteforce)))
            print_debug('DEBUG',
                        'charset: {charset}'.format(charset=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', '{word}'.format(word=word))
                        if self.is_masterpassword_correct(''.join(word))[0]:
                            print_debug(
                                'FIND',
                                'Master password found: {master_password}'.
                                format(master_password=word.strip()))
                            return word.strip()
            except (KeyboardInterrupt, SystemExit):
                print 'INTERRUPTED!'
                print_debug('INFO', 'Dictionary attack interrupted')

            print_debug(
                'WARNING',
                'No password has been found using the brute force attack')
        return False
Example #15
0
					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)