archlinux / r3t0x@portfolio
ALL SYSTEMS NOMINAL /
← Back to archive · Pwn

Securinets Friendly CTF 2026 / Pwn WRITEUP

CyberLeek's Final Upload

The final GTA VI archive is already leaving Rockstar's internal network. CyberLeek reached the relay, but the interface was destroyed and the upload continues as an unreadable stream. Keep the last copy of the build from disappearing!

EVENTSecurinets Friendly CTF 2026CATEGORYPwnDIFFICULTYeasyPOINTS200
binary-protocolautomation

Walkthrough

Solution

Treat the connection as a binary stream because each frame is deliberately split across short writes. Read LEEK, then the big-endian sequence, operation, payload length, payload, and checksum. Verify that the checksum is the 32-bit sum of the payload bytes.

Apply the requested operation: reverse, XOR, rotate left, sort, or byte-wise add. For XOR, rotate, and add, the first payload byte is the key rather than data. Reply with ACK!, the original sequence, result length, result, and its big-endian checksum. Processing all 32 frames reveals the flag.

Reference solver

The reference solver supplied with the writeup:

#!/usr/bin/env python3
from pwn import *

context.log_level = "error"

io = remote("127.0.0.1", 9004)
io.recvuntil(b"BEGIN UPLOAD\n")

for _ in range(32):
    io.recvuntil(b"LEEK")

    sequence = u16(io.recvn(2), endian="big")
    operation = io.recvn(1)[0]
    length = u16(io.recvn(2), endian="big")
    payload = io.recvn(length)
    received_sum = u32(io.recvn(4), endian="big")

    assert received_sum == sum(payload) & 0xffffffff

    data = payload
    if operation in (2, 3, 5):
        key = payload[0]
        data = payload[1:]

    if operation == 1:
        result = data[::-1]
    elif operation == 2:
        result = bytes(byte ^ key for byte in data)
    elif operation == 3:
        shift = key % len(data)
        result = data[shift:] + data[:shift]
    elif operation == 4:
        result = bytes(sorted(data))
    else:
        result = bytes((byte + key) & 0xff for byte in data)

    reply = b"ACK!"
    reply += p16(sequence, endian="big")
    reply += p16(len(result), endian="big")
    reply += result
    reply += p32(sum(result) & 0xffffffff, endian="big")
    io.send(reply)

io.recvuntil(b"UPLOAD COMPLETE\n")
print(io.recvline().decode().strip())
io.close()

Flag

Securinets{r4w_fr4m3s_c4rr13d_th3_f1n4l_bu1ld}
Published 2026-09-28 · by r3t0x← Back to archive · Pwn
0xSEARCH_INDEX

Trace a memory.

INDEX ONLINE0 addresses
↑↓ TRACEENTER OPENESC DISMISS