Post

HackTheBox Brevi Moduli Writeup

Explore the basics of cybersecurity in the Brevi Moduli Challenge on Hack The Box. This very-easy-level Challenge introduces encryption reversal and file handling concepts in a clear and accessible way, perfect for beginners.

https://app.hackthebox.com/challenges/799

Description

On a cold Halloween night, five adventurers gathered at the entrance of an ancient crypt. The Cryptkeeper appeared from the shadows, his voice a chilling whisper: “Five locks guard the treasure inside. Crack them, and the crypt is yours.” One by one, they unlocked the crypt’s secrets, but as the final door creaked open, the Cryptkeeper’s eerie laughter filled the air. “Beware, for not all who enter leave unchanged.”

Source

server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from Crypto.Util.number import isPrime, getPrime, bytes_to_long
from Crypto.PublicKey import RSA

rounds = 5
e = 65537

for i in range(rounds):
    print('*'*10, f'Round {i+1}/{rounds}', '*'*10)

    pumpkin1 = getPrime(110)
    pumpkin2 = getPrime(110)
    n = pumpkin1 * pumpkin2
    large_pumpkin = RSA.construct((n, e)).exportKey()
    print(f'\n🎃Can you crack this pumpkin🎃?\n{large_pumpkin.decode()}\n')

    assert isPrime(_pmp1 := int(input('enter your first pumpkin = '))), exit()
    assert isPrime(_pmp2 := int(input('enter your second pumpkin = '))), exit()

    if n != _pmp1 * _pmp2:
        print('wrong! bye...')
        exit()

    print()

print(open('flag.txt').read())

Exploitation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from pwn import *
from Crypto.PublicKey import RSA
import re
import subprocess

def get_process():
    try:
        host, port = sys.argv[1].split(':')
        return remote(host, int(port))
    except IndexError:
        print(f'Usage: python {sys.argv[0]} <ip:port>')
        exit(1)

def get_sage_factors(n):
    with open('factor.sage', 'w') as f:
        f.write(f"n = {n}\nF = factor(n)\nprint(F[0][0])\nprint(F[1][0])")
    subprocess.run(['sage', '--preparse', 'factor.sage'])
    result = subprocess.run(['sage', 'factor.sage.py'], capture_output=True, text=True)
    lines = result.stdout.strip().split('\n')
    return int(lines[0]), int(lines[1])

def solve_challenge():
    try:
        conn = get_process()
        for round_num in range(5):
            print(f"\nStarting Round {round_num + 1}/5")
            conn.recvuntil(b'Round')
            line = conn.recvline().decode()
            print(f"Current round: {line.strip()}")
            data = conn.recvuntil(b'enter your first pumpkin = ').decode()
            match = re.search('-----BEGIN PUBLIC KEY-----(.*?)-----END PUBLIC KEY-----', data, re.DOTALL)
            if not match:
                raise ValueError("Could not find PUBLIC KEY in response")
            pem = match.group(0)
            key = RSA.importKey(pem.encode())
            n = key.n
            print(f'n = {n}')
            p, q = get_sage_factors(n)
            print(f'Factors found: p = {p}, q = {q}')
            print(f'Verifying: {p} * {q} == {n}')
            if p * q != n:
                raise ValueError("Factorization verification failed!")
            conn.sendline(str(p).encode())
            print("Sent first factor")
            conn.recvuntil(b'enter your second pumpkin = ')
            conn.sendline(str(q).encode())
            print("Sent second factor")
            response = conn.recvline()
            print(response.decode().strip())
        remaining = conn.recvall(timeout=1)
        if remaining:
            print(remaining.decode().strip())  
    except Exception as e:
        print(f'Error occurred: {str(e)}')
    finally:
        conn.close()

if __name__ == '__main__':
    solve_challenge()

Summary

Brevi Moduli on Hack The Box involves cracking RSA keys by factoring small modulus values across multiple rounds. Each round gives a 220-bit modulus $n = p \times q$, requiring the client to factorize $n$ and submit $p$ and $q$ to verify correctness. The poc uses SageMath for rapid factorization. After completing all rounds, the server reveals the flag.

This post is licensed under CC BY 4.0 by the author.