$ / 2 min read/web

CSALE

A Flask storefront solved black-box after the source release was pulled — unauthenticated account enumeration, an unthrottled 4-digit PIN, and a two-layer decoy built to eat your time.

section
CSAW26
event
ctf.csaw.io ↗
category
web
status
● solved

Note the flag format: this challenge uses last year’s csawctf{}, not csaw{}.

Summary

A Flask storefront. The organisers pulled the source release as “inaccurate”, so this had to be solved black-box against the live instance. The real difficulty is not the exploitation — it is a two-layer decoy designed to absorb effort on a hidden-text extraction that turns out to be bait.

1. Account enumeration

The store exposes seller accounts, including a non-obvious one: superdiscreetflaguser.

Spelling matters: this instance uses discreet; the Revenge instance uses discrete. Easy to mistype.

2. PIN brute force

Accounts are gated behind a 4-digit PIN with no lockout and no rate limiting — a 10,000-key space. Recovered:

Walter_W:              3276
Zoro:                  7800
OSIRIS:                9898
Zuko:                  0540
superdiscreetflaguser: 9837

3. Pull the flag account’s images

Authenticated as the flag account, fetch its listing/draft images rather than the public thumbnails.

4. The two-layer trap

Layer 1 — the decoy (expensive, wrong)

One image carries text rendered at extremely low contrast: grey on orange, roughly 20 RGB levels of separation, completely invisible at normal viewing. Recovering it requires per-channel separation, contrast stretching, and connected-component analysis to segment the glyphs. It yields:

csawctf{REDACTED}

This feels like the solve. It is not. The same image also carries large handwritten text above and below the flag line reading:

do not submit this as flag / you will be banned

Layer 2 — the real flag

The actual flag is in a second image (flag_v2.png), written in plain black handwriting across the top of a Zuko/Aang panel from Avatar. No extraction technique is needed — it is legible as soon as you are looking at the right asset.

csawctf{REDACTED}

(“That’s rough, buddy.”)

Lesson

The hard-to-extract hidden text exists specifically to consume time. When a recovered flag is rejected, re-examine which asset you are looking at before assuming the extraction was wrong.

Artifacts: ~/ctf/work/web/ — flag_v2.png (real), flag_img.png (decoy), flagv2_zoom.png, zoom_rough.png, pins_new.txt

## challenge files

137 files · 12.2 MB
  • _account_unlisted_1_image.png
  • advance.py
  • afterbrace.png
  • allusers.py
  • attach.py
  • big_OSIRIS.png
  • big_Walter_W.png
  • big_Zoro.png
  • brute.py
  • brute_all.py
  • brute_new.py
  • ch_A.png
  • ch_A_auto.png
  • ch_B.png
  • +100 more
download .zip

flags redacted; flag images and local flag.txt files removed