Vapt-env / server /knowledge_base /responses.py
Sayuj63's picture
first commit
344db23
Raw
History Blame Contribute Delete
48.3 kB
"""
Response templates for simulated security tool output.
Each vulnerability type has templates for three difficulty tiers:
- easy: Labeled output with severity tags, CWE, CVSS, remediation.
- medium: Evidence-based output requiring analyst interpretation.
- hard: Raw HTTP/tool output requiring full analysis.
Templates use Python str.format() named variables. The tool simulation
engine fills in context variables to generate realistic output.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional
# ---------------------------------------------------------------------------
# Data class
# ---------------------------------------------------------------------------
@dataclass
class ResponseTemplate:
"""Response template for a single vulnerability type."""
vuln_type_id: str
vulnerable: Dict[str, str] # keys: "easy", "medium", "hard"
safe: str # what a clean / non-vulnerable response looks like
context_vars: List[str] = field(default_factory=list)
# ---------------------------------------------------------------------------
# Template registry (module-level singleton)
# ---------------------------------------------------------------------------
_TEMPLATES: Dict[str, ResponseTemplate] = {}
def _register(t: ResponseTemplate) -> None:
_TEMPLATES[t.vuln_type_id] = t
# ===================================================================
# 1. SQL Injection
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="sqli",
vulnerable={
"easy": (
"[CRITICAL] SQL Injection DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Anomalous database response detected\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" Payload sent: {payload}\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid input", "message": "The provided value is not valid"}}\n\n'
"No SQL injection indicators found on {host} {endpoint}. "
"Input appears to be parameterized. No database error messages leaked."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "service_version", "evidence_detail",
"remediation", "status_code", "response_body", "response_time",
],
))
# ===================================================================
# 2. Stored XSS
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="xss_stored",
vulnerable={
"easy": (
"[HIGH] Stored Cross-Site Scripting (XSS) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Unsanitized user input rendered in stored content\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" Submitted payload was echoed without encoding in a subsequent page load.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" POST {endpoint} -> HTTP {status_code}\n"
" Subsequent GET response body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms\n"
" Note: Payload present in DOM on later page render."
),
},
safe=(
"HTTP/1.1 200 OK\n"
"Content-Type: text/html; charset=utf-8\n"
"Content-Security-Policy: default-src 'self'; script-src 'self'\n"
"X-Content-Type-Options: nosniff\n\n"
"Stored input was HTML-entity encoded on output. "
"No executable script rendered. CSP header present on {host} {endpoint}."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 3. Reflected XSS
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="xss_reflected",
vulnerable={
"easy": (
"[HIGH] Reflected Cross-Site Scripting (XSS) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Reflected input in HTTP response without encoding\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" The payload was reflected directly into the HTML response.\n"
" X-XSS-Protection header: not set\n"
" Content-Security-Policy: not set\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 200 OK\n"
"X-XSS-Protection: 1; mode=block\n"
"Content-Security-Policy: default-src 'self'\n\n"
"Payload was HTML-entity encoded in response "
"(<script> rendered as text). No reflected XSS on {host} {endpoint}."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 4. Server-Side Request Forgery (SSRF)
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="ssrf",
vulnerable={
"easy": (
"[CRITICAL] Server-Side Request Forgery (SSRF) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Internal resource accessible via user-controlled URL\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" The server fetched an internal resource and returned its content.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid URL", "message": "The requested URL is not allowed. '
'Only external HTTP/HTTPS URLs are permitted."}}\n\n'
"URL scheme and host validated on {host} {endpoint}. "
"Internal/private IP ranges blocked."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 5. Server-Side Template Injection (SSTI)
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="ssti",
vulnerable={
"easy": (
"[CRITICAL] Server-Side Template Injection (SSTI) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Template expression evaluated in server response\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" The input '{{{{7*7}}}}' was rendered as '49' in the response body, "
"confirming server-side template evaluation.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n\n"
"Template expression rendered as literal text (not evaluated). "
"No SSTI on {host} {endpoint}. Sandboxed template engine in use."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 6. Command Injection
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="command_injection",
vulnerable={
"easy": (
"[CRITICAL] OS Command Injection DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] OS command output detected in application response\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" Injected shell metacharacters produced unexpected output "
"consistent with command execution.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid input", "message": "The hostname contains invalid characters"}}\n\n'
"Shell metacharacters rejected on {host} {endpoint}. "
"Input validated against allowlist. No command execution observed."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 7. Insecure Direct Object Reference (IDOR)
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="idor",
vulnerable={
"easy": (
"[HIGH] Insecure Direct Object Reference (IDOR) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Unauthorized object access via parameter manipulation\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" Modifying the object identifier returned data belonging to a "
"different user/entity. No authorization check observed.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 403 Forbidden\n"
"Content-Type: application/json\n\n"
'{{"error": "Forbidden", "message": "You do not have permission to access this resource"}}\n\n'
"Object-level authorization enforced on {host} {endpoint}. "
"Attempts to access other users' resources returned 403."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 8. Path Traversal
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="path_traversal",
vulnerable={
"easy": (
"[HIGH] Path Traversal / Local File Inclusion DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Unexpected file content returned via path manipulation\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" Payload: {payload}\n"
" Response contained content consistent with a system file "
"(e.g., /etc/passwd format).\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid file path", "message": "Path traversal characters are not allowed"}}\n\n'
"Path traversal sequences stripped/rejected on {host} {endpoint}. "
"File access restricted to allowed directory."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 9. XML External Entity (XXE)
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="xxe",
vulnerable={
"easy": (
"[HIGH] XML External Entity Injection (XXE) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] XML parser resolved external entity\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" A DOCTYPE declaration with an external entity was processed. "
"The entity content appeared in the response body.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "XML parsing error", "message": "DOCTYPE declarations are not allowed"}}\n\n'
"External entity processing disabled on {host} {endpoint}. "
"DTD processing rejected by parser configuration."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 10. Broken Authentication
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="broken_auth",
vulnerable={
"easy": (
"[CRITICAL] Broken Authentication DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Authentication bypass confirmed\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Login was bypassed using SQL injection in the authentication query. "
"Session cookie set without valid credentials.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint}\n"
" Payload: {payload}\n"
" Response: HTTP {status_code}\n"
" Headers: Set-Cookie: session=eyJhbGciOiJIUzI1NiJ9...; Path=/; HttpOnly\n"
" Location: /dashboard\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 401 Unauthorized\n"
"Content-Type: application/json\n\n"
'{{"error": "Authentication failed", "message": "Invalid username or password"}}\n\n'
"Login endpoint on {host} {endpoint} correctly rejected invalid credentials. "
"Generic error message returned. No session created."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 11. Default Credentials
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="default_credentials",
vulnerable={
"easy": (
"[CRITICAL] Default Credentials DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Service: {service_version}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Service login accepted well-known default credentials\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Service: {service_version}\n"
" Login succeeded with a commonly known default username/password pair. "
"Administrative access was granted.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint}\n"
" Credentials tested: {payload}\n"
" Response: HTTP {status_code}\n"
" Headers: Set-Cookie: JSESSIONID=ABC123; Path=/\n"
" Location: /manager/html\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 401 Unauthorized\n"
"Content-Type: text/html\n\n"
"All tested default credential pairs were rejected on {host} {endpoint}. "
"Service {service_version} appears to have had its default password changed."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "service_version", "evidence_detail",
"remediation", "status_code", "response_body", "response_time",
],
))
# ===================================================================
# 12. Weak Credentials
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="weak_credentials",
vulnerable={
"easy": (
"[HIGH] Weak Credentials DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Service: {service_version}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Weak password accepted for user account\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Service: {service_version}\n"
" A commonly guessable password was accepted after minimal brute-force "
"attempts. No account lockout or rate limiting was observed.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint}\n"
" Attempt #{payload}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms\n"
" Note: No X-RateLimit-* headers. No CAPTCHA challenge. "
"No account lockout after 100+ failed attempts."
),
},
safe=(
"HTTP/1.1 401 Unauthorized\n"
"X-RateLimit-Remaining: 0\n"
"Retry-After: 300\n\n"
"Brute-force testing on {host} {endpoint} was rate-limited after 5 attempts. "
"Account lockout triggered. Strong password policy enforced."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "service_version", "evidence_detail",
"remediation", "status_code", "response_body", "response_time",
],
))
# ===================================================================
# 13. Weak TLS / Cryptographic Failures
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="weak_tls",
vulnerable={
"easy": (
"[MEDIUM] Weak TLS Configuration DETECTED\n"
" Host: {host}\n"
" Port: {port}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Deprecated TLS protocol and/or weak cipher suites offered\n"
" Host: {host}\n"
" Port: {port}\n"
" ssl-enum-ciphers results:\n"
" SSLv3: OFFERED (insecure)\n"
" TLSv1.0: OFFERED (deprecated)\n"
" TLSv1.1: OFFERED (deprecated)\n"
" TLSv1.2: offered\n"
" TLSv1.3: not offered\n"
" Weak ciphers: RC4, 3DES detected\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"PORT STATE SERVICE\n"
"{port}/tcp open https\n"
"| ssl-enum-ciphers:\n"
"| SSLv3:\n"
"| ciphers:\n"
"| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C\n"
"| TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C\n"
"| warnings:\n"
"| Broken cipher RC4 is deprecated by RFC 7465\n"
"| TLSv1.0:\n"
"| ciphers:\n"
"| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A\n"
"| TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C\n"
"| TLSv1.2:\n"
"| ciphers:\n"
"| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A\n"
"|_ least strength: C"
),
},
safe=(
"PORT STATE SERVICE\n"
"{port}/tcp open https\n"
"| ssl-enum-ciphers:\n"
"| TLSv1.2:\n"
"| ciphers:\n"
"| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A\n"
"| TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A\n"
"| TLSv1.3:\n"
"| ciphers:\n"
"| TLS_AES_256_GCM_SHA384 (ecdh_x25519) - A\n"
"|_ least strength: A\n\n"
"TLS configuration on {host}:{port} is strong. "
"Only TLS 1.2+ with AEAD ciphers offered. No deprecated protocols."
),
context_vars=[
"host", "port", "cvss", "cwe", "severity", "owasp",
"evidence_detail", "remediation",
],
))
# ===================================================================
# 14. Security Misconfiguration
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="security_misconfig",
vulnerable={
"easy": (
"[HIGH] Security Misconfiguration DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Insecure server configuration identified\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Findings:\n"
" - Missing security headers (HSTS, CSP, X-Frame-Options)\n"
" - Server version disclosed in headers\n"
" - Sensitive endpoint accessible without authentication\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"- Nikto v2.5.0\n"
"---------------------------------------------------------------------------\n"
"+ Target IP: {host}\n"
"+ Target Hostname: {host}\n"
"+ Target Port: {port}\n"
"---------------------------------------------------------------------------\n"
"+ Server: {service_version}\n"
"+ /: The anti-clickjacking X-Frame-Options header is not present.\n"
"+ /: The X-Content-Type-Options header is not set.\n"
"+ /: Uncommon header 'x-powered-by' found, with contents: PHP/7.4.3.\n"
"+ {endpoint}: {evidence_detail}\n"
"+ 8945 requests: 0 error(s) and 6 item(s) reported on remote host\n"
"---------------------------------------------------------------------------\n"
"+ 1 host(s) tested"
),
},
safe=(
"HTTP/1.1 200 OK\n"
"Strict-Transport-Security: max-age=63072000; includeSubDomains; preload\n"
"Content-Security-Policy: default-src 'self'\n"
"X-Content-Type-Options: nosniff\n"
"X-Frame-Options: DENY\n"
"Referrer-Policy: strict-origin-when-cross-origin\n\n"
"All required security headers present on {host}. "
"Server version hidden. Debug endpoints disabled. "
"No misconfiguration issues identified."
),
context_vars=[
"host", "endpoint", "port", "cvss", "cwe", "severity", "owasp",
"service_version", "evidence_detail", "remediation",
],
))
# ===================================================================
# 15. Vulnerable Component
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="vulnerable_component",
vulnerable={
"easy": (
"[CRITICAL] Vulnerable Component DETECTED\n"
" Host: {host}\n"
" Service: {service_version}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Outdated software version with known CVEs\n"
" Host: {host}\n"
" Service: {service_version}\n"
" The detected service version has publicly disclosed vulnerabilities "
"with available exploits.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"PORT STATE SERVICE VERSION\n"
"{port}/tcp open {service_version}\n"
"| vulners:\n"
"| {evidence_detail}\n"
"|\n"
"Nmap done: 1 IP address (1 host up) scanned in 12.45 seconds"
),
},
safe=(
"PORT STATE SERVICE VERSION\n"
"{port}/tcp open {service_version}\n"
"| vulners:\n"
"| No known vulnerabilities for this version\n"
"|\n"
"Component {service_version} on {host} is up to date. "
"No known CVEs found."
),
context_vars=[
"host", "port", "cvss", "cwe", "severity", "owasp",
"service_version", "evidence_detail", "remediation",
],
))
# ===================================================================
# 16. File Upload
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="file_upload",
vulnerable={
"easy": (
"[HIGH] Unrestricted File Upload DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Executable file uploaded and accessible on server\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" A PHP file was uploaded with a spoofed Content-Type (image/jpeg). "
"The file was stored in a web-accessible directory and executed "
"when accessed.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint}\n"
" Content-Type: multipart/form-data\n"
" Filename: shell.php.jpg | Content-Type (declared): image/jpeg\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms\n\n"
"GET /uploads/shell.php.jpg?cmd=id\n"
" Response: HTTP 200\n"
" Body: uid=33(www-data) gid=33(www-data) groups=33(www-data)"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid file type", "message": "Only .jpg, .png, '
'and .gif files are allowed"}}\n\n'
"File extension and magic bytes validated on {host} {endpoint}. "
"Uploaded files stored outside webroot with randomized names."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 17. Cross-Site Request Forgery (CSRF)
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="csrf",
vulnerable={
"easy": (
"[MEDIUM] Cross-Site Request Forgery (CSRF) DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] State-changing request accepted without CSRF token\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" A POST request to a state-changing endpoint succeeded without "
"any anti-CSRF token. The session cookie does not have the SameSite "
"attribute set.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint}\n"
" Origin: https://attacker.com\n"
" Referer: https://attacker.com/csrf-poc.html\n"
" Cookie: session=victim_session_abc123\n"
" Body: email=attacker@evil.com\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 403 Forbidden\n"
"Content-Type: application/json\n\n"
'{{"error": "CSRF token validation failed", "message": "Invalid or missing CSRF token"}}\n\n'
"Anti-CSRF token required and validated on {host} {endpoint}. "
"SameSite=Strict set on session cookies."
),
context_vars=[
"host", "endpoint", "parameter", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 18. Missing Rate Limiting
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="missing_rate_limiting",
vulnerable={
"easy": (
"[HIGH] Missing Rate Limiting DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] No rate limiting or account lockout on authentication endpoint\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Over 100 login attempts were processed without any blocking, "
"CAPTCHA challenge, or account lockout. No X-RateLimit-* headers observed.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"POST {endpoint} x500 (brute-force test)\n"
" Request #1: HTTP 401 | 143 bytes | 52ms\n"
" Request #100: HTTP 401 | 143 bytes | 48ms\n"
" Request #500: HTTP 401 | 143 bytes | 51ms\n"
" No 429 responses. No Retry-After header. "
"No X-RateLimit-* headers.\n"
" {evidence_detail}"
),
},
safe=(
"HTTP/1.1 429 Too Many Requests\n"
"Retry-After: 300\n"
"X-RateLimit-Limit: 5\n"
"X-RateLimit-Remaining: 0\n"
"Content-Type: application/json\n\n"
'{{"error": "Too many login attempts", "message": "Account temporarily locked. '
'Try again in 5 minutes."}}\n\n'
"Rate limiting enforced on {host} {endpoint} after 5 failed attempts. "
"Account lockout and exponential backoff observed."
),
context_vars=[
"host", "endpoint", "parameter", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
],
))
# ===================================================================
# 19. Email Security Misconfiguration
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="email_misconfig",
vulnerable={
"easy": (
"[MEDIUM] Email Security Misconfiguration DETECTED\n"
" Host: {host}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Missing or weak email authentication records\n"
" Host: {host}\n"
" DNS checks:\n"
" SPF: missing or overly permissive (+all)\n"
" DKIM: no DKIM record found\n"
" DMARC: no DMARC record found (or p=none)\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"dig TXT {host}\n"
" ;; ANSWER SECTION:\n"
" {host}. 300 IN TXT \"v=spf1 +all\"\n\n"
"dig TXT _dmarc.{host}\n"
" ;; ANSWER SECTION:\n"
" (empty - no DMARC record)\n\n"
"dig TXT default._domainkey.{host}\n"
" ;; ANSWER SECTION:\n"
" (empty - no DKIM record)"
),
},
safe=(
"dig TXT {host}\n"
" ;; ANSWER SECTION:\n"
" {host}. 300 IN TXT \"v=spf1 include:_spf.google.com -all\"\n\n"
"dig TXT _dmarc.{host}\n"
" ;; ANSWER SECTION:\n"
" _dmarc.{host}. 300 IN TXT \"v=DMARC1; p=reject; rua=mailto:dmarc@{host}\"\n\n"
"Email authentication properly configured on {host}. "
"SPF strict (-all), DKIM present, DMARC p=reject."
),
context_vars=[
"host", "cvss", "cwe", "severity", "owasp",
"evidence_detail", "remediation",
],
))
# ===================================================================
# 20. Sensitive Data Exposure
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="sensitive_data_exposure",
vulnerable={
"easy": (
"[HIGH] Sensitive Data Exposure DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Sensitive information disclosed in server response\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Sensitive data was found exposed, including credentials, API keys, "
"or internal configuration details in a publicly accessible location.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"GET {endpoint}\n"
" Response: HTTP {status_code}\n"
" Body (first 200 chars): {response_body}\n"
" Timing: {response_time}ms\n"
" Headers: Server: {service_version}\n"
" X-Powered-By: PHP/7.4.3"
),
},
safe=(
"HTTP/1.1 404 Not Found\n"
"Content-Type: application/json\n\n"
'{{"error": "Not Found"}}\n\n'
"No sensitive data exposed on {host} {endpoint}. "
"Debug endpoints disabled. Sensitive files (.env, .git) return 404. "
"Error responses use generic messages without stack traces."
),
context_vars=[
"host", "endpoint", "cvss", "cwe", "severity", "owasp",
"service_version", "evidence_detail", "remediation",
"status_code", "response_body", "response_time",
],
))
# ===================================================================
# 21. Insufficient Logging
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="insufficient_logging",
vulnerable={
"easy": (
"[MEDIUM] Insufficient Logging and Monitoring DETECTED\n"
" Host: {host}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Security events not adequately logged\n"
" Host: {host}\n"
" Multiple failed login attempts and suspicious activity did not "
"trigger any alerts or produce audit log entries. "
"No centralized logging infrastructure detected.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Tested: 50 failed logins, 10 SQL injection attempts, "
"5 path traversal attempts on {host}\n"
" Log review: /var/log/auth.log — no entries for web app events\n"
" Log review: /var/log/app/audit.log — file does not exist\n"
" SIEM integration: not detected\n"
" Alert triggers: none observed\n"
" {evidence_detail}"
),
},
safe=(
"Security logging verified on {host}:\n"
" - Failed login attempts logged with IP, timestamp, and user agent\n"
" - Suspicious requests trigger alerts via SIEM integration\n"
" - Audit trail covers authentication, authorization, and data access\n"
" - Log integrity protected (append-only, centralized)\n"
" Logging and monitoring adequate."
),
context_vars=[
"host", "cvss", "cwe", "severity", "owasp",
"evidence_detail", "remediation",
],
))
# ===================================================================
# 22. Open Redirect
# ===================================================================
_register(ResponseTemplate(
vuln_type_id="open_redirect",
vulnerable={
"easy": (
"[LOW] Open Redirect DETECTED\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" CWE: {cwe}\n"
" CVSS: {cvss}\n"
" OWASP: {owasp}\n"
" Payload: {payload}\n"
" Evidence: {evidence_detail}\n"
" Remediation: {remediation}"
),
"medium": (
"[!] Application redirects to user-controlled external URL\n"
" Host: {host}\n"
" Endpoint: {endpoint}\n"
" Parameter: {parameter}\n"
" The server issued a 302 redirect to an attacker-controlled domain "
"based on user input in the URL parameter.\n"
" {evidence_detail}\n"
" Assess the vulnerability type, severity, and impact."
),
"hard": (
"Parameter: {parameter} | Payload: {payload}\n"
" Response: HTTP 302 Found\n"
" Location: https://evil.com\n"
" Body: (empty)\n"
" Timing: {response_time}ms"
),
},
safe=(
"HTTP/1.1 400 Bad Request\n"
"Content-Type: application/json\n\n"
'{{"error": "Invalid redirect URL", "message": "Redirect to external domains is not allowed"}}\n\n'
"Redirect parameter validated on {host} {endpoint}. "
"Only relative paths and allowlisted domains accepted."
),
context_vars=[
"host", "endpoint", "parameter", "payload", "cvss", "cwe",
"severity", "owasp", "evidence_detail", "remediation",
"response_time",
],
))
# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------
def get_response_template(vuln_type_id: str) -> ResponseTemplate:
"""Return the ResponseTemplate for a given vulnerability type ID.
Raises KeyError if the vuln_type_id is not registered.
"""
if vuln_type_id not in _TEMPLATES:
raise KeyError(
f"Unknown vuln_type_id '{vuln_type_id}'. "
f"Available: {sorted(_TEMPLATES.keys())}"
)
return _TEMPLATES[vuln_type_id]
def get_all_response_templates() -> Dict[str, ResponseTemplate]:
"""Return a copy of the full template registry."""
return dict(_TEMPLATES)
def render_vulnerable(
vuln_type_id: str,
difficulty: str,
context: Dict[str, str],
) -> str:
"""Render the vulnerable-response template for a given difficulty tier.
Parameters
----------
vuln_type_id : str
Vulnerability type identifier (e.g. "sqli", "xss_stored").
difficulty : str
One of "easy", "medium", "hard".
context : dict
Template variables to fill in. Missing keys are replaced with
a placeholder so rendering never raises.
Returns
-------
str
The fully rendered template string.
"""
template = get_response_template(vuln_type_id)
if difficulty not in template.vulnerable:
raise ValueError(
f"Unknown difficulty '{difficulty}'. "
f"Expected one of: {sorted(template.vulnerable.keys())}"
)
raw = template.vulnerable[difficulty]
return _safe_format(raw, context)
def render_safe(
vuln_type_id: str,
context: Dict[str, str],
) -> str:
"""Render the safe / non-vulnerable response template.
Parameters
----------
vuln_type_id : str
Vulnerability type identifier.
context : dict
Template variables to fill in.
Returns
-------
str
The fully rendered safe-response string.
"""
template = get_response_template(vuln_type_id)
return _safe_format(template.safe, context)
# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------
class _DefaultDict(dict):
"""Dict subclass that returns a placeholder for missing keys."""
def __missing__(self, key: str) -> str:
return f"<{key}>"
def _safe_format(template: str, context: Dict[str, str]) -> str:
"""Format *template* with *context*, substituting placeholders for
any variables that are absent from *context*."""
safe_ctx = _DefaultDict(context)
return template.format_map(safe_ctx)