HackTheBox Secure Singning Writeup
Explore the basics of cybersecurity in the Secure Singning Challenge on Hack The Box. This easy-level Challenge introduces encryption reversal and file handling concepts in a clear and accessible way, perfect for beginners.
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
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
from hashlib import sha256
from secret import FLAG
WELCOME_MSG = """
Welcome to my Super Secure Signing service which uses unbreakable hash function.
We combine your Cipher with our secure key to make sure that it is more secure than it should be.
"""
def menu():
print("1 - Sign Your Message")
print("2 - Verify Your Message")
print("3 - Exit")
def xor(a, b):
return bytes([i ^ j for i, j in zip(a, b)])
def H(m):
return sha256(m).digest()
def main():
print(WELCOME_MSG)
while True:
try:
menu()
choice = int(input("> "))
except:
print("Try again.")
continue
if choice == 1:
message = input("Enter your message: ").encode()
hsh = H(xor(message, FLAG))
print(f"Hash: {hsh.hex()}")
elif choice == 2:
message = input("Enter your message: ").encode()
hsh = input("Enter your hash: ")
if H(xor(message, FLAG)).hex() == hsh:
print("[+] Signature Validated!\n")
else:
print(f"[!] Invalid Signature!\n")
else:
print("Good Bye")
exit(0)
if __name__ == "__main__":
main()
secret.py
1
FLAG = b"HTB{T3ST}"
Introduction to Extracting the FLAG Using XOR Properties
The goal of this process is to extract a secret FLAG
from a signing service that hashes messages combined with the FLAG
. By understanding how the XOR operation works, we can cleverly deduce the FLAG
without needing direct access to it.
Key Concepts
- Self-Canceling: \(A \oplus A = 0\)
- XORing a value with itself results in zero.
- Reversible: \(A \oplus B \oplus B = A\)
- You can recover the original value by XORing it with the same value again.
- Hashing Function: The signing function produces a hash of the format
H(xor(message, FLAG))
. This means the hash depends on both the input message and the secretFLAG
.
Attack Strategy
- Submit Two Distinct Messages:
- Choose two different messages (e.g.,
m1
andm2
) and submit them to the signing service to get their hashes:HASH1 = H(xor(m1, FLAG))
HASH2 = H(xor(m2, FLAG))
- Choose two different messages (e.g.,
- Extract FLAG Using XOR:
- XOR the two hashes: [ FLAG = HASH1 \(\oplus\) HASH2]
- This operation isolates the
FLAG
by canceling out the contributions from the messages.
Conclusion
By strategically submitting different messages and using the reversible nature of the XOR operation, we can effectively reveal the hidden FLAG
. This technique highlights the importance of secure hashing and signing mechanisms in cryptography.
Poc
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
#!/usr/bin/env python
from hashlib import sha256
from pwn import *
exe = 'server.py'
context.log_level = 'info'
charset = string.ascii_letters + string.digits + string.punctuation
def start(argv=[], *a, **kw):
if len(sys.argv) >= 3 and sys.argv[1] == '-r':
host = sys.argv[2]
port = int(sys.argv[3])
return remote(host, port, *a, **kw)
else:
return process(['python', exe] + argv, *a, **kw)
def xor(a, b):
return bytes([i ^ j for i, j in zip(a, b)])
def H(m):
return sha256(m).digest()
io = start()
p = log.progress('Flag ')
last_flag = last_hash = new_hash = zero_xor_hash = ""
while zero_xor_hash == new_hash:
flag_length = len(last_flag) + 1
zero_xor_flag = "." * flag_length
zero_xor_hash = H(xor(zero_xor_flag.encode(),zero_xor_flag.encode())).hex()
for c in charset:
new_flag = last_flag + c
io.recvuntil(b"> ")
io.send(b"1\n")
io.recvuntil(b": ")
io.send(new_flag.encode() + b"\n")
io.recvuntil(b": ")
new_hash = io.recvline().decode().rstrip()
if last_hash == new_hash:
p.success(f"{last_flag}")
exit()
if zero_xor_hash == new_hash:
p.status(f"{new_flag} {new_hash}")
last_flag = new_flag
last_hash = new_hash
break
io.close()
This post is licensed under CC BY 4.0 by the author.