Last active
April 6, 2022 13:54
-
-
Save timmc/f11dbe7c6cfc618062aa93207fb0daa4 to your computer and use it in GitHub Desktop.
Avvo reverse attempts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Attempt to reverse-engineer Avvo.com's hash algorithm, | |
given a leaked record and a known password. | |
Sample for validation of hash checker: | |
$ cat ~/tmp/ram/sample-record.txt | |
some@email,1199546,3e6139dd5bba6c8617c112abdb026a648e9bf592,45aa026ed8621c824dfa0acbb478d3eef87020bd,NULL | |
$ cat ~/tmp/ram/sample-password.txt | |
hello | |
$ python3 ~/adhoc/avvo.py ~/tmp/ram/sample-record.txt ~/tmp/ram/sample-password.txt | |
FOUND! Matched second hash: input=b'3e6139dd5bba6c8617c112abdb026a648e9bf592;some@email_1199546=hello' | |
""" | |
import base64 | |
import hashlib | |
import itertools | |
import sys | |
def intercalate(xs, ys): | |
""" | |
Interleave xs and ys, where ys is one element shorter than xs. | |
""" | |
return [el for pair in zip(xs, list(ys) + [None]) for el in pair][:-1] | |
def main(record_path, password_path): | |
with open(record_path, 'rb') as f: | |
record = f.read() | |
(email, seqid, hex1, hex2, _) = record.split(b',') | |
bytes1 = bytes.fromhex(hex1.decode()) | |
bytes2 = bytes.fromhex(hex2.decode()) | |
with open(password_path, 'rb') as f: | |
password = f.read().split(b'\n')[0] | |
symbols = [c.encode() for c in "`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>? "] | |
delimiters = symbols + [b''] | |
def check(pieces): | |
input = b''.join(pieces) | |
h = hashlib.sha1() | |
h.update(input) | |
if h.digest() == bytes1: | |
print(f"FOUND! Matched first hash: {input=!r}") | |
exit(0) | |
if h.digest() == bytes2: | |
print(f"FOUND! Matched second hash: {input=!r}") | |
exit(0) | |
def check_parts(parts): | |
""" | |
Given 1+ pieces of data, try all permutations and in combination with | |
various delimiters. | |
""" | |
for perm in itertools.permutations(parts): | |
for delims in itertools.product(delimiters, repeat=len(parts)-1): | |
check(intercalate(perm, delims)) | |
def check_all(password_variant): | |
combos = [ | |
[password_variant], | |
[password_variant, email], | |
[password_variant, seqid], | |
[password_variant, email, seqid], | |
] | |
for combo in combos: | |
check_parts(combo) | |
for salt in [hex1, hex2, bytes1, bytes2]: | |
check_parts(combo + [salt]) | |
check_all(password) | |
check_all(password.hex().encode()) | |
check_all(base64.b64encode(password)) | |
if __name__ == '__main__': | |
if len(sys.argv) != 3: | |
print("Usage: avvo.py <record_file> <password_file>") | |
exit(0) | |
main(sys.argv[1], sys.argv[2]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment