SKIP TO MAIN CONTENT

[ WRITEUP NODE / FIELD REPORTS ]

SOLVED CHALLENGES & FIELD ANALYSIS

SECURITY RESEARCH KNOWLEDGE TECHNIQUES
B3S/WRITEUPS/GASLIGHTCTF-2026-ICON-SKETCH-WRITEUP
← BACK TO ARCHIVE
EVENT: gaslightCTF 2026CATEGORY: ForensicsPOINTS: 500 PTS

GasLightCTF 2026 - Icon Sketch Writeup

AUTHORED BY:@bealthguy8/16/2026

icon-sketch

  • Category: forensics · Author: riyc
  • Description: "the pee people found the first version of the gaslightCTF icon... apparently theres a flag in here?"
  • Attachment: icon.zipicon.png (2000×800 RGBA, gaslightCTF logo)

Flag: gaslightCTF{i5_th4t_supp0s3d_2b_p1ss?}

TL;DR

  1. unzip icon.zipicon.png
  2. strings icon.png → two base64 blobs in the XMP metadata (Iptc4xmpExt:AOTitle and dc:title) + a plaintext hint dGhlIHBlZSBwZW9wbGUgc2FpZCB0byBkZWNvZGUgYW5kIHB1dCB0aGUgdGl0bGVzIHRvZ2V0aGVy.
  3. Hint decodes to: "the pee people said to decode and put the titles together".
  4. Title A: base64 → "2e 2e ..." hex → ASCII: ........CTF..._.h4._..pp0s3..2b_.1s..} (dots = blanks).
  5. Title B: base64 → tzhortsg...{r5.g..g.hf.....w_...k..h?.Atbashgaslight...{i5.t..t.su.....d_...p..s?..
  6. The two decoded titles are perfectly complementary (A's letters sit exactly where B has dots and vice-versa; no overlaps, no gaps). Overlay A[i] if A[i]!='.' else Atbash(B)[i] → flag.

Recon chain

Base64 + hex, and a raw hint

strings -a icon.png shows (besides the PNG header/XMP):

dGhlIHBlZSBwZW9wbGUgc2FpZCB0byBkZWNvZGUgYW5kIHB1dCB0aGUgdGl0bGVzIHRvZ2V0aGVy

the pee people said to decode and put the titles together (base64, plaintext hint).

The two "titles" in XMP

<Iptc4xmpExt:AOTitle><rdf:li xml:lang='x-default'>
  MmUgMmUgMmUgMmUgMmUgMmUgMmUgMmUgNDMgNTQgNDYgMmUgMmUgMmUgNWYgMmUgNjggMzQgMmUgNWYgMmUgMmUgNzAgNzAgMzAgNzMgMzMgMmUgMmUgMzIgNjIgNWYgMmUgMzEgNzMgMmUgMmUgN2Q=
</rdf:li></Iptc4xmpExt:AOTitle>
<dc:title><rdf:li xml:lang='x-default'>
  dHpob3J0c2cuLi57cjUuZy4uZy5oZi4uLi4ud18uLi5rLi5oPy4=
</rdf:li></dc:title>
  • Title A: base64 → 2e 2e 2e ... 43 54 46 ... 7d (space-separated hex bytes) → bytes.fromhex(...)........CTF..._.h4._..pp0s3..2b_.1s..}. Dots = missing chars.
  • Title B: base64 → tzhortsg...{r5.g..g.hf.....w_...k..h?.. The leading tzhortsg is Atbash of gaslight (t↔g z↔a h↔s o↔l r↔i s↔h). Atbash the whole string → gaslight...{i5.t..t.su.....d_...p..s?..

Put them together

A and Atbash(B) are the same 38-char skeleton with complementary blanks: every index has a letter in exactly one of the two. Merge with A[i] if A[i] != '.' else Atbash(B)[i]:

A : ........CTF..._.h4._..pp0s3..2b_.1s..}
AB: gaslight...{i5.t..t.su.....d_...p..s?.
   = gaslightCTF{i5_th4t_supp0s3d_2b_p1ss?}

Commands (copy-paste)

unzip icon.zip && cd extracted
# hint
echo &#039;dGhlIHBlZSBwZW9wbGUgc2FpZCB0byBkZWNvZGUgYW5kIHB1dCB0aGUgdGl0bGVzIHRvZ2V0aGVy&#039; | base64 -d
# decode titles
python3 - <<&#039;EOF&#039;
import base64
a=&#039;MmUgMmUgMmUgMmUgMmUgMmUgMmUgMmUgNDMgNTQgNDYgMmUgMmUgMmUgNWYgMmUgNjggMzQgMmUgNWYgMmUgMmUgNzAgNzAgMzAgNzMgMzMgMmUgMmUgMzIgNjIgNWYgMmUgMzEgNzMgMmUgMmUgN2Q=&#039;
b=&#039;dHpob3J0c2cuLi57cjUuZy4uZy5oZi4uLi4ud18uLi5rLi5oPy4=&#039;
A=bytes.fromhex(base64.b64decode(a).decode()).decode()
at=lambda s: &#039;&#039;.join(chr(219-ord(c)) if c.islower() else chr(155-ord(c)) if c.isupper() else c for c in s)
AB=at(base64.b64decode(b).decode())
print(&#039;&#039;.join(A[i] if A[i]!=&#039;.&#039; else AB[i] for i in range(len(A))))
EOF

Findings / lessons

  • strings on a PNG is the first move: text chunks + XMP are where hidden data lives. exiftool -a or strings | grep -i 'xmp\|title' exposes it.
  • Base64 output can be another encoding: title A was base64 → hex-with-spaces → ASCII. Chain until it reads.
  • Atbash (a↔z, b↔y, …) turned tzhortsg into gaslight — a reliable tell when a lowercase blob starts with a jumbled 8-letter word.
  • "Put the titles together" → the two decoded strings share a skeleton and complement each other exactly (A's blanks == B's letters). Overlay with blank-fill.
  • Image pixels were a dead end: the logo is just the gaslightCTF icon (14 unique colors, rare colors = anti-aliasing, nothing stashed).

Escalation toolkit (if blank-fill overlay isn't the rule)

  • Try XOR of the two decoded strings, or interleave A/Atbash(B) by the dot pattern.
  • Check for a THIRD title/metadata field (IPTC ArtworkTitle, DocumentName, Comment).
  • If pixels matter: mask the non-logo colors and OCR; check alpha-channel stego; zsteg if installed.

Flag

gaslightCTF{i5_th4t_supp0s3d_2b_p1ss?}