Add files via upload

This commit is contained in:
Joas A Santos
2026-01-19 19:21:57 -03:00
committed by GitHub
parent b966ba658a
commit 5a8a1fc0d7
57 changed files with 17928 additions and 0 deletions
@@ -0,0 +1,3 @@
from backend.core.vuln_engine.testers.base_tester import BaseTester
__all__ = ["BaseTester"]
+124
View File
@@ -0,0 +1,124 @@
"""
NeuroSploit v3 - Authentication Vulnerability Testers
Testers for Auth Bypass, JWT, Session Fixation
"""
import re
import base64
import json
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class AuthBypassTester(BaseTester):
"""Tester for Authentication Bypass"""
def __init__(self):
super().__init__()
self.name = "auth_bypass"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for authentication bypass"""
# Check for successful auth indicators after bypass payload
auth_success = [
"welcome", "dashboard", "logged in", "authenticated",
"success", "admin", "profile"
]
if response_status == 200:
body_lower = response_body.lower()
for indicator in auth_success:
if indicator in body_lower:
# Check if this was with a bypass payload
bypass_indicators = ["' or '1'='1", "admin'--", "' or 1=1"]
if any(bp in payload.lower() for bp in bypass_indicators):
return True, 0.8, f"Auth bypass possible: '{indicator}' found after injection"
# Check for redirect to authenticated area
location = response_headers.get("Location", "")
if response_status in [301, 302]:
if "dashboard" in location or "admin" in location or "home" in location:
return True, 0.7, f"Auth bypass: Redirect to {location}"
return False, 0.0, None
class JWTManipulationTester(BaseTester):
"""Tester for JWT Token Manipulation"""
def __init__(self):
super().__init__()
self.name = "jwt_manipulation"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for JWT manipulation vulnerabilities"""
# Check if manipulated JWT was accepted
if response_status == 200:
# Algorithm none attack
if '"alg":"none"' in payload or '"alg": "none"' in payload:
return True, 0.9, "JWT 'none' algorithm accepted"
# Check for elevated privileges response
elevated_indicators = ["admin", "administrator", "role.*admin"]
for pattern in elevated_indicators:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.8, "JWT manipulation: Elevated privileges detected"
# Check for JWT-specific errors
jwt_errors = [
r"invalid.*token", r"jwt.*expired", r"signature.*invalid",
r"token.*malformed", r"unauthorized"
]
for pattern in jwt_errors:
if re.search(pattern, response_body, re.IGNORECASE):
# Error means it's checking - note for further testing
return False, 0.0, None
return False, 0.0, None
class SessionFixationTester(BaseTester):
"""Tester for Session Fixation"""
def __init__(self):
super().__init__()
self.name = "session_fixation"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for session fixation vulnerability"""
# Check Set-Cookie header
set_cookie = response_headers.get("Set-Cookie", "")
# If session ID in URL was accepted
if "JSESSIONID=" in payload or "PHPSESSID=" in payload:
if response_status == 200:
# Check if session was NOT regenerated
if not set_cookie or "JSESSIONID" not in set_cookie:
return True, 0.7, "Session ID from URL accepted without regeneration"
# Check for session in URL
if re.search(r'[?&](?:session|sid|PHPSESSID|JSESSIONID)=', response_body):
return True, 0.6, "Session ID exposed in URL"
return False, 0.0, None
@@ -0,0 +1,130 @@
"""
NeuroSploit v3 - Authorization Vulnerability Testers
Testers for IDOR, BOLA, Privilege Escalation
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class IDORTester(BaseTester):
"""Tester for Insecure Direct Object Reference"""
def __init__(self):
super().__init__()
self.name = "idor"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for IDOR vulnerability"""
# Check if we got data for a different ID
if response_status == 200:
# Look for user data indicators
user_data_patterns = [
r'"user_?id"\s*:\s*\d+',
r'"email"\s*:\s*"[^"]+"',
r'"name"\s*:\s*"[^"]+"',
r'"account"\s*:',
r'"profile"\s*:'
]
for pattern in user_data_patterns:
if re.search(pattern, response_body, re.IGNORECASE):
# Check if ID in payload differs from context user
if "original_id" in context:
if context["original_id"] not in payload:
return True, 0.8, f"IDOR: Accessed different user's data"
# Generic data access check
if len(response_body) > 50:
return True, 0.6, "IDOR: Response contains data - verify authorization"
return False, 0.0, None
class BOLATester(BaseTester):
"""Tester for Broken Object Level Authorization"""
def __init__(self):
super().__init__()
self.name = "bola"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for BOLA in APIs"""
# BOLA in REST APIs
if response_status == 200:
# Check for successful data access
data_indicators = [
r'"data"\s*:\s*\{',
r'"items"\s*:\s*\[',
r'"result"\s*:\s*\{',
r'"id"\s*:\s*\d+'
]
for pattern in data_indicators:
if re.search(pattern, response_body):
return True, 0.7, "BOLA: API returned object data - verify authorization"
# Check for enumeration possibilities
if response_status in [200, 404]:
# Different status for valid vs invalid IDs indicates BOLA risk
return True, 0.5, "BOLA: Different responses for IDs - enumeration possible"
return False, 0.0, None
class PrivilegeEscalationTester(BaseTester):
"""Tester for Privilege Escalation"""
def __init__(self):
super().__init__()
self.name = "privilege_escalation"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for privilege escalation"""
if response_status == 200:
# Check for admin/elevated access indicators
elevated_access = [
r'"role"\s*:\s*"admin"',
r'"is_?admin"\s*:\s*true',
r'"admin"\s*:\s*true',
r'"privilege"\s*:\s*"(?:admin|root|superuser)"',
r'"permissions"\s*:\s*\[.*"admin".*\]'
]
for pattern in elevated_access:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.9, f"Privilege escalation: Elevated role in response"
# Check for admin functionality access
admin_functions = [
"user management", "delete user", "admin panel",
"system settings", "all users", "user list"
]
body_lower = response_body.lower()
for func in admin_functions:
if func in body_lower:
return True, 0.7, f"Privilege escalation: Admin functionality '{func}' accessible"
return False, 0.0, None
@@ -0,0 +1,107 @@
"""
NeuroSploit v3 - Base Vulnerability Tester
Base class for all vulnerability testers.
"""
from typing import Tuple, Dict, List, Optional, Any
from urllib.parse import urlparse, urlencode, parse_qs, urlunparse
class BaseTester:
"""Base class for vulnerability testers"""
def __init__(self):
self.name = "base"
def build_request(
self,
endpoint,
payload: str
) -> Tuple[str, Dict, Dict, Optional[str]]:
"""
Build a test request with the payload.
Returns:
Tuple of (url, params, headers, body)
"""
url = endpoint.url
params = {}
headers = {"User-Agent": "NeuroSploit/3.0"}
body = None
# Inject payload into parameters if endpoint has them
if endpoint.parameters:
for param in endpoint.parameters:
param_name = param.get("name", param) if isinstance(param, dict) else param
params[param_name] = payload
else:
# Try to inject into URL query string
parsed = urlparse(url)
if parsed.query:
query_params = parse_qs(parsed.query)
for key in query_params:
query_params[key] = [payload]
new_query = urlencode(query_params, doseq=True)
url = urlunparse(parsed._replace(query=new_query))
else:
# Add as query parameter
params["test"] = payload
return url, params, headers, body
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""
Analyze response to determine if vulnerable.
Returns:
Tuple of (is_vulnerable, confidence, evidence)
"""
return False, 0.0, None
def check_timeout_vulnerability(self, vuln_type: str) -> bool:
"""Check if timeout indicates vulnerability for this type"""
return False
def get_injection_points(self, endpoint) -> List[Dict]:
"""Get all injection points for an endpoint"""
points = []
# URL parameters
if endpoint.parameters:
for param in endpoint.parameters:
param_name = param.get("name", param) if isinstance(param, dict) else param
points.append({
"type": "parameter",
"name": param_name,
"location": "query"
})
# Parse URL for query params
parsed = urlparse(endpoint.url)
if parsed.query:
query_params = parse_qs(parsed.query)
for key in query_params:
if not any(p.get("name") == key for p in points):
points.append({
"type": "parameter",
"name": key,
"location": "query"
})
# Headers that might be injectable
injectable_headers = ["User-Agent", "Referer", "X-Forwarded-For", "Cookie"]
for header in injectable_headers:
points.append({
"type": "header",
"name": header,
"location": "header"
})
return points
@@ -0,0 +1,150 @@
"""
NeuroSploit v3 - Client-Side Vulnerability Testers
Testers for CORS, Clickjacking, Open Redirect
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class CORSTester(BaseTester):
"""Tester for CORS Misconfiguration"""
def __init__(self):
super().__init__()
self.name = "cors_misconfig"
def build_request(self, endpoint, payload: str) -> Tuple[str, Dict, Dict, Optional[str]]:
"""Build CORS test request with Origin header"""
headers = {
"User-Agent": "NeuroSploit/3.0",
"Origin": payload # payload is the test origin
}
return endpoint.url, {}, headers, None
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for CORS misconfiguration"""
acao = response_headers.get("Access-Control-Allow-Origin", "")
acac = response_headers.get("Access-Control-Allow-Credentials", "")
# Wildcard with credentials
if acao == "*" and acac.lower() == "true":
return True, 0.95, "CORS: Wildcard origin with credentials allowed"
# Origin reflection
if acao == payload:
if acac.lower() == "true":
return True, 0.9, f"CORS: Arbitrary origin '{payload}' reflected with credentials"
return True, 0.7, f"CORS: Arbitrary origin '{payload}' reflected"
# Wildcard (without credentials still risky)
if acao == "*":
return True, 0.5, "CORS: Wildcard origin allowed"
# Null origin accepted
if acao == "null":
return True, 0.8, "CORS: Null origin accepted"
return False, 0.0, None
class ClickjackingTester(BaseTester):
"""Tester for Clickjacking vulnerability"""
def __init__(self):
super().__init__()
self.name = "clickjacking"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for clickjacking protection"""
# Check X-Frame-Options
xfo = response_headers.get("X-Frame-Options", "").upper()
# Check CSP frame-ancestors
csp = response_headers.get("Content-Security-Policy", "")
has_frame_ancestors = "frame-ancestors" in csp.lower()
if not xfo and not has_frame_ancestors:
return True, 0.8, "Clickjacking: No X-Frame-Options or frame-ancestors CSP"
if xfo and xfo not in ["DENY", "SAMEORIGIN"]:
return True, 0.7, f"Clickjacking: Weak X-Frame-Options: {xfo}"
# Check for JS frame busting that can be bypassed
frame_busters = [
r"if\s*\(\s*top\s*[!=]=",
r"if\s*\(\s*self\s*[!=]=\s*top",
r"if\s*\(\s*parent\s*[!=]="
]
for pattern in frame_busters:
if re.search(pattern, response_body):
if not xfo and not has_frame_ancestors:
return True, 0.6, "Clickjacking: Only JS frame-busting (bypassable)"
return False, 0.0, None
class OpenRedirectTester(BaseTester):
"""Tester for Open Redirect vulnerability"""
def __init__(self):
super().__init__()
self.name = "open_redirect"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for open redirect"""
# Check redirect status and Location header
if response_status in [301, 302, 303, 307, 308]:
location = response_headers.get("Location", "")
# Check if our payload URL is in Location
if payload in location:
return True, 0.9, f"Open redirect: Redirecting to {location}"
# Check for partial match (domain)
if "evil.com" in payload and "evil.com" in location:
return True, 0.9, "Open redirect: External domain in redirect"
# Check for meta refresh redirect
meta_refresh = re.search(
r'<meta[^>]+http-equiv=["\']?refresh["\']?[^>]+content=["\']?\d+;\s*url=([^"\'>\s]+)',
response_body, re.IGNORECASE
)
if meta_refresh:
redirect_url = meta_refresh.group(1)
if payload in redirect_url:
return True, 0.8, f"Open redirect via meta refresh: {redirect_url}"
# Check for JavaScript redirect
js_redirects = [
rf'location\.href\s*=\s*["\']?{re.escape(payload)}',
rf'location\.assign\s*\(["\']?{re.escape(payload)}',
rf'location\.replace\s*\(["\']?{re.escape(payload)}'
]
for pattern in js_redirects:
if re.search(pattern, response_body):
return True, 0.7, "Open redirect via JavaScript"
return False, 0.0, None
@@ -0,0 +1,203 @@
"""
NeuroSploit v3 - File Access Vulnerability Testers
Testers for LFI, RFI, Path Traversal, XXE, File Upload
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class LFITester(BaseTester):
"""Tester for Local File Inclusion"""
def __init__(self):
super().__init__()
self.name = "lfi"
self.file_signatures = {
# Linux files
r"root:.*:0:0:": "/etc/passwd",
r"\[boot loader\]": "Windows boot.ini",
r"\[operating systems\]": "Windows boot.ini",
r"# /etc/hosts": "/etc/hosts",
r"localhost": "/etc/hosts",
r"\[global\]": "Samba config",
r"include.*php": "PHP config",
# Windows files
r"\[extensions\]": "Windows win.ini",
r"for 16-bit app support": "Windows system.ini",
}
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for LFI indicators"""
for pattern, file_name in self.file_signatures.items():
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.95, f"LFI confirmed: {file_name} content detected"
# Check for path in error messages
path_patterns = [
r"failed to open stream.*No such file",
r"include\(.*\): failed to open stream",
r"Warning.*file_get_contents",
r"fopen\(.*\): failed"
]
for pattern in path_patterns:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.6, "LFI indicator: File operation error with path"
return False, 0.0, None
class RFITester(BaseTester):
"""Tester for Remote File Inclusion"""
def __init__(self):
super().__init__()
self.name = "rfi"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for RFI indicators"""
# Check if our remote content was included
if "neurosploit_rfi_test" in response_body:
return True, 0.95, "RFI confirmed: Remote content executed"
# Check for URL-related errors
rfi_errors = [
r"failed to open stream: HTTP request failed",
r"allow_url_include",
r"URL file-access is disabled"
]
for pattern in rfi_errors:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.5, f"RFI indicator: {pattern}"
return False, 0.0, None
class PathTraversalTester(BaseTester):
"""Tester for Path Traversal"""
def __init__(self):
super().__init__()
self.name = "path_traversal"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for path traversal indicators"""
# Same as LFI essentially
file_contents = [
r"root:.*:0:0:",
r"\[boot loader\]",
r"# /etc/",
r"127\.0\.0\.1.*localhost"
]
for pattern in file_contents:
if re.search(pattern, response_body):
return True, 0.9, f"Path traversal successful: File content detected"
return False, 0.0, None
class XXETester(BaseTester):
"""Tester for XML External Entity Injection"""
def __init__(self):
super().__init__()
self.name = "xxe"
def build_request(self, endpoint, payload: str) -> Tuple[str, Dict, Dict, Optional[str]]:
"""Build XXE request with XML body"""
headers = {
"User-Agent": "NeuroSploit/3.0",
"Content-Type": "application/xml"
}
return endpoint.url, {}, headers, payload
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for XXE indicators"""
# File content indicators
xxe_indicators = [
r"root:.*:0:0:",
r"\[boot loader\]",
r"# /etc/hosts",
r"<!ENTITY",
]
for pattern in xxe_indicators:
if re.search(pattern, response_body):
return True, 0.9, f"XXE confirmed: External entity processed"
# Error indicators
xxe_errors = [
r"XML parsing error",
r"External entity",
r"DOCTYPE.*ENTITY",
r"libxml"
]
for pattern in xxe_errors:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.6, f"XXE indicator: XML error with entity reference"
return False, 0.0, None
class FileUploadTester(BaseTester):
"""Tester for Arbitrary File Upload"""
def __init__(self):
super().__init__()
self.name = "file_upload"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for file upload vulnerability indicators"""
# Check for successful upload indicators
if response_status in [200, 201]:
success_indicators = [
"uploaded successfully",
"file saved",
"upload complete",
'"success"\\s*:\\s*true',
'"status"\\s*:\\s*"ok"'
]
for pattern in success_indicators:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.7, "File uploaded successfully - verify execution"
# Check for path disclosure in response
if re.search(r'["\']?(?:path|url|file)["\']?\s*:\s*["\'][^"\']+\.(php|asp|jsp)', response_body, re.IGNORECASE):
return True, 0.8, "Executable file path returned - possible RCE"
return False, 0.0, None
@@ -0,0 +1,152 @@
"""
NeuroSploit v3 - Infrastructure Vulnerability Testers
Testers for Security Headers, SSL/TLS, HTTP Methods
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class SecurityHeadersTester(BaseTester):
"""Tester for Missing Security Headers"""
def __init__(self):
super().__init__()
self.name = "security_headers"
self.required_headers = {
"Strict-Transport-Security": "HSTS not configured",
"X-Content-Type-Options": "X-Content-Type-Options not set",
"X-Frame-Options": "X-Frame-Options not set",
"Content-Security-Policy": "CSP not configured",
"X-XSS-Protection": "X-XSS-Protection not set (legacy but still useful)",
"Referrer-Policy": "Referrer-Policy not configured"
}
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for missing security headers"""
missing = []
headers_lower = {k.lower(): v for k, v in response_headers.items()}
for header, message in self.required_headers.items():
if header.lower() not in headers_lower:
missing.append(message)
# Check for weak CSP
csp = headers_lower.get("content-security-policy", "")
if csp:
weak_csp = []
if "unsafe-inline" in csp:
weak_csp.append("unsafe-inline")
if "unsafe-eval" in csp:
weak_csp.append("unsafe-eval")
if "*" in csp:
weak_csp.append("wildcard sources")
if weak_csp:
missing.append(f"Weak CSP: {', '.join(weak_csp)}")
if missing:
confidence = min(0.3 + len(missing) * 0.1, 0.8)
return True, confidence, f"Missing/weak headers: {'; '.join(missing[:3])}"
return False, 0.0, None
class SSLTester(BaseTester):
"""Tester for SSL/TLS Issues"""
def __init__(self):
super().__init__()
self.name = "ssl_issues"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for SSL/TLS issues"""
issues = []
# Check HSTS
hsts = response_headers.get("Strict-Transport-Security", "")
if not hsts:
issues.append("HSTS not enabled")
else:
# Check HSTS max-age
max_age_match = re.search(r'max-age=(\d+)', hsts)
if max_age_match:
max_age = int(max_age_match.group(1))
if max_age < 31536000: # Less than 1 year
issues.append(f"HSTS max-age too short: {max_age}s")
if "includeSubDomains" not in hsts:
issues.append("HSTS missing includeSubDomains")
# Check for HTTP resources on HTTPS page
if "https://" in (context.get("url", "") or ""):
http_resources = re.findall(r'(?:src|href)=["\']http://[^"\']+', response_body)
if http_resources:
issues.append(f"Mixed content: {len(http_resources)} HTTP resources")
if issues:
return True, 0.6, f"SSL/TLS issues: {'; '.join(issues)}"
return False, 0.0, None
class HTTPMethodsTester(BaseTester):
"""Tester for Dangerous HTTP Methods"""
def __init__(self):
super().__init__()
self.name = "http_methods"
self.dangerous_methods = ["TRACE", "TRACK", "PUT", "DELETE", "CONNECT"]
def build_request(self, endpoint, payload: str) -> Tuple[str, Dict, Dict, Optional[str]]:
"""Build OPTIONS request to check allowed methods"""
headers = {
"User-Agent": "NeuroSploit/3.0"
}
# payload is the HTTP method to test
return endpoint.url, {}, headers, None
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for dangerous HTTP methods"""
# Check Allow header from OPTIONS response
allow = response_headers.get("Allow", "")
dangerous_found = []
for method in self.dangerous_methods:
if method in allow.upper():
dangerous_found.append(method)
# TRACE method enables XST attacks
if "TRACE" in dangerous_found or "TRACK" in dangerous_found:
return True, 0.7, f"Dangerous methods enabled: {', '.join(dangerous_found)} (XST risk)"
if dangerous_found:
return True, 0.5, f"Potentially dangerous methods: {', '.join(dangerous_found)}"
# Check if specific method test succeeded
if payload.upper() in self.dangerous_methods:
if response_status == 200:
return True, 0.6, f"{payload} method accepted"
return False, 0.0, None
@@ -0,0 +1,372 @@
"""
NeuroSploit v3 - Injection Vulnerability Testers
Testers for XSS, SQL Injection, Command Injection, SSTI, etc.
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class XSSReflectedTester(BaseTester):
"""Tester for Reflected XSS vulnerabilities"""
def __init__(self):
super().__init__()
self.name = "xss_reflected"
# Unique markers for detection
self.markers = [
"neurosploit",
"xsstest123",
"alert(1)"
]
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check if XSS payload is reflected in response"""
if response_status >= 400:
return False, 0.0, None
# Check if payload is reflected
if payload in response_body:
# Check if it's in a dangerous context
dangerous_patterns = [
rf'<script[^>]*>{re.escape(payload)}',
rf'on\w+\s*=\s*["\']?{re.escape(payload)}',
rf'javascript:\s*{re.escape(payload)}',
rf'<[^>]+{re.escape(payload)}[^>]*>',
]
for pattern in dangerous_patterns:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.9, f"XSS payload reflected in dangerous context: {pattern}"
# Payload reflected but possibly encoded
return True, 0.7, "XSS payload reflected in response"
# Check for partial reflection (script tags, etc.)
for marker in self.markers:
if marker in payload and marker in response_body:
return True, 0.6, f"XSS marker '{marker}' found in response"
return False, 0.0, None
class XSSStoredTester(BaseTester):
"""Tester for Stored XSS vulnerabilities"""
def __init__(self):
super().__init__()
self.name = "xss_stored"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for stored XSS - requires subsequent request verification"""
# For stored XSS, we need to check if data was stored
# This is a simplified check - full implementation would verify on retrieval
if response_status in [200, 201, 302]:
if "success" in response_body.lower() or "created" in response_body.lower():
return True, 0.5, "Data possibly stored - verify retrieval for stored XSS"
return False, 0.0, None
class XSSDomTester(BaseTester):
"""Tester for DOM-based XSS vulnerabilities"""
def __init__(self):
super().__init__()
self.name = "xss_dom"
self.dom_sinks = [
"innerHTML", "outerHTML", "document.write", "document.writeln",
"eval(", "setTimeout(", "setInterval(", "location.href",
"location.assign", "location.replace"
]
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for DOM XSS indicators"""
# Look for dangerous DOM sinks in JavaScript
for sink in self.dom_sinks:
pattern = rf'{sink}[^;]*(?:location|document\.URL|document\.referrer|window\.name)'
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.7, f"Potential DOM XSS sink found: {sink}"
# Check if URL parameters are used in JavaScript
if re.search(r'(?:location\.search|location\.hash|document\.URL)', response_body):
if any(sink in response_body for sink in self.dom_sinks):
return True, 0.6, "URL input flows to DOM sink"
return False, 0.0, None
class SQLiErrorTester(BaseTester):
"""Tester for Error-based SQL Injection"""
def __init__(self):
super().__init__()
self.name = "sqli_error"
self.error_patterns = [
# MySQL
r"SQL syntax.*MySQL", r"Warning.*mysql_", r"MySQLSyntaxErrorException",
r"valid MySQL result", r"check the manual that corresponds to your MySQL",
# PostgreSQL
r"PostgreSQL.*ERROR", r"Warning.*pg_", r"valid PostgreSQL result",
r"Npgsql\.", r"PG::SyntaxError",
# SQL Server
r"Driver.*SQL[\-\_\ ]*Server", r"OLE DB.*SQL Server",
r"(\W|\A)SQL Server.*Driver", r"Warning.*mssql_",
r"(\W|\A)SQL Server.*[0-9a-fA-F]{8}", r"Microsoft SQL Native Client error",
# Oracle
r"\bORA-[0-9][0-9][0-9][0-9]", r"Oracle error", r"Oracle.*Driver",
r"Warning.*oci_", r"Warning.*ora_",
# SQLite
r"SQLite/JDBCDriver", r"SQLite\.Exception", r"System\.Data\.SQLite\.SQLiteException",
r"Warning.*sqlite_", r"Warning.*SQLite3::",
# Generic
r"SQL syntax.*", r"syntax error.*SQL", r"unclosed quotation mark",
r"quoted string not properly terminated"
]
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for SQL error messages in response"""
for pattern in self.error_patterns:
match = re.search(pattern, response_body, re.IGNORECASE)
if match:
return True, 0.9, f"SQL error detected: {match.group(0)[:100]}"
return False, 0.0, None
class SQLiUnionTester(BaseTester):
"""Tester for Union-based SQL Injection"""
def __init__(self):
super().__init__()
self.name = "sqli_union"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for union-based SQLi indicators"""
# Look for injected data markers
union_markers = ["neurosploit", "uniontest", "concat(", "version()"]
for marker in union_markers:
if marker in payload.lower() and marker in response_body.lower():
return True, 0.8, f"Union injection marker '{marker}' found in response"
# Check for database version strings
version_patterns = [
r"MySQL.*\d+\.\d+", r"PostgreSQL.*\d+\.\d+",
r"Microsoft SQL Server.*\d+", r"Oracle.*\d+",
r"\d+\.\d+\.\d+-MariaDB"
]
for pattern in version_patterns:
if re.search(pattern, response_body):
return True, 0.7, "Database version string found - possible union SQLi"
return False, 0.0, None
class SQLiBlindTester(BaseTester):
"""Tester for Boolean-based Blind SQL Injection"""
def __init__(self):
super().__init__()
self.name = "sqli_blind"
self.baseline_length = None
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for boolean-based blind SQLi"""
# This requires comparing responses - simplified check
response_length = len(response_body)
# Check for significant difference in response
if "baseline_length" in context:
diff = abs(response_length - context["baseline_length"])
if diff > 100: # Significant difference
return True, 0.6, f"Response length differs by {diff} bytes - possible blind SQLi"
# Check for conditional responses
if "1=1" in payload and response_status == 200:
return True, 0.5, "True condition returned 200 - possible blind SQLi"
return False, 0.0, None
class SQLiTimeTester(BaseTester):
"""Tester for Time-based Blind SQL Injection"""
def __init__(self):
super().__init__()
self.name = "sqli_time"
def check_timeout_vulnerability(self, vuln_type: str) -> bool:
"""Time-based SQLi is indicated by timeout"""
return True
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Time-based detection relies on timeout"""
# Response time analysis would be done in the engine
return False, 0.0, None
class CommandInjectionTester(BaseTester):
"""Tester for OS Command Injection"""
def __init__(self):
super().__init__()
self.name = "command_injection"
self.command_outputs = [
# Linux
r"root:.*:0:0:", r"bin:.*:1:1:", # /etc/passwd
r"uid=\d+.*gid=\d+", # id command
r"Linux.*\d+\.\d+\.\d+", # uname
r"total \d+.*drwx", # ls -la
# Windows
r"Volume Serial Number",
r"Directory of [A-Z]:\\",
r"Windows.*\[Version",
r"Microsoft Windows"
]
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for command execution evidence"""
for pattern in self.command_outputs:
match = re.search(pattern, response_body, re.IGNORECASE)
if match:
return True, 0.95, f"Command output detected: {match.group(0)[:100]}"
# Check for our marker
if "neurosploit" in payload and "neurosploit" in response_body:
return True, 0.8, "Command injection marker echoed"
return False, 0.0, None
class SSTITester(BaseTester):
"""Tester for Server-Side Template Injection"""
def __init__(self):
super().__init__()
self.name = "ssti"
# Mathematical expressions that prove code execution
self.math_results = {
"{{7*7}}": "49",
"${7*7}": "49",
"#{7*7}": "49",
"<%= 7*7 %>": "49",
"{{7*'7'}}": "7777777", # Jinja2
}
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for SSTI indicators"""
# Check mathematical results
for expr, result in self.math_results.items():
if expr in payload and result in response_body:
return True, 0.95, f"SSTI confirmed: {expr} = {result}"
# Check for template errors
template_errors = [
r"TemplateSyntaxError", r"Jinja2", r"Twig_Error",
r"freemarker\.core\.", r"velocity\.exception",
r"org\.apache\.velocity", r"Smarty"
]
for pattern in template_errors:
if re.search(pattern, response_body):
return True, 0.7, f"Template engine error: {pattern}"
return False, 0.0, None
class NoSQLInjectionTester(BaseTester):
"""Tester for NoSQL Injection"""
def __init__(self):
super().__init__()
self.name = "nosql_injection"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for NoSQL injection indicators"""
# MongoDB errors
nosql_errors = [
r"MongoError", r"MongoDB", r"bson",
r"\$where", r"\$gt", r"\$ne",
r"SyntaxError.*JSON"
]
for pattern in nosql_errors:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.7, f"NoSQL error indicator: {pattern}"
# Check for authentication bypass
if "$ne" in payload or "$gt" in payload:
if response_status == 200 and "success" in response_body.lower():
return True, 0.6, "Possible NoSQL authentication bypass"
return False, 0.0, None
@@ -0,0 +1,99 @@
"""
NeuroSploit v3 - Request Forgery Vulnerability Testers
Testers for SSRF and CSRF
"""
import re
from typing import Tuple, Dict, Optional
from backend.core.vuln_engine.testers.base_tester import BaseTester
class SSRFTester(BaseTester):
"""Tester for Server-Side Request Forgery"""
def __init__(self):
super().__init__()
self.name = "ssrf"
# Cloud metadata indicators
self.cloud_indicators = [
r"ami-[a-z0-9]+", # AWS AMI ID
r"instance-id",
r"iam/security-credentials",
r"compute/v1", # GCP
r"metadata/instance",
r"169\.254\.169\.254"
]
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for SSRF indicators"""
# Check for cloud metadata
for pattern in self.cloud_indicators:
if re.search(pattern, response_body, re.IGNORECASE):
return True, 0.95, f"SSRF to cloud metadata: {pattern}"
# Check for internal service indicators
internal_indicators = [
r"localhost",
r"127\.0\.0\.1",
r"192\.168\.\d+\.\d+",
r"10\.\d+\.\d+\.\d+",
r"172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+"
]
for pattern in internal_indicators:
if pattern in payload and re.search(pattern, response_body):
return True, 0.8, f"SSRF accessing internal resource: {pattern}"
# Check for different response when internal URL requested
if response_status == 200 and len(response_body) > 100:
if "169.254" in payload or "localhost" in payload or "127.0.0.1" in payload:
return True, 0.6, "Response received from internal URL - possible SSRF"
return False, 0.0, None
class CSRFTester(BaseTester):
"""Tester for Cross-Site Request Forgery"""
def __init__(self):
super().__init__()
self.name = "csrf"
def analyze_response(
self,
payload: str,
response_status: int,
response_headers: Dict,
response_body: str,
context: Dict
) -> Tuple[bool, float, Optional[str]]:
"""Check for CSRF vulnerability indicators"""
# Check for missing CSRF protections
csrf_protections = [
r'name=["\']?csrf',
r'name=["\']?_token',
r'name=["\']?authenticity_token',
r'X-CSRF-TOKEN',
r'X-XSRF-TOKEN'
]
has_protection = any(
re.search(pattern, response_body, re.IGNORECASE)
for pattern in csrf_protections
)
# Check SameSite cookie
has_samesite = "samesite" in str(response_headers).lower()
# State-changing request without protection
if not has_protection and not has_samesite:
if response_status in [200, 302]:
return True, 0.7, "No CSRF token found in form - possible CSRF"
return False, 0.0, None