Post

HackTheBox One Step Closer Writeup

Explore the basics of cybersecurity in the One Step Closer Challenge on Hack The Box. This medium-level Challenge introduces encryption reversal and file handling concepts in a clear and accessible way, perfect for beginners.

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

Description

Reading out loud Danbeer’s thoughts from the cloud server shocked everyone. Knowing that your father has become a consciousness that can be easily turned off and on is traumatizing. You are overwhelmed by your feelings and angry at yourself. You begin to ask yourself. Why am I feeling so much pain? Is there a part of my brain that is still encrypted? Have I screwed up again? You run towards the lab while shouting and slamming the doors behind you. Upon seeing that, Ulysses immediately flees the spaceship. Many days have passed and you are still obsessed with finding the part of your brain that needs to be repaired. Your comrades are startled by your sudden introversion and worry about Ulysses, who is nowhere to be seen. Weeks have passed and Ulysses is still missing. Suddenly, the ship receives a docking signal and as you scan the alien spacecraft for signs of life, a male passenger is discovered. It’s Ulysses! Excited, he rushes out of his capsule and overtakes the crew members, that longed to hug him to get to your lab. Ulysses informs you that he has managed to steal one of the cloud backup servers from the facility where the experiments took place. It seems that this device alters the consciousness of each test subject. Stunned by this information, a realization comes to mind. You are going to get your father back.

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python3
from Crypto.Util.number import long_to_bytes
import requests, sys

def get_process():
    if len(sys.argv) > 1:
        ip, port = sys.argv[1].split(':')
        return f"{ip}:{port}"
    print(f"Usage: {sys.argv[0]} <ip:port>")
    sys.exit(1)

class Polynomial:
    def __init__(self, coeffs, modulus):
        self.coeffs = [x % modulus for x in coeffs]
        self.modulus = modulus
        self.trim()
    
    def trim(self):
        while len(self.coeffs) > 1 and self.coeffs[-1] == 0:
            self.coeffs.pop()
    
    def __add__(self, other):
        result = [0] * max(len(self.coeffs), len(other.coeffs))
        for i in range(len(result)):
            a = self.coeffs[i] if i < len(self.coeffs) else 0
            b = other.coeffs[i] if i < len(other.coeffs) else 0
            result[i] = (a + b) % self.modulus
        return Polynomial(result, self.modulus)
    
    def __sub__(self, other):
        result = [0] * max(len(self.coeffs), len(other.coeffs))
        for i in range(len(result)):
            a = self.coeffs[i] if i < len(self.coeffs) else 0
            b = other.coeffs[i] if i < len(other.coeffs) else 0
            result[i] = (a - b) % self.modulus
        return Polynomial(result, self.modulus)
    
    def __mul__(self, other):
        result = [0] * (len(self.coeffs) + len(other.coeffs) - 1)
        for i in range(len(self.coeffs)):
            for j in range(len(other.coeffs)):
                result[i+j] = (result[i+j] + self.coeffs[i] * other.coeffs[j]) % self.modulus
        return Polynomial(result, self.modulus)
    
    def __divmod__(self, other):
        if len(other.coeffs) > len(self.coeffs):
            return Polynomial([0], self.modulus), self
        inv_lead = pow(other.coeffs[-1], -1, self.modulus)
        quotient = [0] * (len(self.coeffs) - len(other.coeffs) + 1)
        remainder = self.coeffs.copy()
        for i in range(len(self.coeffs) - len(other.coeffs), -1, -1):
            if len(remainder) <= i + len(other.coeffs) - 1:
                continue
            coeff = (remainder[i + len(other.coeffs) - 1] * inv_lead) % self.modulus
            quotient[i] = coeff
            for j in range(len(other.coeffs)):
                idx = i + j
                if idx < len(remainder):
                    remainder[idx] = (remainder[idx] - coeff * other.coeffs[j]) % self.modulus
        return (Polynomial(quotient, self.modulus), 
                Polynomial(remainder[:len(other.coeffs)-1], self.modulus))

def poly_gcd(a, b):
    while len(b.coeffs) > 1 or b.coeffs[0] != 0:
        _, r = divmod(a, b)
        a, b = b, r
    return a

def get_encrypted_data(url):
    r = requests.get(f'http://{url}/api/get_flag')
    return r.json()

def create_polynomial(a, b, c, e, n):
    result = Polynomial([b % n, a % n], n)
    temp = result
    for i in range(e-1):
        temp = temp * result
    temp.coeffs[0] = (temp.coeffs[0] - c) % n
    return temp

def main():
    url = get_process()
    print("[+] Getting first encryption...")
    data1 = get_encrypted_data(url)
    print("[+] Getting second encryption...")
    data2 = get_encrypted_data(url)
    n = int(data1['n'], 16)
    e = int(data1['e'], 16)
    a1 = int(data1['a'], 16)
    b1 = int(data1['b'], 16)
    c1 = int(data1['ct'], 16)
    a2 = int(data2['a'], 16)
    b2 = int(data2['b'], 16)
    c2 = int(data2['ct'], 16)
    print("[+] Running Franklin-Reiter attack...")
    f1 = create_polynomial(a1, b1, c1, e, n)
    f2 = create_polynomial(a2, b2, c2, e, n)
    gcd = poly_gcd(f1, f2)
    if len(gcd.coeffs) > 1:
        a, b = gcd.coeffs[1], gcd.coeffs[0]
        flag_value = (-b * pow(a, -1, n)) % n
        flag = long_to_bytes(flag_value)
        print(f"[+] Found flag: {flag.decode()}")
    else:
        print("[-] Attack failed")

if __name__ == '__main__':
    main()

Summary

The One Step Closer Challenge on Hack The Box is a medium-level task focusing on cryptographic exploitation and RSA encryption. By implementing the Franklin-Reiter related message attack, participants use polynomial arithmetic to recover the flag from two related RSA encryptions obtained from an API endpoint. The Python script automates the attack by creating polynomials from the encrypted data, finding their GCD, and extracting the original message. This challenge demonstrates advanced cryptographic concepts and mathematical techniques in breaking RSA under specific conditions, making it an excellent exercise for those interested in cryptographic attacks and polynomial mathematics.

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