┌───────────────────────┐
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
└───────────────────────┘
coalmine revenge — DEF CON CTF Qualifier 2026
~ Imattas aka Zemi
 Category: Binary Exploitation
 Difficulty: Medium
 Points: 299
 Author: Imattas aka Zemi
 Flag: bbb{REDACTED}

────────────────────────────────────────────────────────────────────────────────

--[ Challenge Description ]--

 Public challenge prompt was not recoverable from indexed sources.

────────────────────────────────────────────────────────────────────────────────

--[ Recon / Initial Analysis ]--

Challenge name and point value were recovered from official index snippets; full
handout was not archived.

The first pass is to avoid guessing from the bird-themed prompt and instead
build a small, repeatable workflow around the handout or service. For this file,
the public archive did not expose enough verified challenge material to claim a
completed solve transcript, so the writeup records the clean solve path I would
use once the handout is available.
-- bash --
$ mkdir -p work/{handout,notes,scripts}
$ file handout/* 2>/dev/null || true
$ strings -a handout/* 2>/dev/null | head -50
────────────────────────────────────────────────────────────────────────────────

--[ Vulnerability / Observation ]--

Unverified. Look for incomplete validation added around the original failing
path, especially checks that validate once but reuse mutated state later.

Start from the original coalmine model, then diff mitigations and code changes.
Revenge tasks usually patch the obvious primitive and leave a second-order bug
in the same state machine.

────────────────────────────────────────────────────────────────────────────────

--[ Exploitation / Solution ]--

:: Step 1 — Rebuild the challenge context

Keep the local environment close to the remote challenge. Save the original
handout, record hashes, and write every probe as a command or script so the path
can be repeated.
-- bash --
$ sha256sum handout/*
$ tree -a handout
:: Step 2 — Reduce the problem

1. Diff the original and revenge binaries if both handouts are available.
2. Port the original harness and mark where it fails.
3. Trace the new guard and identify assumptions it introduced.
4. Search adjacent command sequences for stale indexes, stale lengths, or
inconsistent ownership.
5. Exploit the second primitive with the same remote harness shape.

:: Step 3 — Confirm the flag path

The final check is always local first: the script should either print bbb{...}
directly or produce one artifact where the flag is visible. Only after that
should the same payload or input be sent to the live challenge service.

────────────────────────────────────────────────────────────────────────────────

--[ Full Exploit Script ]--
-- python --
#!/usr/bin/env python3
from pwn import *

# ── config ──────────────────────────────────────────────
HOST = args.HOST or 'challenge.host'
PORT = int(args.PORT or 31337)
BINARY = './challenge'

context.binary = ELF(BINARY, checksec=False)
context.log_level = 'info'

# ── helpers ─────────────────────────────────────────────
def start():
    if args.REMOTE:
        return remote(HOST, PORT)
    return process(BINARY)

def build_payload():
    # Replace this with the verified primitive from the local handout.
    offset = 0
    payload = flat({
        offset: b'REPLACE_WITH_CONTROLLED_DATA',
    })
    return payload

# ── exploit ─────────────────────────────────────────────
def main():
    io = start()
    io.sendlineafter(b'> ', build_payload())
    io.interactive()

if __name__ == '__main__':
    main()
────────────────────────────────────────────────────────────────────────────────

--[ Key Takeaways ]--

- Revenge tasks are fastest when solved by diffing against the first version.
- A patched bug often points directly at the remaining attack surface.
- Do not submit this generated file as an official qualifying writeup without
adding your own verified solve notes, command output, and final flag.