## Saturday, January 18, 2014

### Hack You CTF 2014 - Crypto 200 - Hashme - [Team SegFault]

We have access to the source code of a remote service which allows users to register and login.

Register:
[*] Computed hash is appended to login={username}&role=anonymous, encrypted with a key using xor and then encoded using base64
[*] The generated base64 string is our certificate for login

[*] The user provided certificate is base64 decoded and decrypted using xor
[*] Hash of SALT+login={username}&role=anonymous is computed and checked with the user supplied hash. If it matches, then login is provided

We have to find a way to get administrator access by forging the request. Ok, first we have to find the key used in the remote machine. This can be done by registering a user with long username
```client sends: username as "A"*1000 # login={username}&role=anonymous is our known plain text
```
Using the plain text - cipher text combination, the KEY can be found.
Now we have to find a way to compute valid hash without knowing the SALT. Thanks to my friend who pointed me out the Hash Length Extension attack. The final 32 byte of hash comes from A,B,C and D of used hash algorithm
```A = 0x67452301
B = 0xEFCDAB89
D = 0x10325476
X = [int(0xFFFFFFFF * sin(i)) & 0xFFFFFFFF for i in xrange(256)]

for i,ch in enumerate(s):
k, l = ord(ch), i & 0x1f
A = (B + ROL(A + F(B,C,D) + X[k], l)) & 0xFFFFFFFF
B = (C + ROL(B + G(C,D,A) + X[k], l)) & 0xFFFFFFFF
C = (D + ROL(C + H(D,A,B) + X[k], l)) & 0xFFFFFFFF
D = (A + ROL(D + I(A,B,C) + X[k], l)) & 0xFFFFFFFF

return ''.join(map(lambda x : hex(x)[2:].strip('L').rjust(8, '0'), [B, A, D, C]))
```
We can use the HASH(login={username}&role=anonymous) sent by remote service as initial values, then compute the hash values of newly appended string without knowing the SALT. But one value we need to know is the length of SALT. This can be easily bruteforced.
```if hashme(SALT + auth_str) == hashsum:
data = parse_qs(auth_str, strict_parsing = True)
print '[+] Welcome, %s!' % data['login'][0]
print flag
```
```#!/usr/bin/env python

import base64
from math import sin

def hashme(length, s, state):
# my secure hash function
def F(X,Y,Z):
return ((~X & Z) | (~X & Z)) & 0xFFFFFFFF
def G(X,Y,Z):
return ((X & Z) | (~Z & Y)) & 0xFFFFFFFF
def H(X,Y,Z):
return (X ^ Y ^ Y) & 0xFFFFFFFF
def I(X,Y,Z):
return (Y ^ (~Z | X)) & 0xFFFFFFFF
def ROL(X,Y):
return (X << Y | X >> (32 - Y)) & 0xFFFFFFFF

#A = 0x67452301
#B = 0xEFCDAB89
#D = 0x10325476
B = int(hash[:8],16)
A = int(hash[8:16],16)
D = int(hash[16:24],16)
C = int(hash[24:],16)

X = [int(0xFFFFFFFF * sin(i)) & 0xFFFFFFFF for i in xrange(256)]

for i,ch in enumerate(s):
k, l = ord(ch), (i+length) & 0x1f
A = (B + ROL(A + F(B,C,D) + X[k], l)) & 0xFFFFFFFF
B = (C + ROL(B + G(C,D,A) + X[k], l)) & 0xFFFFFFFF
C = (D + ROL(C + H(D,A,B) + X[k], l)) & 0xFFFFFFFF
D = (A + ROL(D + I(A,B,C) + X[k], l)) & 0xFFFFFFFF

return ''.join(map(lambda x : hex(x)[2:].strip('L').rjust(8, '0'), [B, A, D, C]))

encoded_user_data = "RK5yZMJaRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJkUZfC1QZOZsfcZlXz4V1qj5TTm1j2pJnepqTLNKoeqfSlYQa9IahiQhPbSkaYBUTO0mRRl8LVBk5mx9xmVfPhXWqPlNObWPakmd6mpMs0qh6p9KVhBr0hqGJCE9tKRpgFRM7SZFGXwtUGTmbH3GZV8+Fdao+U05tY9qSZ3qakyzSqHqn0pWEGvSGoYkIT20pGmAVEztJiIqUgB0GMZDU+ldcxAh5N2LaUrM/hIw788YPMU42cruOSc3SaRv/lVRTMODTfQl"

decoded_user_data = base64.b64decode(encoded_user_data)

key = []
for i in range(len(user_data)):
key.append(ord(decoded_user_data[i]) ^ ord(user_data[i]))
key = key[:50]  # sizeof key is 50 bytes

# key
# [40, 193, 21, 13, 172, 103, 4, 88, 61, 108, 17, 37, 167, 45, 60, 135, 36, 30, 127, 84, 151, 233, 184, 12, 120, 244, 206, 43, 8, 220, 171, 43, 13, # 242, 11, 224, 171, 222, 11, 23, 81, 42, 147, 91, 199, 101, 96, 124, 245, 229]

encoded_user_data = "RK5yZMJaRX5PA31AmkxS6EpnEjvimo81G82rT2q5n0k9ym/Tme47IDcT92z2UVJOxNEe+CE5"
decoded_user_data = base64.b64decode(encoded_user_data)

decrypted_data = ''

for i in range(len(decoded_user_data)):
decrypted_data += chr(ord(decoded_user_data[i]) ^ key[i % len(key)])

hash = decrypted_data[-32:]

length_of_salt = 0
length_of_user_data = len(user_data)

for length_of_salt in range(1,30):
forged_hash = hashme(length_of_salt + length_of_user_data, target, hash)
string_to_enc = user_data + target + forged_hash

for i in range(len(string_to_enc)):
enc_payload += chr(ord(string_to_enc[i]) ^ key[i % len(key)])

print "%d : %s" % (length_of_salt, base64.b64encode(enc_payload))
```
We get successful login and flag, when length of SALT is 20 bytes.
```RK5yZMJaRX5PA31AmkxS6EpnEjvimp5+F5irFmm4xkJjm3iU2b9/eCNM8TimAFcdwYca8CU8nQI8OVxbdRefTgzjFi0bMaPejw==
[+] Welcome, A!
CTF{40712b12d4be002e20f51424309a068c}
```