# Capture the flag: reversing the passwords (Solutions)

## Step 1 - Recovering the corrupted data

According to the doc, the following stream is corrupted:

7b 0a 20 a0 22 65 76 e5
6e 74 22 ba 20 22 70 e1
73 73 77 ef 72 64 5f e3
68 61 6e e7 65 22 2c 8a
20 20 22 f5 73 65 72 ee
61 6d 65 a2 3a 20 22 e2
63 6f 6c ec 69 6e 22 ac
0a 20 20 a2 6f 6c 64 df
70 61 73 f3 77 6f 72 e4
22 3a 20 a2 3a 5c 78 c3
37 5c 78 c6 34 5c 6e dc
78 41 46 a9 29 37 43 dc
78 31 35 dc 78 44 30 dc
78 46 33 dc 78 44 45 e9
55 3b 22 ac 0a 20 20 a2
6e 65 77 df 70 61 73 f3
77 6f 72 e4 22 3a 20 a2
39 5c 78 c6 41 5c 78 b9
39 5c 78 c3 41 5c 78 c5
44 5c 78 c6 32 58 53 c7
5c 78 44 c4 2d 5c 78 c3
32 5c 78 b8 45 7a 48 eb
22 2c 0a a0 20 22 74 e9
6d 65 73 f4 61 6d 70 a2
3a 20 31 b5 30 31 38 b5
38 38 36 b0 30 30 30 8a
7d 0a


Running xxd -r -p we can see that individual characters are readable and some are not.

The readable ones help us figure out what we need to change and bit-by-bit, while playing around we start noticing a clear pattern.

▶ hex(0xE5 ^ 0x80)
'0x65'


Admittedly, figuring out the pattern took a bit of trial and error, but eventually I constructed the following:

{
"timestamp": 1501858860000
}


What I found out later (I will explain this in more detail later) is that the username and the timestamp were only really there to verify the data after I had fixed it.

## Step 2 - Gibberish to hash

The old_password hash was already escaped, so I could make it readable as follows:

▶ ':\xC7\xF4\n\xAF))7C\x15\xD0\xF3\xDEiU;'.encode('hex')
'3ac7f40aaf2929374315d0f3de69553b'


The second one required a bit more work, but eventually I got there:

▶ '\x39\xFA\x99\xCA\xED\xF2\x58\x53\x47\xDD\x2D\xC2\x8E\x7A\x48\x6B'.encode('hex')
'39fa99caedf2585347dd2dc28e7a486b'


The doc states that a hashing algorithm was used to make recovery harder. By measuring the length of the hashes we can assume that MD5 was used to store the passwords, which we will later see is an insecure method to store passwords.

▶ len(':\xC7\xF4\n\xAF))7C\x15\xD0\xF3\xDEiU;'.encode('hex'))
32


## Step 3 - “Reversing” the hashes

This is the part where I needed Jobert’s help. There were two vital moments that allowed me to figure out the solution. As you may know reversing a hash in a technological sense is impossible, since hashing algorithms are one-way functions. In order to get to the passwords you would need to crack the hashes first. I attempted this to no avail. Trust me, I tried everything. Aside from running cracking software, I hashed every single word in the doc and looked up keywords to find more keywords that could be linked to the password. This is where I started looking up Barry Collin and trying to figure out a possible hint. Yes, I assumed this CTF would be another Cicada 3301! Finally, after hours of hard work, one simple little mistake by Jobert made me focus on something else and slowly get to the solution: Jobert accidentally got Barry’s name wrong and called him Brian.

This is when I jumped back to the “reversing” aspect of things. This was the final moment when Jobert helped me with a final hint.

This was the lightbulb moment. I did not have to crack the hashes as is, I had to literally reverse the strings:

▶ old_password = '3ac7f40aaf2929374315d0f3de69553b'[::-1]
b35596ed3f0d5134739292faa04f7ca3
b684a7e82cd2dd7435852fdeac99af93


## Step 4 - Cracking the hashes

Now finally, the fun part!

The old_password hash was md5(md5).

$python pybozocrack.py -s b35596ed3f0d5134739292faa04f7ca3 b35596ed3f0d5134739292faa04f7ca3:2a9d119df47ff993b662a8ef36f9ea20$ python pybozocrack.py -s 2a9d119df47ff993b662a8ef36f9ea20
2a9d119df4ff993b662a8ef36f9ea20:p4ssw0rd


The new_password required the use of Crackstation:

b684a7e82cd2dd7435852fdeac99af93 - md5(md5) - thisiscrazy


## What did I learn?

The most secure method of password storage, which will keep hackers busy is simply reversing an MD5 hash. 😛