mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-13 22:03:20 +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,53 @@
|
||||
# API Reference: HTTP Request Smuggling Detection Agent
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| requests | >=2.28 | Architecture fingerprinting via HTTP headers |
|
||||
| socket/ssl | stdlib | Raw HTTP request construction for smuggling probes |
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash
|
||||
python scripts/agent.py --url https://target.example.com/ --output smuggling.json
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### `identify_architecture(url) -> dict`
|
||||
Sends a GET request and inspects `Server`, `Via`, `X-Served-By`, `CF-Ray` headers to identify proxy/CDN chain.
|
||||
|
||||
### `send_raw_request(host, port, request_bytes, use_ssl, timeout) -> tuple`
|
||||
Low-level socket send for crafting ambiguous HTTP requests. Returns `(response_bytes, elapsed_seconds, error)`.
|
||||
|
||||
### `test_clte_detection(host, port, use_ssl) -> dict`
|
||||
Sends a CL.TE probe with mismatched `Content-Length` and incomplete chunked body. A response delay >5s suggests vulnerability.
|
||||
|
||||
### `test_tecl_detection(host, port, use_ssl) -> dict`
|
||||
Sends a TE.CL probe. Back-end reading `Content-Length` receives extra data that becomes the next request prefix.
|
||||
|
||||
### `test_te_te_detection(host, port, use_ssl) -> dict`
|
||||
Tests 5 `Transfer-Encoding` header obfuscation variants to detect differential parsing.
|
||||
|
||||
### `run_assessment(url) -> dict`
|
||||
Orchestrates all tests and compiles results.
|
||||
|
||||
## Smuggling Types
|
||||
|
||||
| Type | Front-End Uses | Back-End Uses | Detection |
|
||||
|------|---------------|---------------|-----------|
|
||||
| CL.TE | Content-Length | Transfer-Encoding | Time delay on incomplete chunk |
|
||||
| TE.CL | Transfer-Encoding | Content-Length | Extra data becomes next request |
|
||||
| TE.TE | Transfer-Encoding | Transfer-Encoding | Obfuscated TE header parsed differently |
|
||||
|
||||
## Output Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "https://target.example.com/",
|
||||
"architecture": {"server": "nginx", "cdn": "Cloudflare"},
|
||||
"tests": {"CL.TE": {"likely_vulnerable": false}, ...},
|
||||
"summary": {"clte_vulnerable": false, "tecl_vulnerable": false}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
# For authorized testing in lab/CTF environments only
|
||||
"""HTTP request smuggling detection agent using raw socket and requests."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
import time
|
||||
from urllib.parse import urlparse
|
||||
from typing import Optional
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
sys.exit("requests is required: pip install requests")
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def identify_architecture(url: str) -> dict:
|
||||
"""Identify the front-end/back-end HTTP architecture from response headers."""
|
||||
resp = requests.get(url, timeout=10, allow_redirects=False)
|
||||
headers = dict(resp.headers)
|
||||
arch = {
|
||||
"url": url,
|
||||
"server": headers.get("Server", "unknown"),
|
||||
"via": headers.get("Via", ""),
|
||||
"x_served_by": headers.get("X-Served-By", ""),
|
||||
"x_cache": headers.get("X-Cache", ""),
|
||||
"cf_ray": headers.get("CF-Ray", ""),
|
||||
"http_version": f"HTTP/{resp.raw.version / 10:.1f}" if hasattr(resp.raw, "version") else "unknown",
|
||||
}
|
||||
if arch["cf_ray"]:
|
||||
arch["cdn"] = "Cloudflare"
|
||||
elif "cloudfront" in headers.get("X-Amz-Cf-Id", "").lower():
|
||||
arch["cdn"] = "AWS CloudFront"
|
||||
elif arch["x_cache"]:
|
||||
arch["cdn"] = "Varnish/CDN"
|
||||
logger.info("Architecture: server=%s, cdn=%s", arch["server"], arch.get("cdn", "none"))
|
||||
return arch
|
||||
|
||||
|
||||
def send_raw_request(host: str, port: int, request_bytes: bytes,
|
||||
use_ssl: bool = True, timeout: float = 10.0) -> tuple:
|
||||
"""Send a raw HTTP request and measure response time."""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(timeout)
|
||||
if use_ssl:
|
||||
context = ssl.create_default_context()
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
sock = context.wrap_socket(sock, server_hostname=host)
|
||||
start = time.time()
|
||||
try:
|
||||
sock.connect((host, port))
|
||||
sock.sendall(request_bytes)
|
||||
response = b""
|
||||
while True:
|
||||
try:
|
||||
chunk = sock.recv(4096)
|
||||
if not chunk:
|
||||
break
|
||||
response += chunk
|
||||
except socket.timeout:
|
||||
break
|
||||
except Exception as exc:
|
||||
elapsed = time.time() - start
|
||||
return b"", elapsed, str(exc)
|
||||
finally:
|
||||
sock.close()
|
||||
elapsed = time.time() - start
|
||||
return response, elapsed, None
|
||||
|
||||
|
||||
def test_clte_detection(host: str, port: int, use_ssl: bool = True) -> dict:
|
||||
"""Test for CL.TE smuggling via time-based detection."""
|
||||
probe = (
|
||||
f"POST / HTTP/1.1\r\n"
|
||||
f"Host: {host}\r\n"
|
||||
f"Content-Length: 4\r\n"
|
||||
f"Transfer-Encoding: chunked\r\n"
|
||||
f"\r\n"
|
||||
f"1\r\nA\r\nX"
|
||||
).encode()
|
||||
|
||||
response, elapsed, error = send_raw_request(host, port, probe, use_ssl, timeout=15)
|
||||
vulnerable = elapsed > 5.0 and not error
|
||||
result = {
|
||||
"test": "CL.TE",
|
||||
"response_time": round(elapsed, 2),
|
||||
"likely_vulnerable": vulnerable,
|
||||
"error": error,
|
||||
}
|
||||
logger.info("CL.TE test: %.2fs response (vulnerable=%s)", elapsed, vulnerable)
|
||||
return result
|
||||
|
||||
|
||||
def test_tecl_detection(host: str, port: int, use_ssl: bool = True) -> dict:
|
||||
"""Test for TE.CL smuggling via differential response."""
|
||||
probe = (
|
||||
f"POST / HTTP/1.1\r\n"
|
||||
f"Host: {host}\r\n"
|
||||
f"Content-Length: 6\r\n"
|
||||
f"Transfer-Encoding: chunked\r\n"
|
||||
f"\r\n"
|
||||
f"0\r\n\r\nX"
|
||||
).encode()
|
||||
|
||||
response, elapsed, error = send_raw_request(host, port, probe, use_ssl, timeout=15)
|
||||
status = ""
|
||||
if response:
|
||||
first_line = response.split(b"\r\n", 1)[0].decode(errors="ignore")
|
||||
status = first_line
|
||||
|
||||
vulnerable = elapsed > 5.0 and not error
|
||||
result = {
|
||||
"test": "TE.CL",
|
||||
"response_time": round(elapsed, 2),
|
||||
"response_status": status,
|
||||
"likely_vulnerable": vulnerable,
|
||||
"error": error,
|
||||
}
|
||||
logger.info("TE.CL test: %.2fs (vulnerable=%s)", elapsed, vulnerable)
|
||||
return result
|
||||
|
||||
|
||||
def test_te_te_detection(host: str, port: int, use_ssl: bool = True) -> dict:
|
||||
"""Test for TE.TE smuggling with obfuscated Transfer-Encoding headers."""
|
||||
obfuscations = [
|
||||
"Transfer-Encoding: xchunked",
|
||||
"Transfer-Encoding : chunked",
|
||||
"Transfer-Encoding: chunked\r\nTransfer-Encoding: x",
|
||||
"Transfer-Encoding:\tchunked",
|
||||
"X: x\r\nTransfer-Encoding: chunked",
|
||||
]
|
||||
results = []
|
||||
for obf in obfuscations:
|
||||
probe = (
|
||||
f"POST / HTTP/1.1\r\n"
|
||||
f"Host: {host}\r\n"
|
||||
f"Content-Length: 4\r\n"
|
||||
f"{obf}\r\n"
|
||||
f"\r\n"
|
||||
f"1\r\nA\r\nX"
|
||||
).encode()
|
||||
response, elapsed, error = send_raw_request(host, port, probe, use_ssl, timeout=10)
|
||||
results.append({
|
||||
"obfuscation": obf.replace("\r\n", " | "),
|
||||
"response_time": round(elapsed, 2),
|
||||
"suspicious": elapsed > 5.0,
|
||||
})
|
||||
return {"test": "TE.TE", "obfuscation_results": results}
|
||||
|
||||
|
||||
def run_assessment(url: str) -> dict:
|
||||
"""Run the full HTTP request smuggling assessment."""
|
||||
parsed = urlparse(url)
|
||||
host = parsed.hostname
|
||||
use_ssl = parsed.scheme == "https"
|
||||
port = parsed.port or (443 if use_ssl else 80)
|
||||
|
||||
arch = identify_architecture(url)
|
||||
clte = test_clte_detection(host, port, use_ssl)
|
||||
tecl = test_tecl_detection(host, port, use_ssl)
|
||||
tete = test_te_te_detection(host, port, use_ssl)
|
||||
|
||||
return {
|
||||
"target": url,
|
||||
"architecture": arch,
|
||||
"tests": {"CL.TE": clte, "TE.CL": tecl, "TE.TE": tete},
|
||||
"summary": {
|
||||
"clte_vulnerable": clte["likely_vulnerable"],
|
||||
"tecl_vulnerable": tecl["likely_vulnerable"],
|
||||
"any_suspicious": any(r["suspicious"] for r in tete["obfuscation_results"]),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="HTTP Request Smuggling Detection Agent")
|
||||
parser.add_argument("--url", required=True, help="Target URL")
|
||||
parser.add_argument("--output", default="smuggling_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = run_assessment(args.url)
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
logger.info("Report saved to %s", args.output)
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user