The First Half: Reloaded
Cryptography · MUST CTF: 2024 · Superior
Problem
This code represents a challenge where the goal is to deduce a secret "flag" value using a partially leaking encryption process.
The Encryption Process:
Flag Setup:
A flag is fetched from the environment variable
flag
, defaulting to a placeholder value if not set.The flag is stored as a byte-encoded string.
Leak Function:
The function
leak(i)
takes an indexi
and returns the XOR of thei
-th byte of the flag with a randomly chosen byte from the stringMUSTCTF
.
User Interaction:
The program accepts user input
i
to specify the index of the flag byte to leak.Leaks are restricted to the first half of the flag (
len(flag) // 2
).
Termination:
An unexpected input or exception breaks the loop, terminating the process.
Remote Access:
Players interact with the challenge through a remote service using the command:
nc 139.162.5.230 10169
import os
flag = os.environ.get('flag', 'MUSTCTF{fake_flag_for_testing}').encode()
def leak(i):
from random import choice
return flag[i] ^ choice(b'MUSTCTF')
while True:
try:
i = int(input('i = '))
assert i < len(flag) // 2 # Sorry. Only first half is leaked
print('Leak:', leak(i))
except Exception:
print('Unexpected error')
break
Solution
This Python script uses the Pwntools library to communicate with the remote server and deduce the flag:
Setup:
Establishes a remote connection to the provided address.
Initializes an empty
flag
array to store deduced bytes.Defines
allowed_chars
as the byte stringb"MUSTCTF"
.
Deduction Logic:
A helper function
deduce_flag_byte
iterates over possible byte values (0–255) and determines which matches the leaked XORed values.A byte is deemed correct if XORing it with each leaked value produces a valid character from
allowed_chars
.
Leaking Flag Bytes:
For each index in the last half of the flag (
-32
to0
):Sends the index to the remote service multiple times to gather leak values.
Uses
deduce_flag_byte
to find the actual flag byte.Maps the deduced byte to the correct position in the
flag
array.
Error Handling:
Handles EOF errors gracefully, ensuring the connection is closed cleanly.
Output:
Prints the partially or fully reconstructed flag, replacing undeduced bytes with a
?
.
from pwn import *
io = remote("139.162.5.230", 10169)
flag = [None] * 40
allowed_chars = b"MUSTCTF"
def deduce_flag_byte(leaks):
for char in range(256):
if all((char ^ leak) in allowed_chars for leak in leaks):
return char
return None
try:
for i in range(-32, 0):
leaks = []
for _ in range(100):
io.sendlineafter(b"i = ", str(i).encode())
io.recvuntil(b"Leak: ")
leak_value = int(io.recvline().strip())
leaks.append(leak_value)
flag_byte = deduce_flag_byte(leaks)
positive_index = 32 + i
if flag_byte is not None:
flag[positive_index] = flag_byte
print(f"Flag[{positive_index}] = {chr(flag[positive_index])}")
else:
print(f"Could not deduce Flag[{positive_index}]")
except EOFError:
print("Connection closed by the server.")
finally:
io.close()
print("Flag:", "".join(chr(c) if c else '?' for c in flag))
Last updated