Skip to content

Instantly share code, notes, and snippets.

@teknogeek
Last active July 23, 2021 14:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save teknogeek/6e13b69ea69b3e33fef39c0bacce5e41 to your computer and use it in GitHub Desktop.
Save teknogeek/6e13b69ea69b3e33fef39c0bacce5e41 to your computer and use it in GitHub Desktop.
HackerOne Hoodie CTF

The Data

The data given was a block of hexadecimal numbers, shown belown:

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

Using Python, I decoded this data:

import binascii

data = '''
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
'''.replace('\n', '').replace(' ', '')

with open('data_raw', 'wb') as f:
    f.write(binascii.unhexlify(data))

Now I had a file, data_raw that had the raw data given inside of it:

# teknogeek at teknogeek-mbp in ~/Documents/CTF/Other/HackerOneHoodie [14:35:18]
→ cat data_raw
    1 {
    2  �"ev�nt"� "p�ssw�rd_�han�e",�  "�ser�ame�: "�col�in"�
    3   �old�pas�wor�": �:\x�7\x�4\n�xAF�)7C�x15�xD0�xF3�xDE�U;"�
    4   �new�pas�wor�": �9\x�A\x�9\x�A\x�D\x�2XS�\xD�-\x�2\x�EzH�",
    5 � "t�mes�amp�: 1�018�886�000�}

There seems to be something very wrong with this, but consistently -- every 4th character is a broken one. So I looked at the hex data for it using xxd:

# teknogeek at teknogeek-mbp in ~/Documents/CTF/Other/HackerOneHoodie [14:35:22]
→ xxd data_raw
00000000: 7b0a 20a0 2265 76e5 6e74 22ba 2022 70e1  {. ."ev.nt". "p.
00000010: 7373 77ef 7264 5fe3 6861 6ee7 6522 2c8a  ssw.rd_.han.e",.
00000020: 2020 22f5 7365 72ee 616d 65a2 3a20 22e2    ".ser.ame.: ".
00000030: 636f 6cec 696e 22ac 0a20 20a2 6f6c 64df  col.in"..  .old.
00000040: 7061 73f3 776f 72e4 223a 20a2 3a5c 78c3  pas.wor.": .:\x.
00000050: 375c 78c6 345c 6edc 7841 46a9 2937 43dc  7\x.4\n.xAF.)7C.
00000060: 7831 35dc 7844 30dc 7846 33dc 7844 45e9  x15.xD0.xF3.xDE.
00000070: 553b 22ac 0a20 20a2 6e65 77df 7061 73f3  U;"..  .new.pas.
00000080: 776f 72e4 223a 20a2 395c 78c6 415c 78b9  wor.": .9\x.A\x.
00000090: 395c 78c3 415c 78c5 445c 78c6 3258 53c7  9\x.A\x.D\x.2XS.
000000a0: 5c78 44c4 2d5c 78c3 325c 78b8 457a 48eb  \xD.-\x.2\x.EzH.
000000b0: 222c 0aa0 2022 74e9 6d65 73f4 616d 70a2  ",.. "t.mes.amp.
000000c0: 3a20 31b5 3031 38b5 3838 36b0 3030 308a  : 1.018.886.000.
000000d0: 7d0a                                     }.

Looking at this data, I could see that this was JSON and was able to make some conclusions based on the length of words, which character was missing, and the context of the situation.

String Hex
"ev.nt" 22 65 76 e5 6e 74 22
"p.ssw.rd_.han.e" 22 70 e1 73 73 77 ef 72 64 5f e3 68 61 6e e7 65 22

These should be "event" and "password_change". Comparing the wrong character codes with the correct ones, I could see that the e in event was a 0xe5 instead of a 0x65. The a, o, c, and g in password_change were 0xe1 instead of 0x61, 0xef instead of 0x6f, 0xe3 instead of 0x63, and 0xe7 instead of 0x67. All of these were a difference of 0x80 (128).

Combining the fact that every 4th character needed to be fixed, and the difference for all the broken characters was 0x80, I wrote a python script to fix the data, output it to a file, and print it:

data = open('data_raw', 'rb').read()

fixed_data = ''.join([chr(c - 0x80 if (idx + 1) % 4 == 0 else c) for idx, c in enumerate(data)])
print(fixed_data)

with open('fixed_data.json', 'w') as f:
    f.write(fixed_data)

Sorry about the list comprehension...let me make that easier to read.

data = open('data_raw', 'rb').read()

fixed_data = ''
# keep the current index handy to know if a 4th character
# (zero-indexed 3)
for idx, c in enumerate(data):
    # it is a 4th character
    if (idx + 1) % 4 == 0:
        c -= 0x80

    # convert the character code to a string and add it
    # to the end of the result
    fixed_data += chr(c)

print(fixed_data)

with open('fixed_data.json', 'w') as f:
    f.write(fixed_data)

Now I have this cleaned up data:

{
  "event": "password_change",
  "username": "bcollin",
  "old_password": ":\xC7\xF4\n\xAF))7C\x15\xD0\xF3\xDEiU;",
  "new_password": "9\xFA\x99\xCA\xED\xF2XSG\xDD-\xC2\x8EzHk",
  "timestamp": 1501858860000
}

This seems very accurate now because the sysadmin's name was Barry Collin and the username is bcollin. Also, the timestamp is 1501858860000 which is Friday August 04, 2017 08:01:00am (-0700 DST) and lines up with the scenario.

Now I needed to figure out what the passwords were.

The Passwords

The passwords were both an old and new password, and the scenario stated that the passwords were hashed. Additionally, the solution said to "reverse" the passwords...but hash functions can't be reversed. This took me MANY hours to figure out but I was able to understand it finally when I converted the strings to hexadecimal representation, and THEN reversed the strings.

  • :\xC7\xF4\n\xAF))7C\x15\xD0\xF3\xDEiU; -> 3ac7f40aaf2929374315d0f3de69553b
  • 9\xFA\x99\xCA\xED\xF2XSG\xDD-\xC2\x8EzHk -> 39fa99caedf2585347dd2dc28e7a486b

Then, REVERSING these hex strings, I got b35596ed3f0d5134739292faa04f7ca3 and b684a7e82cd2dd7435852fdeac99af93. These are double MD5 hashes of p4ssw0rd and thisiscrazy, the two passwords!

Shameless Plug

Wanna see more stuff like this? Follow me on Twitter and GitHub!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment