code hacking, zen coding

HackYouToo CTF – Crypto 300 – Everybody Lies

Mr. Menhall has invented his own encryption algorithm and promised to give the flag to anyone who manages to decipher the message:

vWsMajX21l6BdKwDxaRA3utqhpvFL0V=

def hashcrypt(msg, key):
    token = hashlib.sha1(key).digest()
    res = ""
    for c in msg:
        n = ord(c) ^ 0xfe ^ 0xc3 ^ 0x42 ^ 0x21
        n ^= 0xc2 ^ ord(token[0])
        n ^= 0xf3 ^ ord(token[1])
        n ^= 0x27 ^ ord(token[2])
        n ^= 0x4c ^ ord(token[3])
        n ^= 0x21 ^ ord(token[4])
        n ^= 0xfe ^ ord(token[5])
        n ^= 0xa3 ^ ord(token[6])
        n ^= 0xf0 ^ ord(token[7])
        n ^= 0x11 ^ ord(token[6])
        n ^= 0x54 ^ ord(token[5])
        n ^= 0xca ^ ord(token[4])
        n ^= 0x3c ^ ord(token[3])
        n ^= 0x20 ^ ord(token[2])
        n ^= 0xd1 ^ ord(token[1])
        n ^= 0xf2 ^ ord(token[0])
        res += chr(n)
        token = hashlib.sha1(chr(n)).digest()
    return res.encode('base64').encode('rot13')

We need to code the reverse function to decrypt the cypher text.

Looking more closely, we notice most of the tokens (token[0] -> token[6]) are nulling each other because the operator between them is XOR: A^B^B = A

Also the token will get overwritten at each step with the sha1 hash of the previous cypher byte: We can decrypt all the chars except the first one.

import hashlib

def hashdecrypt(msg, key):
    msg = msg.decode('rot13').decode('base64')
    token = hashlib.sha1(key).digest()
    res = ""

    for c in msg:
        n = ord(c) ^ 0xfe ^ 0xc3 ^ 0x42 ^ 0x21
        n ^= 0xc2
        n ^= 0xf3
        n ^= 0x27
        n ^= 0x4c
        n ^= 0x21
        n ^= 0xfe
        n ^= 0xa3
        n ^= 0xf0 ^ ord(token[7])
        n ^= 0x11
        n ^= 0x54
        n ^= 0xca
        n ^= 0x3c
        n ^= 0x20
        n ^= 0xd1
        n ^= 0xf2
        res += chr(n)
        token = hashlib.sha1(c).digest()
    return res

msg = "vWsMajX21l6BdKwDxaRA3utqhpvFL0V="
plaintext = hashdecrypt(msg, "unknown")

print "plaintext=", plaintext

Output:

plaintext= 9_lied_no_flag_for_you!

Guessing time… “i_lied_no_flag_for_you!” was the correct flag.

Share