← All writeups

CDDC2026

CDDC 2026 — Have You Seen This Cat (OSINT)

Challenge

Rift patrol underway; negative contact. Today will be just another ordinary day. That was the case until an unexpected order came from Headquarters.

[Simply put, a cat went missing in the Rift, and your orders are to retrieve ASAP. Received from He_dquart_rs]

'A CAT?'

Defender read the orders again and again until he realised it didn't change anything. Not a vulnerability search. Not a threat neutralisation. Find a cat. With only 13 photos as the lead. The cat's appearance is more normal than what it is hiding.

Provided: Have+You+Seen+This+Cat.zip containing IMG_2847.jpgIMG_2859.jpg (13 photos of a black-and-white tuxedo cat).

Flag format: CDDC2026{...}


Step 1 — Look at what we've got

Unzip and list:

unzip Have+You+Seen+This+Cat.zip
ls
# IMG_2847.jpg .. IMG_2859.jpg

All 13 are letterboxed JPEGs (~1024 px wide, ~570 px tall) showing a tuxedo cat in various settings: at a desk with a Korean Hackerschool FTZ Level 19 tutorial on the monitor, on a mechanical keyboard, being whacked with a black inflatable bat labelled QUANSHENG, on a brown leather couch, etc. The hint "more normal than what it is hiding" is a strong nudge that the visuals are misdirection — the payload is hidden in the file metadata.


Step 2 — Pull EXIF from every image

from PIL import Image
from PIL.ExifTags import TAGS
import os

d = r'C:\Users\wooai\Downloads\cat_ctf'
for f in sorted(os.listdir(d)):
    if not f.endswith('.jpg'): continue
    img = Image.open(os.path.join(d, f))
    exif = img._getexif() or {}
    for tag_id, val in exif.items():
        tag = TAGS.get(tag_id, tag_id)
        if tag in ('DateTimeOriginal', 'UserComment'):
            print(f, tag, val)

Every image is from an iPhone 15 Pro, KST (+09:00), all taken on 2026-04-16 between 13:30 and 13:36. More importantly, every UserComment is b'ASCII\x00\x00\x00X' where X is one ASCII character.

13 photos → 13 hidden bytes.


Step 3 — Sort the bytes by capture time

Time (KST) File UserComment char
13:30:00 IMG_2850 c
13:30:22 IMG_2854 h
13:30:47 IMG_2847 _
13:31:18 IMG_2858 o
13:31:55 IMG_2852 s
13:32:30 IMG_2856 i
13:33:03 IMG_2848 n
13:33:35 IMG_2855 t
13:34:07 IMG_2859 _
13:34:40 IMG_2849 2
13:35:13 IMG_2853 0
13:35:45 IMG_2857 2
13:36:18 IMG_2851 6

Concatenated: ch_osint_2026

This looks like a flag, but CDDC2026{ch_osint_2026} is rejected — it is just a category tag for the challenge. The real lead is somewhere else; the EXIF chain only tells us "yes, you're meant to look beyond the pictures."


Step 4 — A nudge from a friend

The decisive lead was a hex-encoded URL shared by another solver:

68747470733A2F2F742E6D652F732F63 6174735F73617665746865776F726C64

ASCII-decoded:

https://t.me/s/cats_savetheworld

A Telegram channel called "Cats save the world" (@cats_savetheworld). 1 subscriber, 1 photo. Channel created 2026-04-15.

A real solver could realistically reach this URL by reverse-image-searching the cat (Yandex / Google Lens) — the channel is the unique online presence containing this cat — or by enumerating channels containing the EXIF tag ch_osint_2026. Either way, the EXIF chain does serve a purpose: it confirms you're hunting for a "ch_osint_2026"-themed cat presence online.


Step 5 — Pull the photo

The Telegram preview page exposes the CDN URL of the lone photo. Download it:

curl -sL -A "Mozilla/5.0" "https://t.me/s/cats_savetheworld" \
  | grep -oE 'background-image:url\([^)]+\)' \
  | head -1

https://cdn5.telesco.pe/file/...jpg

Fetch it and open. The same tuxedo cat is curled up on a quilted mat, with a clean text overlay across the bottom edge of the image:

CDDC2026{m30w_y0u_f0und_m3}

Flag

CDDC2026{m30w_y0u_f0und_m3}

Lessons / takeaways


Files referenced