challenge

Capture The Flag challenges

Cyber security from several angles in one place: attack a practice target as the red team, investigate an incident as the blue team, and piece together clues from open sources with OSINT. Every challenge comes with step-by-step hints and the tools you can use.

0/6 solved · 0 pts

Red Team

Think like an attacker: recon, find the gap, exploit.

red-01Easy100 pts

The Staging Server Nobody Cleaned Up

Scenario
You've been hired to pentest PT NusaLogistik (fictional). The only in-scope entry point is the staging employee portal. Its login form is disabled, but the developers are known for leaving traces.
Mission
Recon the portal, find the leaked configuration file, then extract the flag hidden inside the service token.
Files & target
Flag format
FLAG{...}

Hints Open them one at a time, only when you're stuck.

Hint 1 — Start with what you can see

A page that looks empty often keeps notes in its source. Read the HTML, not the rendered page.

Tools
  • View Source (Ctrl+U) — read the raw HTML, including <!-- --> comments
  • DevTools → Elements — inspect elements and comments in the DOM
  • curl — curl -s <url> | less to see the response as-is
Hint 2 — What's forbidden is interesting

robots.txt is a polite request to crawlers, not access control. Disallowed paths often point at sensitive files.

Tools
  • curl — fetch robots.txt from the same folder as the portal
  • gobuster / ffuf / dirsearch — enumerate directories & files (.bak, .old, ~) with a wordlist when there's no clue
  • Burp Suite — map every request & response on the target
Hint 3 — Take the token apart

Three dot-separated parts means a JWT: header.payload.signature, each Base64URL. The payload isn't encrypted. One field's value isn't plain text.

Tools
  • CyberChef — JWT Decode recipe, then From Hex for the odd field
  • jwt.io — view a JWT's header & payload (never paste real production tokens into third-party sites)
  • base64 / xxd — echo <payload> | base64 -d, then echo <hex> | xxd -r -p

Blue Team

Think like a defender: detect, analyse, respond.

blue-01Easy100 pts

A Night That Was Too Busy

Scenario
The SOC got an alert from PT NusaLogistik's (fictional) portal server in the early hours of 12 October 2026: a spike in requests and a strange file in the upload folder. You've been handed a copy of the web server's access log.
Mission
Reconstruct the attack: which attacker got in, which webshell they uploaded, and which server the data was exfiltrated to.
Files & target
Flag format
FLAG{attackerip_webshellfilename_exfiltrationserverip}

Hints Open them one at a time, only when you're stuck.

Hint 1 — Who's the loudest?

Count requests per IP and per status code. A run of 401s on /login followed by a single 302 is a successful brute force. Careful: not every noisy IP got in.

Tools
  • awk + sort + uniq — awk '{print $1}' access.log | sort | uniq -c | sort -rn
  • grep — grep '"POST /login' access.log | awk '{print $1, $9}' | sort | uniq -c
  • GoAccess — quick dashboard from an access log (goaccess access.log --log-format=COMBINED)
Hint 2 — Follow the trail after login

Filter every request from the attacker's IP and read it in order. An avatar upload that accepts a .php file is a red flag.

Tools
  • grep — grep '^<ip> ' access.log for a single attacker's timeline
  • Splunk / Elastic (Kibana) — query by IP and sort by time
  • User-Agent — watch the last column: a UA change marks a change of tooling
Hint 3 — Disguised commands

The webshell's ?c= parameter holds commands that were Base64-encoded, then URL-encoded. Decode them one by one; one of them ships an archive to an outside server.

Tools
  • CyberChef — URL Decode → From Base64 recipe
  • base64 -d — grep -o 'c=[^ ]*' access.log | cut -d= -f2 | sed 's/%3D/=/g' | while read x; do echo "$x" | base64 -d; echo; done
  • Python — urllib.parse.unquote + base64.b64decode to automate it

blue-02Medium150 pts

Whispers Over DNS

