Compy's Blog
473 words
2 minutes
[DreamHack] stroooooooong-hash

일단 문제 코드는 딱 하나만 집중해서 보면 된다.

from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad
import os
import hashlib
import itertools
import string


def stronghash(msg: bytes) -> bytes:
    hashed_msg = pad(msg, 16)
    for _ in "Stronger!!":
        hashed_msg = AES.new(hashed_msg[:16], AES.MODE_ECB).encrypt(hashed_msg)

    for length in range(2, 16):
        md5 = hashlib.md5(hashed_msg[:length])
        hashed_msg = md5.digest()

    for length in range(16, 32):
        sha256 = hashlib.sha256(hashed_msg[:length])
        hashed_msg = sha256.digest()

    return hashed_msg

요 stronghash 이 친군데.. 사실 아래 하나만 더 보자

def main():
    print("I invented my custom hash function, which is very very strong")
    print("Can you steal my flag from it?")

    stage = 100
    pw = [os.urandom(16) for _ in range(stage)]
    for i in range(stage):
        print(f"Stage {i + 1}")
        print(f"My hashed password : {stronghash(pw[i]).hex()}")
        msg = bytes.fromhex(input("Guess my password(hex) > "))
        if stronghash(msg) != stronghash(pw[i]):
            exit("Get out stranger! ୧(๑•̀ᗝ•́)૭")
    
    print('Here is your flag, master.')
    give_flag()

이거 보면 pw가 os.urandom(16) 으로 작성된 것을 알 수 있다. 근데 이게 사실 2^16이 별로 안 크다…짜잔

일단 왜 이문제가 또 bruteforce로 풀어야되는지 알려주겠다.

일단 현재 sha256은 one way hash func으로 다시 역산하는 것이 사실상 많이 어렵다. 그래서 처음에 이걸 알고서 아 그러면 하나 하나 비교해야되겠다!! 이랬는데 순간 머리에서 2^16이 아니라 10^16을 생각하면서 어? 이거 어트케 푸냐 이러고 있었다. 담부턴 이런 상황은 없을 듯 머리에 크게 남았음.

하튼 bruteforce로 간단히 짜면 아래와 같이 나온다


from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad
from Cryptodome.Util.number import long_to_bytes
import os
import hashlib
import itertools
import string

from pwn import *


def stronghash(msg: bytes) -> bytes:
    hashed_msg = pad(msg, 16)
    for _ in "Stronger!!":
        hashed_msg = AES.new(hashed_msg[:16], AES.MODE_ECB).encrypt(hashed_msg)

    for length in range(2, 16):
        md5 = hashlib.md5(hashed_msg[:length])
        hashed_msg = md5.digest()

    for length in range(16, 32):
        sha256 = hashlib.sha256(hashed_msg[:length])
        hashed_msg = sha256.digest()

    return hashed_msg


hash_values = {}

for i in range((2 << 16)):
    value = long_to_bytes(i)
    hash_value = stronghash(value)
    hash_values[hash_value] = value
p = remote("host3.dreamhack.games", 16226)

start = 2<<16
for i in range(100):
    hash_value = p.recvline_contains(b": ").replace(b"My hashed password : ", b"")
    print(hash_value)

    # print(bytes.fromhex(hash_value))
    # print(hash_value
    key = bytes.fromhex(hash_value.decode())

    if key in hash_values:
        p.sendline(hash_values[bytes.fromhex(hash_value.decode())].hex())
        print(hash_values[bytes.fromhex(hash_value.decode())].hex())
    else:
        for i in range(start, (2 << 128)):
            if stronghash(long_to_bytes(i)) == key:
                p.sendline(long_to_bytes(i).hex())
                print(str(hex(i))[2:])
                break
p.interactive()
[DreamHack] stroooooooong-hash
https://compy07.github.io/Blog/posts/security/crypto/dreamhack/level_1/stroooooooong_hash/
Author
뒹굴뒹굴 이정훈 공부방
Published at
2024-09-18