Challenge: Warmer Up · CTF: DalCTF 2026 · Category: Forensics · Difficulty: Easy

TL;DR

The “challenge file” is the CTF’s own rules PDF. The flag is sitting in plain text as the very last line of the document. Open the PDF, scroll to the bottom (or run pdftotext), and read the rules like the author begged you to:

1
dalctf{d1d_y0u_r34d_th3m?}

That’s the whole thing. But let’s do it properly, because “it’s just plain text” is the conclusion — not something you know going in.


The setup

The challenge name is Warmer Up and the description is a cheeky “What, the rules again?”. The provided file is rules1.pdf — the same rules document handed out at the start of the event. The category tag is forensics, and the joke writes itself: the author is daring you to actually read the rules instead of skimming past them to get to the “real” challenges.

This is a classic CTF tradition. Almost every event hides a freebie flag somewhere in the rules, the welcome message, or the Discord topic. They’re worth a few easy points and they reward the one habit every competitor should have: read everything carefully.

But I didn’t know it was a freebie when I started. A 50-point forensics tag on a PDF could just as easily mean carved data after EOF, an embedded file, a stego’d image, or a malicious /OpenAction. So I treated it like any other PDF forensics target.


Step 1 — Identify the file

First, confirm what we’re actually holding:

1
2
3
4
5
file rules1.pdf
# rules1.pdf: PDF document, version 1.5

du -b rules1.pdf
# 54267 rules1.pdf

A ~53 KB PDF, version 1.5. Nothing weird yet. On to the standard forensics passes.

Step 2 — Look for the easy win (strings + flag grep)

The fastest possible check — grep the raw bytes for anything flag-shaped:

1
strings -n 6 rules1.pdf | grep -iE "flag|ctf|dalctf|password|secret"

Nothing. That’s expected — the actual page text in a PDF lives inside compressed (FlateDecode/zlib) streams, so strings on the raw file won’t surface readable body text. This is the #1 reason people get stuck on PDF challenges: they run strings, see nothing, and assume the flag is deeply hidden, when in reality it’s just compressed plain text.

Step 3 — Map the structure with binwalk

1
binwalk rules1.pdf
1
2
3
4
5
6
7
DECIMAL    HEXADECIMAL   DESCRIPTION
--------------------------------------------------------------
0          0x0           PDF document, version: "1.5"
227        0xE3          Zlib compressed data, default compression
6038       0x1796        Zlib compressed data, default compression
13740      0x35AC        Zlib compressed data, default compression
...        ...           (dozens more zlib streams)

Dozens of zlib streams. At first glance this looks suspicious (“why so many embedded blobs?!”), but this is completely normal for a PDF — each text object, font subset, and content stream gets its own Flate-compressed object. This is a structural artifact, not a hiding spot. Don’t get nerd-sniped into carving forty font tables.

Step 4 — Metadata

1
exiftool rules1.pdf
1
2
3
4
5
Page Count    : 3
Title         : rules.md
Creator       : Mozilla/5.0 ... HeadlessChrome/148.0.0.0 ...
Producer      : 3.0.35 (5.1.21)
Create Date   : 2026:06:03 19:40:42+00:00

Interesting little tells here, but nothing secret:

  • Title: rules.md — the source was a Markdown file.
  • Creator: HeadlessChrome — this PDF was generated by “printing” the rendered Markdown to PDF via headless Chrome.

Translation: someone wrote rules.md, rendered it in a browser, and printed it. The flag, if it’s text, will be in the document body, not in some exotic structure. That points us straight at the rendered text.

Step 5 — Just read the document

This is the move people skip. Decompress the streams and dump the actual text:

1
pdftotext rules1.pdf -

The output is exactly what you’d expect from a rules sheet — welcome blurb, in-person vs. online brackets, prizes, logistics, and the rules list:

1
2
3
4
5
6
Rules

In person team size limit is 5 members. Online has no team limit.
Flag format is dalctf{...} unless otherwise specified
Do not share any flags, solutions, or challenge info publicly during the CTF.
...

And then, after the AI Policy section, the document signs off:

1
2
3
4
5
... Our challenge authors put time and effort into making these
challenges, so ideally people will put in some honest effort in solving them.
DONT SLOP
Thank you for your cooperation to make DalCTF fun for everyone!
dalctf{d1d_y0u_r34d_th3m?}

There it is — the final line of the entire document:

1
dalctf{d1d_y0u_r34d_th3m?}

The flag literally reads “did you read them?” — a perfect punchline for a challenge whose description is “What, the rules again?”


Step 6 — Due diligence (ruling out the rabbit holes)

Even after finding the flag, it’s worth a 30-second sanity check to confirm there isn’t a second, harder flag hidden elsewhere — and to confirm the PDF is benign.

Appended data after EOF? A common PDF trick is stashing a ZIP or image after the %%EOF marker.

1
2
3
4
grep -aob '%%EOF' rules1.pdf
# 54261:%%EOF
stat -c%s rules1.pdf
# 54267

The last %%EOF is at offset 54261; the file is 54267 bytes. That’s only 6 trailing bytes — just a newline/whitespace. Nothing carved onto the end.

Active / embedded content? PDFs can carry JavaScript, embedded files, or auto-run actions.

1
2
strings rules1.pdf | grep -aiE "javascript|/js|/embeddedfile|/openaction|/launch|/uri"
# (no output)

No /JavaScript, no /EmbeddedFile, no /OpenAction, no /Launch. The PDF is clean — it’s purely a rendered document with no hidden payload.

Confirmed: one flag, in plain sight, at the bottom of the rules.


Lessons / takeaways

  • Read the rules. Actually read them. This is the entire moral of the challenge, and it generalizes: in CTFs (and pentests), the intro material, READMEs, and “boring” docs frequently hide the win.
  • strings on a PDF tells you almost nothing about its text. PDF body text is Flate-compressed inside stream objects. Reach for pdftotext, mutool, or pdf-parser to read content — not strings.
  • Don’t get nerd-sniped by structure. Forty zlib streams in a PDF is normal (fonts + content objects), not forty hidden files. Know what “normal” looks like so you can spot what isn’t.
  • Metadata is a free hint. Title: rules.md + Creator: HeadlessChrome immediately told us this was Markdown → browser → PDF, meaning the payload was plain rendered text, not an exotic embed.
  • Finish with a quick EOF + active-content check. Even a freebie deserves a 30-second confirmation that you didn’t miss a second flag and that the file is safe to open.

A perfect warm-up. Or, as the author put it: DONT SLOP. 🐙

Flag: dalctf{d1d_y0u_r34d_th3m?}