SKIP TO MAIN CONTENT

[ WRITEUP NODE / FIELD REPORTS ]

SOLVED CHALLENGES & FIELD ANALYSIS

SECURITY RESEARCH KNOWLEDGE TECHNIQUES
B3S/WRITEUPS/COOKIE-TAMPER-BASIC-WEB
← BACK TO ARCHIVE
EVENT: Cyberweek Africa Qualifiers 2026CATEGORY: WebPOINTS: 100 PTS

Cookie Tamper

AUTHORED BY:@bealthguy10/5/2026

02 Cookie Tamper

Flag:

FLAG{cwa2026_18d3e1884e9eca82}

The blurb, taken at face value

An internal administrative session manager encodes client state directly into browser cookies using predictable transformations. Alter the serialized identity parameters to elevate privileges to administrator status.

That is a precise specification. It names a mechanism, a location, and an objective: a running application, a cookie carrying serialized state, a role field somewhere inside it, and a tamper that flips it to administrator. Each of those elements is directly testable.

Expected artefact

A login page that sets a cookie. The cookie would be base64 or JSON or a JWT, and somewhere inside it a field like role, is_admin, privilege or level. The expected procedure would be to decode it, edit one value, re-encode it, send it back, and hold administrator rights. The "predictable transformations" wording suggested something as plain as base64 or a hex encoding, which is to say no signature to defeat.

What the target actually was

The root of ch-002.ctf.africa returns this:

HTTP/2 200
content-type: text/html
last-modified: Mon, 28 Sep 2026 15:09:49 GMT
server: SimpleHTTP/0.6 Python/3.11.16
content-length: 169
<html><head><title>002-web-02-cookie-tamper</title></head><body><h2>Cyberweek Africa CTF Target: 002-web-02-cookie-tamper</h2><p>Endpoint operational.</p></body></html>

The Server header settles the question of target type. SimpleHTTP/0.6 is Python's http.server, which serves a directory of files. It has no sessions, no serialization, no role logic, and no request routing beyond filename lookup. There was no administrative session manager to tamper with.

Testing the cookie hypothesis

The absence of cookies was confirmed directly rather than assumed. The cookie jar after a request to the root was empty, not populated with something unreadable, because the response carried no Set-Cookie header at all. Every reachable path was then checked explicitly:

/            0 set-cookie headers
/flag.txt    0 set-cookie headers
/index.html  0 set-cookie headers

An application was probed for before concluding that none existed. Twenty-four paths were chosen to cover the vocabulary of the blurb as well as the obvious defaults:

admin  admin/  login  signin  session  dashboard  panel  console  app
api  api/session  auth  flag  flag.txt  .env  config.php  index.php
index.htm  home  robots.txt  sitemap.xml  static/  assets/  js/  app.js

All returned 404 except index.html and flag.txt. There was no login route, no session route, no administrative prefix, and nothing that returned a cookie.

The tampering mechanic was therefore not merely awkward to exercise. There was no cookie, no serialized identity parameter, and no privilege field anywhere on the target to alter.

The actual find

flag.txt was already visible in the probe list above, returning 200 with 31 bytes. A flag served at a guessable path carries the same shape as a decoy, so two properties were established before accepting it.

First, that flag.txt was the only thing in the directory. Candidates were generated by crossing eighty session, admin, cookie, identity and infrastructure words against eleven extensions, giving 880 paths in recon/paths.txt:

ffuf -w recon/paths.txt -u https://ch-002.ctf.africa/FUZZ -fs 335,169 -mc all -t 30 -timeout 15 -s

Filtering out the 404 body at 335 bytes and the index stub at 169, one hit:

flag.txt

Second, that the value was specific to this challenge rather than a generic placeholder. The sibling challenge 01-header-sleuth in the same event had already been solved, and its value differs:

ch-001: FLAG{cwa2026_0cef5e17574204d2}
ch-002: FLAG{cwa2026_18d3e1884e9eca82}

That per-challenge difference is the discriminating evidence. A shared or decoy value would have been identical across targets. The sibling account also documents the same deployment pattern, a Python SimpleHTTP file directory where the blurb described response headers but the value was a plain file in the body, which is consistent with the behaviour observed here.

The fetch:

HTTP/2 200
content-type: text/plain
date: Fri, 02 Oct 2026 21:21:10 GMT
last-modified: Mon, 28 Sep 2026 15:09:49 GMT
server: SimpleHTTP/0.6 Python/3.11.16
content-length: 31

FLAG{cwa2026_18d3e1884e9eca82}

Decoy material in the challenge folder

The supplied test-file.html contains:

<!-- KCR{always_check_the_source} class="hljs-keyword">-->

This is not FLAG{ }, so it is not the challenge value, but it is shaped exactly like one and its filename invites inspection. Two separate traps sit in this challenge, one in the folder and one on the target, and both are strings that look like values without being the answer.

Methodological assessment

The early phase of this challenge was spent on cookie mechanics before the existence of a cookie had been established. Reading the Server header, concluding that http.server was serving a directory, and proceeding directly to file enumeration would have been the correct order; an attempt was made to reverse a mechanism before confirming that the mechanism was deployed.

flag.txt was nearly discarded for the opposite reason. A flag served at a plain path felt too easy given a brief that described cookie tampering, so it was treated as a probable decoy while the search continued for a hidden application that did not exist. That was the more expensive of the two errors. The applicable standard is not whether a result appears too easy but whether the value is specific to the target and consistent with the deployment, and by that standard flag.txt qualified from the moment it was compared against the sibling challenge.

The broader lesson across this event is that the blurbs describe an intended technique rather than the shipped target. 01-header-sleuth promised response headers and delivered a static file. This one promises cookie tampering and delivers the same. Reading the server banner first converts that from a guessing game into a file listing.

Reproducing

The candidate list is in recon/paths.txt, the enumeration hits in recon/ffuf-crossed.txt, the response headers in evidence/flag-txt-headers.txt, and the value itself in loot/flag.txt. No browser automation was required; the whole target is three files served over HTTPS.