Bits of Space
Here is a code to one of our relays, can you reach the others?
nc sunshinectf.games 25401
Attachment:
import socket
import struct
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from secrets import key
HOST = "0.0.0.0"
PORT = 25401
VALID_DEVICES = {
0x13371337: b"Status Relay\n",
0x1337babe: b"Ground Station Alpha\n",
0xdeadbeef: b"Lunar Relay\n",
0xdeadbabe: b"Restricted Relay\n"
}
CHANNEL_MESSAGES = {
1: b"Channel 1: Deep Space Telemetry Stream.\n",
2: b"Channel 2: Asteroid Mining Operations Log.\n",
3: b"Channel 3: Secret Alien Communication Feed!\n",
}
def read_flag():
with open("/flag", "rb") as fl: return fl.readline() + b'\n'
def decrypt_subscription(data: bytes, key: bytes):
iv = data[:AES.block_size]
body = data[AES.block_size:]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(body), AES.block_size)
device_id, start, end, channel = struct.unpack("<IQQI", plaintext)
return device_id, start, end, channel
def handle_client(conn):
try:
conn.sendall(b"== Space Relay ==\n")
conn.sendall(b"Send your subscription packet:\n")
data = conn.recv(1024).strip()
if not data:
conn.sendall(b"No data received.\n")
return
try:
device_id, start, end, channel = decrypt_subscription(data, key)
except Exception as e:
conn.sendall(b"Invalid subscription. Access denied.\n")
return
if device_id not in VALID_DEVICES:
conn.sendall(b"Unknown device ID. Authentication failed.\n")
return
# Secret Device
if device_id == 0xdeadbabe:
conn.sendall(b"You have reached the restricted relay... here you go.\n")
conn.sendall(read_flag())
return
if channel not in CHANNEL_MESSAGES:
conn.sendall(b"Unknown channel. No signal.\n")
return
device_name = VALID_DEVICES[device_id]
conn.sendall(b"Authenticated device: " + device_name)
conn.sendall(CHANNEL_MESSAGES[channel])
finally:
conn.sendall(b"See you next time space cowboy.\n")
conn.close()
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(5)
print(f"Satellite relay listening on {HOST}:{PORT}...")
while True:
conn, addr = s.accept()
handle_client(conn)
if __name__ == "__main__":
main()
We are provided a voyager.bin
, which corresponds to 0x13371337 device id:
$ cat voyager.bin | nc sunshinectf.games 25401
== Space Relay ==
Send your subscription packet:
Authenticated device: Status Relay
Channel 1: Deep Space Telemetry Stream.
Since it is AES-CBC, we can change IV to change the first plain text block given the known plain text part:
from pwn import *
data = open("voyager.bin", "rb").read()
# change device id from:
# 0x13371337: Status Relay
# to
# 0xdeadbabe
iv = bytearray(data[:16])
body = data[16:]
old = struct.pack("<I", 0x13371337)
new = struct.pack("<I", 0xdeadbabe)
for i in range(4):
iv[i] ^= old[i] ^ new[i]
print(old, new)
p = remote("sunshinectf.games", 25401)
p.send(iv + body)
p.interactive()
Flag: sun{m4yb3_4_ch3ck5um_w0uld_b3_m0r3_53cur3}
.