Save The Trees

May 18, 2026

Save The Trees

Overview

Save The Trees was a multi-stage web challenge involving an announcement board and a separate print-spooler service. I recovered the first three flags through the board-side application logic. The fourth flag was not recovered, so this is a partial public writeup.

Concrete flags are redacted in this public version.

Challenge Context

Two hosts mattered:

  • announcement-board.ctf
  • print-spooler.ctf

The announcement board was the upstream application. The print spooler was a separate IIS/WebBatch system exposing a queue/status page.

The board-side path was fully useful for flags 1-3. The spooler remained the likely surface for the final flag, but I did not find a reliable control path for it during the event.

The spooler exposed one visible WebBatch route:

http://print-spooler.ctf/webcgi/webbatch.exe?print-spooler/print-spooler.web

The page displayed printer resource exhaustion and a queue of wasting-paper*.pdf files. The only visible action was a disabled Print a file button.

Repeated polling showed no queue mutation, and the baseline page stayed constant.

Inputs tested without useful behavior included:

  • GET parameters
  • POST form fields
  • multipart upload field names
  • WebBatch positional argument forms
  • admin/debug/source toggles
  • common proxy and reflection headers

Static-path testing showed partial normalization around queued PDFs, but not raw source disclosure for print-spooler.web.

PDF Review

The queued PDFs were downloaded and analyzed. They fell into repeated junk families:

  • large vector one-page junk art
  • 102-page split-document junk artifacts
  • Word-generated black-square paper-waste pages

Some files reconstructed to repeated THIS PAGE IS EMPTY text. Others contained abusive junk text like YOU DESERVE TO BURN and repeated WASTE. No attachments, JavaScript, embedded files, or useful OCR text were found.

Announcement Board Source Disclosure

The real progress came from announcement-board.ctf, which exposed many .inc files directly, including:

  • init.inc
  • constants.inc
  • common.inc
  • database.inc
  • api/account.inc
  • api/admin.inc
  • templates/*.inc
  • templates/admin/*.inc
  • lang/en.inc
  • lang/fr.inc

Important source facts:

  • init.inc contained flag 1 in a comment.
  • constants.inc loaded flag 2 and flag 3 from local files.
  • Roles were numeric: user, manager, and Bourgmestre.

The first recovered flag is redacted:

[redacted savethetrees flag 1]

Privilege Escalation

The board exposed account and admin logic through the recovered source. The working chain was:

  1. Create a user through the unauthenticated account flow.
  2. Abuse the role update logic to become a manager.
  3. Abuse a case-mismatch bug in update_user to escalate to Bourgmestre.
  4. Use privileged pages and methods to reach additional flag material.

The second and third recovered flags are redacted:

[redacted savethetrees flag 2]
[redacted savethetrees flag 3]

Remaining Flag 4 Research

The final flag was not recovered. The strongest remaining lead was hidden runtime logic in handlers such as:

  • /templates/index.php
  • /images/index.php
  • /js/index.php
  • /css/index.php

Those handlers consistently returned JSON 403 Forbidden, but they were connected to the same application language strings as the visible admin UI.

The update-language feature could rewrite language files and affect the hidden handlers’ output, proving runtime linkage. However, the available notes indicated that a language-file interpolation trick had been marked organizer-forbidden, so I did not use it as a solve path.

Takeaways

The most valuable bug class was source disclosure. Once the board’s .inc files were readable, the role model and escalation path became understandable. The print spooler looked important for the full challenge, but the solved flags came from the announcement board’s exposed source and broken authorization model.