Hack The Box - Secure Signin

Challenge Description:

Can you crack our Ultra Secure Signing Oracle?

We are given the code from the server:

from hashlib import sha256
from secret import FLAG

WELCOME_MSG = """
Welcome to my Super Secure Signing service which uses unbreakable hash function.
We combine your Cipher with our secure key to make sure that it is more secure than it should be.
"""


def menu():
    print("1 - Sign Your Message")
    print("2 - Verify Your Message")
    print("3 - Exit")


def xor(a, b):
    return bytes([i ^ j for i, j in zip(a, b)]) ### [input]  ^ FLAG = res -> sha256(res) = hash -> [print(hash)]


def H(m):
    return sha256(m).digest()


def main():
    print(WELCOME_MSG)

    while True:
        try:
            menu()
            choice = int(input("> "))
        except:
            print("Try again.")
            continue

        if choice == 1:
            message = input("Enter your message: ").encode()
            hsh = H(xor(message, FLAG))
            print(f"Hash: {hsh.hex()}")
        elif choice == 2:
            message = input("Enter your message: ").encode()
            hsh = input("Enter your hash: ")
            if H(xor(message, FLAG)).hex() == hsh:
                print("[+] Signature Validated!\n")
            else:
                print(f"[!] Invalid Signature!\n")
        else:
            print("Good Bye")
            exit(0)


if __name__ == "__main__":
    main() 

After looking at the code for a bit, we can see that the server is XORing the input with the flag and then hashing it with SHA256. The vulnerability here lies in the way that the XOR function works. Because of the zip function, if we XOR the flag with a string that is smaller than the length of the flag, the XOR function will not repeat the input and just XOR the length of the input with the flag. This means that we can brute-force the flag byte by byte.

Solution:

from pwn import *
from hashlib import sha256

# context.log_level = 'debug'

def bf_sha(hsh, curr):
    for i in range(0, 256):
        # print(sha256(curr + chr(i).encode()).digest().hex())
        if sha256(curr + chr(i).encode()).digest().hex().encode() == hsh:
            return curr + chr(i).encode()

length = 1
flag = b""
curr = b""

while True:
    p = remote("94.237.53.113", 46090)
    p.recvuntil(b"> ")
    p.sendline(b"1")
    p.recvuntil(b": ")
    p.sendline(b"a" * length)
    length+=1
    p.recvuntil(b"Hash: ")
    hsh = p.recvline().strip()
    # print(hsh)
    curr=bf_sha(hsh, curr)
    flag+=xor(curr[-1], b"a")
    print(flag.decode())
    if flag[-1] == b"}":
        exit(0)