Tags: hash-length-extension unicode

Rating:

There are two endpoints in this challenge: /new and /view. We have to become admin to get the flag back from the server.
with /new we can create a note. We have to provide an author and the note content. The server signs our parameters using the SHA1 algorithm, and later in /view checks that the signature we provided is the same. The server also adds admin=False, access_sensitive=False, entrynum=783 as default to our parameters before signing.

To get the flag, these parameters must be set as the following: admin=True&access_sensitive=False&entrynum=7
It looks like we can use a hash length extension attack to add some extra parameters at the end, and overwrite admin, access_sensitive and entrynum.

I used hashpumpy to solve this. I extended the id string with &admin=True&access_sensitive=True&entrynum=7 and set integrity to the new sha1 string generated by hashpumpy. One problem I had for a long time is that the server raised exceptions because we send in raw bytes that it cannot utf8 decode. Encoding the string using unicode-escape did the trick!

script:
python
import hashpumpy
import requests
from urllib.parse import quote
from base64 import b64encode, b64decode

url = 'http://crypto.chal.csaw.io:5003'

res = requests.post(url + '/new', data={"author": "zup", "note": "cool"})
print(res.text)

infostr = b64decode(res.text.split()[2].split(':')[0]).strip()
sha1 = res.text.split()[2].split(':')[1].strip()
print(sha1)
print(infostr)

# Bruteforce key length
for i in range(256):
newsign = hashpumpy.hashpump(sha1, infostr, "&admin=True&access_sensitive=True&entrynum=7", i)
print(newsign)

# We need to use unicode-escape because the server prints our extended string and will fail because of invalid utf8 characters
newid = newsign[1].decode('unicode-escape').encode('unicode-escape')
newsha = newsign[0]

print(newid)
print(newsha)

res = requests.post(url + '/view', data={'id': b64encode(newid), 'integrity': newsha})
print(res.text)

if 'Note' in res.text:
break