Post

Baby Time Capsule - HackTheBox CTF

In this HTB challenge, we are given the source code of a encrypting algorithm that is using RSA. We are also given a remote instance serving this script, so that we can retrieve the flag. The vulnerability of this program comes when it encrypts the same text (the flag) using different primes in the RSA algorithm. We’ll be able to use the Chinese Remainder Theorem in order to get the plaintext. Let’s get into it.

Source code

This is the intereseting part of the source code:

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
def __init__(self, msg):
    self.msg = msg
    self.bit_size = 1024
    self.e = 5

def _get_new_pubkey(self):
    while True:
        p = getPrime(self.bit_size // 2)
        q = getPrime(self.bit_size // 2)
        n = p * q
        phi = (p - 1) * (q - 1)
        try:
            pow(self.e, -1, phi)
            break
        except ValueError:
            pass

    return n, self.e

def get_new_time_capsule(self):
    n, e = self._get_new_pubkey()
    m = bytes_to_long(self.msg)
    m = pow(m, e, n)

    return {"time_capsule": f"{m:X}", "pubkey": [f"{n:X}", f"{e:X}"]}

Besides, when we connect to the instance, we are asked to type ‘Y’ or ‘N’, asking whether we want to generate a cipher text or not. If we say ‘Y’, then this code will be executed and will print the result:

example execution

Chinese Remainder Theorem

Let’s say we run the program three times, and we get three cyphertexts: \(ct_1, ct_2, ct_3\) and three “n’s”: \(n_1, n_2, n_3\). Taking into account that \(e=5\), we have the following set of congruences:

\[m^5 \equiv ct_1 ~ (mod \quad n_1)\] \[m^5 \equiv ct_2 ~ (mod \quad n_2)\] \[m^5 \equiv ct_3 ~ (mod \quad n_3)\]

So we can apply the Chinese Remainder Theorem in order to get the value of \(m^5\). We’ll take the 5-th root, and that will be the plaintext!

Solution

This is a little python script I wrote to connect to the instance, get the required values and solve the set of congruences:

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
#!/usr/bin/python3

from pwn import *
from Crypto.Util.number import long_to_bytes
import json
from sympy.ntheory.modular import crt
from sympy.simplify.simplify import nthroot


ip = "206.189.24.162"
port = 32270

r = remote(ip, port)
ct = []
n = []
for i in range(3):
    r.sendlineafter(b"(Y/n) ", b"Y")
    data = r.recvuntil(b"}")
    json_data = json.loads(data)
    ct.append(int(json_data["time_capsule"], 16))
    n.append(int(json_data["pubkey"][0], 16))


solution = crt(n, ct)[0]
m = nthroot(solution, 5)

print(long_to_bytes(m))

And when we execute this script, we’ll get the flag :)

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