pwnfreemedium

Stacking Melodies

metactf

Task: a public DawgCTF / UMBCCyberDawgs source release exposes a non-PIE packet parser with both a format-string bug and an integer-overflow-backed heap overflow. Solution: use the format string to leak code pointers, infer the remote win() offset, and partially overwrite the logging function pointer with %hn to jump to the flag printer.

$ ls tags/ techniques/
ret2winformat_string_leakpartial_function_pointer_overwrite

Stacking Melodies — metactf

Description

A server at nc.umbccd.net 8929 is hosting the same code, but theirs has a flag, retrieve it. Public source: https://github.com/UMBCCyberDawgs/dawgctf-sp26/tree/main/Stacking%20melodies

This challenge came from the public UMBCCyberDawgs / DawgCTF '26 repository, while my local workspace grouped it under metactf. We are given the source for a 64-bit Linux service that parses a small custom packet, prints a title field, computes a rating, and then calls a function pointer stored in a heap-allocated session context.

Analysis

The public source immediately reveals two memory corruption bugs.

1. Primary bug: format string

The title is attacker-controlled and reaches:

printf(title);

This gives both an information leak and an arbitrary write through %n if one of the stack arguments resolves to a writable pointer.

2. Secondary bug: integer overflow into heap overflow

The code also validates the data length incorrectly:

static inline int validate_size(uint32_t sz) { size_t aligned = (sz + 7) & ~7; return (int)aligned; }

Later it allocates with:

size_t stream_size = (size_t)(d_len + 0x40); char *stream_buf = malloc(stream_size); fread(stream_buf, 1, d_len, stdin);

Because validate_size() returns an int after alignment while the real allocation uses d_len + 0x40, a large d_len can wrap and produce a too-small heap chunk before fread() copies the full attacker-controlled size. That looks exploitable, but I did not need it for the solve.

Build assumptions

The source comment says the binary was compiled with:

gcc -no-pie -g in.c -o out

That matters a lot: a non-PIE binary keeps stable text addresses, so once a code pointer is leaked, nearby functions such as win() can be inferred reliably.

Exploitation

Step 1: confirm the format-string layout remotely

I first sent a title of the form:

%1$p|%2$p|%3$p|...|%40$p

...

🔒

Permission denied (requires auth)

Sign in to read this free writeup

This writeup is free — just sign in with GitHub to read it.

$ssh [email protected]