Scenario
Two days after the portal incident, the IDS flagged workstation 10.10.5.23, used by PT NusaLogistik's (fictional) finance team, for contacting the same IP as the earlier exfiltration server. The network team managed to record a minute of its traffic.
Mission
Open the capture in Wireshark, find out what command the malware got from its C2 server, then reconstruct the stolen data. That data is the flag.
Files & target
Flag format
FLAG{...}

Hints Open them one at a time, only when you're stuck.

Hint 1 — Get the big picture first

Don't read packets one by one yet. Find out which protocols are present and who this workstation talks to. One IP isn't on the internal 10.x network.

Tools
  • Wireshark → Statistics → Protocol Hierarchy — see the protocol mix (DNS, HTTP, TCP)
  • Wireshark → Statistics → Conversations — the IPv4 tab lists which IPs talk to each other
  • tshark — tshark -r capture.pcap -q -z conv,ip
Hint 2 — Listen in on the C2 conversation

The malware fetches its task over plain HTTP. Reassemble the TCP packets into one conversation and read the server's reply. Watch out: a FLAG{...} string you find with strings/grep isn't necessarily the right one.

Tools
  • Display filter — http.request or ip.addr == <outside-ip>
  • Follow → TCP Stream / HTTP Stream — right-click an HTTP packet, then Follow to read the request & response
  • File → Export Objects → HTTP — save every file that went over HTTP
  • NetworkMiner — an alternative for extracting files & hosts from a pcap
Hint 3 — Data disguised as domain names

The C2 task names a DNS zone and a <seq>-<hex> label format, sent out of order. Grab every query to that zone, sort by seq number, join the hex parts, then decode.

Tools
  • Display filter — dns.qry.name contains "cdn-metrics" or dns.flags.rcode == 3 (NXDOMAIN)
  • Apply as Column — turn dns.qry.name into a column, then sort it
  • tshark — tshark -r capture.pcap -Y 'dns.flags.response==0 && dns.qry.name contains "cdn-metrics"' -T fields -e dns.qry.name | sort
  • CyberChef — From Hex recipe for the joined hex chunks

OSINT

Think like an investigator: collect, connect, and verify information from open sources without touching the target.

osint-01Easy100 pts

A Weekend in Bandung, Supposedly

Scenario
An employee of PT NusaLogistik (fictional) posted a "weekend getaway in Bandung" photo on the same day they called in sick. HR asked for help verifying it, and all you've got is the original photo file.
Mission
Work out when the photo was actually taken and where. Don't trust the caption; trust the data.
Files & target
Flag format
FLAG{YYYYMMDD_latitude_longitude} (decimal coordinates, 3 decimal places)

Hints Open them one at a time, only when you're stuck.

Hint 1 — A photo holds more than pixels

Phone photos usually carry EXIF metadata: camera make, editing app, timestamps, even GPS. Download the original file, not a screenshot.

Tools
  • exiftool — exiftool -a -G1 liburan.jpg to list every tag with its group
  • Jeffrey's Image Metadata Viewer / exif.tools — web alternatives (for practice photos only, never personal ones)
  • File → Properties (Windows) / Get Info (macOS) — a quick look at some of the metadata
Hint 2 — Not every date is the same

There are several time tags. ModifyDate changes when the photo is edited, while DateTimeOriginal records when the shutter fired. The caption (ImageDescription) can say anything.

Tools
  • exiftool — exiftool -time:all -G1 liburan.jpg
  • CyberChef — Extract EXIF recipe, right in the browser
Hint 3 — From degrees to a map

EXIF GPS is stored as degrees, minutes, seconds (DMS) plus a direction. Decimal = degrees + minutes/60 + seconds/3600, negative for South or West. Paste the result into a map to confirm.

Tools
  • exiftool -n — exiftool -n -GPSPosition liburan.jpg prints decimal numbers directly
  • Google Maps / OpenStreetMap — paste "lat, lon" into the search box
  • Google Earth / Street View — compare the landmark in the photo with the location

osint-02Medium150 pts

