$ / 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{}, notcsaw{}.
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
flags redacted; flag images and local flag.txt files removed