mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 13:44:56 +03:00
c21af3347e
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
264 lines
8.8 KiB
Python
264 lines
8.8 KiB
Python
#!/usr/bin/env python3
|
|
# For authorized testing only
|
|
"""API rate limiting bypass testing agent."""
|
|
|
|
import json
|
|
import sys
|
|
import argparse
|
|
import time
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import requests
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
|
|
BYPASS_HEADERS = [
|
|
{"X-Forwarded-For": "127.0.0.1"},
|
|
{"X-Forwarded-For": "10.0.0.1"},
|
|
{"X-Real-IP": "127.0.0.1"},
|
|
{"X-Originating-IP": "127.0.0.1"},
|
|
{"X-Client-IP": "192.168.1.1"},
|
|
{"X-Forwarded-Host": "localhost"},
|
|
{"True-Client-IP": "127.0.0.1"},
|
|
{"CF-Connecting-IP": "127.0.0.1"},
|
|
{"X-Custom-IP-Authorization": "127.0.0.1"},
|
|
{"Forwarded": "for=127.0.0.1"},
|
|
]
|
|
|
|
|
|
def detect_rate_limit_headers(url, auth_header=None):
|
|
"""Send initial request and extract rate limit response headers."""
|
|
headers = {"User-Agent": "RateLimit-Tester/1.0"}
|
|
if auth_header:
|
|
headers["Authorization"] = auth_header
|
|
try:
|
|
resp = requests.get(url, headers=headers, timeout=10)
|
|
rate_headers = {}
|
|
for key in resp.headers:
|
|
lower = key.lower()
|
|
if any(rl in lower for rl in ["ratelimit", "rate-limit", "x-rate",
|
|
"retry-after", "x-ratelimit"]):
|
|
rate_headers[key] = resp.headers[key]
|
|
return {
|
|
"url": url,
|
|
"status": resp.status_code,
|
|
"rate_limit_headers": rate_headers,
|
|
"has_rate_limiting": len(rate_headers) > 0,
|
|
}
|
|
except Exception as e:
|
|
return {"url": url, "error": str(e)}
|
|
|
|
|
|
def test_header_bypass(url, auth_header=None, request_count=30):
|
|
"""Test rate limit bypass via IP spoofing headers."""
|
|
findings = []
|
|
base_headers = {"User-Agent": "RateLimit-Tester/1.0"}
|
|
if auth_header:
|
|
base_headers["Authorization"] = auth_header
|
|
|
|
for i in range(request_count):
|
|
try:
|
|
resp = requests.get(url, headers=base_headers, timeout=5)
|
|
if resp.status_code == 429:
|
|
baseline_hit = i + 1
|
|
break
|
|
except Exception:
|
|
pass
|
|
else:
|
|
findings.append({
|
|
"test": "baseline",
|
|
"issue": f"No rate limit hit after {request_count} requests",
|
|
"severity": "HIGH",
|
|
})
|
|
return findings
|
|
|
|
for bypass in BYPASS_HEADERS:
|
|
test_headers = {**base_headers, **bypass}
|
|
header_name = list(bypass.keys())[0]
|
|
success_count = 0
|
|
for i in range(10):
|
|
bypass[header_name] = f"10.{i}.{i}.{i}"
|
|
test_headers = {**base_headers, **bypass}
|
|
try:
|
|
resp = requests.get(url, headers=test_headers, timeout=5)
|
|
if resp.status_code != 429:
|
|
success_count += 1
|
|
except Exception:
|
|
pass
|
|
|
|
if success_count > 5:
|
|
findings.append({
|
|
"test": "header_bypass",
|
|
"header": header_name,
|
|
"issue": f"Rate limit bypassed using {header_name} header ({success_count}/10 successful)",
|
|
"severity": "HIGH",
|
|
})
|
|
return findings
|
|
|
|
|
|
def test_method_bypass(url, auth_header=None):
|
|
"""Test if rate limiting applies across HTTP methods."""
|
|
methods = ["GET", "POST", "PUT", "PATCH", "HEAD", "OPTIONS"]
|
|
findings = []
|
|
headers = {"User-Agent": "RateLimit-Tester/1.0"}
|
|
if auth_header:
|
|
headers["Authorization"] = auth_header
|
|
|
|
method_results = {}
|
|
for method in methods:
|
|
try:
|
|
resp = requests.request(method, url, headers=headers, timeout=5)
|
|
method_results[method] = resp.status_code
|
|
except Exception:
|
|
method_results[method] = "error"
|
|
|
|
rate_limited = [m for m, s in method_results.items() if s == 429]
|
|
not_limited = [m for m, s in method_results.items() if isinstance(s, int) and s != 429]
|
|
|
|
if rate_limited and not_limited:
|
|
findings.append({
|
|
"test": "method_bypass",
|
|
"rate_limited": rate_limited,
|
|
"not_limited": not_limited,
|
|
"issue": f"Rate limit not applied to methods: {', '.join(not_limited)}",
|
|
"severity": "MEDIUM",
|
|
})
|
|
return findings
|
|
|
|
|
|
def test_path_bypass(url, auth_header=None):
|
|
"""Test rate limit bypass via URL path manipulation."""
|
|
from urllib.parse import urlparse
|
|
parsed = urlparse(url)
|
|
path = parsed.path
|
|
|
|
path_variations = [
|
|
path + "/",
|
|
path + "?",
|
|
path + "#",
|
|
path.upper(),
|
|
path + "%20",
|
|
path + ";",
|
|
path.replace("/", "//"),
|
|
path + "/.",
|
|
path + "/..",
|
|
]
|
|
|
|
findings = []
|
|
headers = {"User-Agent": "RateLimit-Tester/1.0"}
|
|
if auth_header:
|
|
headers["Authorization"] = auth_header
|
|
|
|
for variant in path_variations:
|
|
test_url = f"{parsed.scheme}://{parsed.netloc}{variant}"
|
|
try:
|
|
resp = requests.get(test_url, headers=headers, timeout=5, allow_redirects=False)
|
|
if resp.status_code not in (429, 404, 301, 302):
|
|
findings.append({
|
|
"test": "path_bypass",
|
|
"original": path,
|
|
"variant": variant,
|
|
"status": resp.status_code,
|
|
"issue": f"Path variation '{variant}' bypasses rate limit (status {resp.status_code})",
|
|
"severity": "MEDIUM",
|
|
})
|
|
except Exception:
|
|
pass
|
|
return findings
|
|
|
|
|
|
def test_encoding_bypass(url, auth_header=None):
|
|
"""Test rate limit bypass via parameter encoding variations."""
|
|
from urllib.parse import urlparse, parse_qs, urlencode
|
|
parsed = urlparse(url)
|
|
params = parse_qs(parsed.query)
|
|
findings = []
|
|
headers = {"User-Agent": "RateLimit-Tester/1.0"}
|
|
if auth_header:
|
|
headers["Authorization"] = auth_header
|
|
|
|
null_byte_url = url + "%00"
|
|
try:
|
|
resp = requests.get(null_byte_url, headers=headers, timeout=5)
|
|
if resp.status_code != 429:
|
|
findings.append({
|
|
"test": "null_byte_bypass",
|
|
"status": resp.status_code,
|
|
"issue": "Null byte appended bypasses rate limit",
|
|
"severity": "HIGH",
|
|
})
|
|
except Exception:
|
|
pass
|
|
|
|
return findings
|
|
|
|
|
|
def run_audit(args):
|
|
"""Execute API rate limiting bypass audit."""
|
|
print(f"\n{'='*60}")
|
|
print(f" API RATE LIMITING BYPASS TESTING")
|
|
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
|
|
print(f"{'='*60}\n")
|
|
|
|
report = {}
|
|
all_findings = []
|
|
|
|
detection = detect_rate_limit_headers(args.url, args.auth)
|
|
report["rate_limit_detection"] = detection
|
|
print(f"--- RATE LIMIT DETECTION ---")
|
|
print(f" URL: {detection.get('url','')}")
|
|
print(f" Has Rate Limiting: {detection.get('has_rate_limiting', False)}")
|
|
for k, v in detection.get("rate_limit_headers", {}).items():
|
|
print(f" {k}: {v}")
|
|
|
|
if args.test_headers:
|
|
header_findings = test_header_bypass(args.url, args.auth, args.request_count)
|
|
all_findings.extend(header_findings)
|
|
print(f"\n--- HEADER BYPASS ({len(header_findings)} findings) ---")
|
|
for f in header_findings:
|
|
print(f" [{f['severity']}] {f['issue']}")
|
|
|
|
if args.test_methods:
|
|
method_findings = test_method_bypass(args.url, args.auth)
|
|
all_findings.extend(method_findings)
|
|
print(f"\n--- METHOD BYPASS ({len(method_findings)} findings) ---")
|
|
for f in method_findings:
|
|
print(f" [{f['severity']}] {f['issue']}")
|
|
|
|
if args.test_paths:
|
|
path_findings = test_path_bypass(args.url, args.auth)
|
|
all_findings.extend(path_findings)
|
|
print(f"\n--- PATH BYPASS ({len(path_findings)} findings) ---")
|
|
for f in path_findings:
|
|
print(f" [{f['severity']}] {f['issue']}")
|
|
|
|
report["findings"] = all_findings
|
|
report["total_findings"] = len(all_findings)
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="API Rate Limiting Bypass Tester")
|
|
parser.add_argument("--url", required=True, help="Target API endpoint URL")
|
|
parser.add_argument("--auth", help="Authorization header value")
|
|
parser.add_argument("--request-count", type=int, default=30,
|
|
help="Requests for baseline detection (default: 30)")
|
|
parser.add_argument("--test-headers", action="store_true", help="Test header-based bypasses")
|
|
parser.add_argument("--test-methods", action="store_true", help="Test HTTP method bypasses")
|
|
parser.add_argument("--test-paths", action="store_true", help="Test URL path bypasses")
|
|
parser.add_argument("--output", help="Save report to JSON file")
|
|
args = parser.parse_args()
|
|
|
|
report = run_audit(args)
|
|
if args.output:
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2, default=str)
|
|
print(f"\n[+] Report saved to {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|