The Server That Isn't on the List

Scenario
PT NusaLogistik (fictional) asked for a passive attack-surface assessment. According to their IT team, every service lives in a single official IP block. You've exported certificate history from Certificate Transparency logs and passive DNS data for their domain.
Mission
Read the scope document, then find the one subdomain that's still live but hosted outside the official IP block (shadow IT).
Files & target
Flag format
FLAG{subdomainlabel_ip} (leftmost label only, e.g. FLAG{www_192.0.2.10})

Hints Open them one at a time, only when you're stuck.

Hint 1 — List every name first

Certificate Transparency logs record every TLS certificate ever issued, so even hostnames that were never published show up. Pull every unique name_value. Wildcard certificates don't name a host, so skip them.

Tools
  • jq — jq -r '.[].name_value' crtsh.json | sort -u
  • crt.sh — in the real world: https://crt.sh/?q=%25.domain.com&output=json
  • subfinder / amass (passive mode) — collect subdomains from many open sources at once
Hint 2 — Where does each name point?

Passive DNS keeps a history of DNS answers along with when they were first and last seen. Filter A records whose IP isn't 192.0.2.x.

Tools
  • awk — awk -F, '$2=="A" && $3 !~ /^192\.0\.2\./' passive-dns.csv
  • csvkit / Excel / LibreOffice — filter the rrtype and rdata columns
  • SecurityTrails / VirusTotal — real-world passive DNS sources
Hint 3 — Alive or dead?

More than one host sits outside the official block, but some haven't been seen in years. Compare last_seen with the date on the scope document; the one still seen this week is your answer.

Tools
  • sort — sort -t, -k5 passive-dns.csv to order by last_seen
  • jq — jq '.[] | select(.name_value|test("<label>")) | {not_before, not_after}' crtsh.json to see its latest certificate

osint-03Medium150 pts

The Internet Never Forgets

Scenario
As part of a security awareness programme approved by PT NusaLogistik (fictional) and its staff, you've been asked to assess the digital footprint of their sysadmin, Raka Pratama. Details like an old handle and a personal email are exactly what attackers use for highly targeted phishing.
Mission
Starting from his current social media profile, find Raka's old handle and then the personal email he once published.
Files & target
Flag format
FLAG{oldhandle_personalemail}

Hints Open them one at a time, only when you're stuck.

Hint 1 — Read what isn't displayed

Social profiles often carry a verified link to the owner's website. It isn't always visible on the page, but it's in the source.

Tools
  • View Source (Ctrl+U) — look at the <link> and <meta> tags in <head>
  • rel="me" — the attribute Mastodon and others use to verify site ownership
  • curl + grep — curl -s <url> | grep -i 'rel="me"'
Hint 2 — A dead domain isn't a gone domain

Sites that were shut down often still have copies in a web archive. Look up Raka's old domain in the archive index.

Tools
  • Wayback Machine — in the real world: web.archive.org/web/*/domain.com/*
  • archive.today — an alternative archive that sometimes keeps pages Wayback doesn't
  • Sherlock / WhatsMyName — in the real world: check the same handle across hundreds of sites
Hint 3 — Deleted means it once existed

The latest capture says the email was removed. Open the older captures one by one.

Tools
  • Comparing captures — the Wayback Machine's Changes feature diffs two dates
  • grep — grep -rEo '[[:alnum:]._-]+@[[:alnum:].-]+' over downloaded copies of the pages

Rules

  • Every target lives in this site's /ctf/ folder and is static. Don't attack any other part of the site, the hosting server, or anyone else.
  • The companies, people, accounts, domains (.invalid), and IPs in the scenarios are fictional (IPs from the RFC 5737 documentation blocks).
  • Flags are checked in your browser by comparing SHA-256 hashes; nothing is sent to the server. Progress is stored in this browser only.
  • The techniques here are for practice and for systems you have written permission to test. OSINT on real people needs consent and a lawful basis; never use it to stalk or dox anyone.