Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 11,467 Bytes
d543fc1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | """
http_method_tampering_scanner.py β HTTP Method Tampering Scanner
=================================================================
Tests all HTTP methods (TRACE, PUT, DELETE, PATCH, OPTIONS, CONNECT) on
discovered endpoints. TRACE enables XST, PUT can write files.
Also tests HTTP method override headers.
"""
from scanners.base_scanner import BaseScanner
DANGEROUS_METHODS = {
"TRACE": ("High", "Enables Cross-Site Tracing (XST) β reflects HTTP headers including cookies/auth tokens back to the client. Can be used to bypass HttpOnly cookie protection via JavaScript."),
"PUT": ("Critical","HTTP PUT on a web server may allow direct file upload, enabling Remote Code Execution (e.g., uploading a webshell)."),
"DELETE": ("High", "HTTP DELETE allowed. An attacker could delete files or resources if the web server maps it to the filesystem."),
"CONNECT": ("Medium", "CONNECT method may allow the server to be used as an HTTP proxy for SSRF or network pivoting."),
"PATCH": ("Medium", "HTTP PATCH allowed. May allow partial modification of server-side resources."),
"PROPFIND":("Medium", "WebDAV PROPFIND allowed. May leak file listings and metadata."),
"MOVE": ("High", "WebDAV MOVE allowed. An attacker can rename/move files on the server."),
"COPY": ("Medium", "WebDAV COPY allowed. An attacker can copy files on the server."),
"MKCOL": ("Medium", "WebDAV MKCOL allowed. An attacker can create directories on the server."),
}
# Curated list of HTTP method override header name variants used in real WAF bypass scenarios.
# Only valid HTTP header name chars (printable ASCII, no control chars) are used.
# Do NOT use waf_evade() here β it generates URL-encoded / control-char variants
# that urllib rejects as invalid header names.
OVERRIDE_HEADERS = [
# Standard override headers
"X-HTTP-Method-Override",
"X-HTTP-Method",
"X-Method-Override",
# Case variations (common WAF bypass)
"x-http-method-override",
"x-http-method",
"x-method-override",
"X-Http-Method-Override",
"X-Http-Method",
# Additional known override header aliases
"X-Forwarded-Method",
"X-Original-Method",
"X-Rewrite-Method",
"XHTTP-Method",
]
class HttpMethodTamperingScanner(BaseScanner):
SCANNER_NAME = "HTTP Method Tampering Scanner"
_SCANNER_KEY = "http_method_tampering"
def __init__(self, scan_id, target, domain, **kwargs):
super().__init__(scan_id, target, domain, **kwargs)
def run(self) -> list:
self.log("INFO", f"[HTTPMethod] Testing dangerous HTTP methods on {self.target}...")
advertised = self._get_options_methods()
if advertised:
self.log("INFO", f"[HTTPMethod] OPTIONS Allow header: {advertised}")
for method, (severity, description) in DANGEROUS_METHODS.items():
status, headers, body = self._send_method(method, self.target)
if status and status not in (405, 501, 400, 0):
cwe = ["CWE-749"]
owasp = "A05:2021 β Security Misconfiguration"
if method == "TRACE" and body and "TRACE" in body.upper():
self.add_vuln(
title="TRACE Method Enabled β Cross-Site Tracing (XST) Risk",
severity=severity,
category="HTTP Method Tampering",
cvss_score=7.4,
description=f"The server responded to a TRACE request with HTTP {status} "
f"and reflected the request body back. {description}",
remediation="Disable TRACE globally: Apache: `TraceEnable Off` | "
"Nginx: `map $request_method $block {{ TRACE 1; }} if ($block) {{ return 405; }}`",
evidence=f"TRACE request reflected body, status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
elif method == "PUT":
self.add_vuln(
title="HTTP PUT Method Accepted",
severity=severity,
category="HTTP Method Tampering",
cvss_score=9.1,
description=f"Server responded HTTP {status} to a PUT request. {description}",
remediation="Disable PUT in web server config unless explicitly required by the API. "
"If required, restrict to authenticated endpoints only.",
evidence=f"PUT request accepted with status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
elif method == "DELETE":
self.add_vuln(
title="HTTP DELETE Method Accepted",
severity=severity,
category="HTTP Method Tampering",
cvss_score=7.5,
description=f"Server responded HTTP {status} to a DELETE request. {description}",
remediation="Restrict DELETE to authenticated, authorized API routes. "
"Disable WebDAV if not needed.",
evidence=f"DELETE request accepted with status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
elif method == "CONNECT":
self.add_vuln(
title="HTTP CONNECT Method Accepted",
severity=severity,
category="HTTP Method Tampering",
cvss_score=5.3,
description=f"Server responded HTTP {status} to CONNECT. {description}",
remediation="Block CONNECT at the web server level unless operating a proxy.",
evidence=f"CONNECT request accepted with status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
elif method == "PATCH":
self.add_vuln(
title="HTTP PATCH Method Accepted",
severity=severity,
category="HTTP Method Tampering",
cvss_score=5.3,
description=f"Server responded HTTP {status} to a PATCH request. {description}",
remediation="Restrict PATCH to authenticated API routes with proper input validation.",
evidence=f"PATCH request accepted with status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
elif method in ("PROPFIND", "MOVE", "COPY", "MKCOL"):
self.add_vuln(
title=f"HTTP {method} Method Accepted (WebDAV)",
severity=severity,
category="HTTP Method Tampering",
cvss_score=6.5 if method == "MOVE" else 5.3,
description=f"Server responded HTTP {status} to {method}. {description}",
remediation="Disable WebDAV methods unless explicitly required. "
"Restrict to authenticated API routes with proper input validation.",
evidence=f"{method} request accepted with status {status}",
confidence="Confirmed",
cwe_ids=cwe,
owasp_category=owasp,
)
self.log("WARNING", f"[HTTPMethod] {method} β HTTP {status}")
if advertised and any(m in advertised for m in ["TRACE", "PUT", "DELETE"]):
self.add_vuln(
title="Dangerous Methods Advertised in OPTIONS Response",
severity="Medium",
category="HTTP Method Tampering",
cvss_score=5.3,
description=f"OPTIONS Allow header reveals: `{advertised}`. Dangerous methods are publicly advertised.",
remediation="Filter the Allow header to only expose methods actually required.",
evidence=f"Allow header: {advertised}",
confidence="Confirmed",
cwe_ids=["CWE-749"],
owasp_category="A05:2021 β Security Misconfiguration",
)
self._test_method_override_headers()
if not self.vulns:
self.log("SUCCESS", "[HTTPMethod] No dangerous HTTP methods accepted.")
return self.vulns
def _get_options_methods(self):
body, status, headers = self._make_request(
self.target, method="OPTIONS", return_response_obj=True
)
if status == 0:
return ""
if isinstance(headers, dict):
return headers.get("Allow", headers.get("allow", ""))
return getattr(headers, "get", lambda x, y="": y)("Allow", "")
def _send_method(self, method, url):
data = b"WSS-probe" if method in ("PUT", "PATCH") else None
body, status, headers = self._make_request(
url, method=method, data=data, return_response_obj=True
)
return status, headers if isinstance(headers, dict) else {}, body or ""
def _test_method_override_headers(self):
for header_name in OVERRIDE_HEADERS:
for override_method in ["PUT", "DELETE", "PATCH", "TRACE"]:
body, status = self._make_request(
self.target,
method="POST",
data=b"WSS-override-test",
headers={"Content-Type": "application/x-www-form-urlencoded", header_name: override_method}
)
if status and status not in (405, 501, 400, 404, 0):
self.add_vuln(
title=f"HTTP Method Override via `{header_name}` β {override_method}",
severity="Medium",
category="HTTP Method Tampering",
cvss_score=6.1,
description=f"Server accepted `{override_method}` via `{header_name}: {override_method}` header. "
f"Response status: {status}. HTTP method override headers can bypass access controls "
f"that only check the HTTP method.",
remediation="Disable HTTP method override headers at the reverse proxy "
"unless explicitly required. Validate the actual HTTP method, not the override header.",
evidence=f"{header_name}: {override_method} β HTTP {status}",
confidence="High",
cwe_ids=["CWE-749"],
owasp_category="A05:2021 β Security Misconfiguration",
)
|