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.