mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-08 03:20: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,147 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SSL stripping assessment agent using subprocess wrappers for bettercap and curl."""
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import json
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
|
||||
def check_hsts_header(target_url):
|
||||
"""Check HSTS header on a target URL using curl."""
|
||||
result = subprocess.run(
|
||||
["curl", "-sI", "--max-time", "10", target_url],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
headers = result.stdout
|
||||
hsts_match = re.search(
|
||||
r"strict-transport-security:\s*(.+)", headers, re.IGNORECASE
|
||||
)
|
||||
findings = {"url": target_url, "hsts_present": False, "details": {}}
|
||||
if hsts_match:
|
||||
hsts_value = hsts_match.group(1).strip()
|
||||
findings["hsts_present"] = True
|
||||
findings["details"]["raw"] = hsts_value
|
||||
max_age = re.search(r"max-age=(\d+)", hsts_value)
|
||||
if max_age:
|
||||
findings["details"]["max_age"] = int(max_age.group(1))
|
||||
findings["details"]["include_subdomains"] = "includesubdomains" in hsts_value.lower()
|
||||
findings["details"]["preload"] = "preload" in hsts_value.lower()
|
||||
return findings
|
||||
|
||||
|
||||
def check_hsts_preload(domain):
|
||||
"""Check if domain is in HSTS preload list via the hstspreload.org API."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["curl", "-s", f"https://hstspreload.org/api/v2/status?domain={domain}"],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
return {
|
||||
"domain": domain,
|
||||
"status": data.get("status", "unknown"),
|
||||
"preloaded": data.get("status") == "preloaded",
|
||||
}
|
||||
except (json.JSONDecodeError, subprocess.TimeoutExpired):
|
||||
return {"domain": domain, "status": "error", "preloaded": False}
|
||||
|
||||
|
||||
def check_redirect_chain(url):
|
||||
"""Follow HTTP redirects and check for HTTPS upgrade."""
|
||||
result = subprocess.run(
|
||||
["curl", "-sIL", "--max-time", "10", "-o", "/dev/null",
|
||||
"-w", "%{redirect_url}\\n%{url_effective}\\n%{scheme}", url],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
lines = result.stdout.strip().split("\n")
|
||||
return {
|
||||
"initial_url": url,
|
||||
"redirect_url": lines[0] if len(lines) > 0 else "",
|
||||
"final_url": lines[1] if len(lines) > 1 else "",
|
||||
"final_scheme": lines[2] if len(lines) > 2 else "",
|
||||
"upgrades_to_https": lines[2] == "HTTPS" if len(lines) > 2 else False,
|
||||
}
|
||||
|
||||
|
||||
def check_mixed_content(url):
|
||||
"""Fetch page and check for HTTP resources on an HTTPS page."""
|
||||
result = subprocess.run(
|
||||
["curl", "-s", "--max-time", "10", url],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
body = result.stdout
|
||||
http_refs = re.findall(r'(src|href|action)=["\']http://', body, re.IGNORECASE)
|
||||
return {
|
||||
"url": url,
|
||||
"mixed_content_found": len(http_refs) > 0,
|
||||
"http_reference_count": len(http_refs),
|
||||
}
|
||||
|
||||
|
||||
def check_security_headers(url):
|
||||
"""Check for key security headers that complement HSTS."""
|
||||
result = subprocess.run(
|
||||
["curl", "-sI", "--max-time", "10", url],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
headers_text = result.stdout.lower()
|
||||
checks = {
|
||||
"content-security-policy": "content-security-policy:" in headers_text,
|
||||
"x-content-type-options": "x-content-type-options:" in headers_text,
|
||||
"x-frame-options": "x-frame-options:" in headers_text,
|
||||
"upgrade-insecure-requests": "upgrade-insecure-requests" in headers_text,
|
||||
}
|
||||
return checks
|
||||
|
||||
|
||||
def run_assessment(targets):
|
||||
"""Run full SSL stripping assessment against a list of target domains."""
|
||||
results = []
|
||||
for target in targets:
|
||||
https_url = f"https://{target}"
|
||||
http_url = f"http://{target}"
|
||||
entry = {"target": target}
|
||||
entry["hsts"] = check_hsts_header(https_url)
|
||||
entry["preload"] = check_hsts_preload(target)
|
||||
entry["redirect"] = check_redirect_chain(http_url)
|
||||
entry["mixed_content"] = check_mixed_content(https_url)
|
||||
entry["security_headers"] = check_security_headers(https_url)
|
||||
vulnerable = (
|
||||
not entry["hsts"]["hsts_present"]
|
||||
or not entry["preload"]["preloaded"]
|
||||
or entry["mixed_content"]["mixed_content_found"]
|
||||
)
|
||||
entry["ssl_strip_risk"] = "HIGH" if not entry["hsts"]["hsts_present"] else (
|
||||
"MEDIUM" if not entry["preload"]["preloaded"] else "LOW"
|
||||
)
|
||||
results.append(entry)
|
||||
return results
|
||||
|
||||
|
||||
def print_report(results):
|
||||
print("SSL Stripping Assessment Report")
|
||||
print("=" * 50)
|
||||
for r in results:
|
||||
print(f"\nTarget: {r['target']}")
|
||||
print(f" HSTS Present: {r['hsts']['hsts_present']}")
|
||||
if r["hsts"]["hsts_present"]:
|
||||
d = r["hsts"]["details"]
|
||||
print(f" max-age: {d.get('max_age', 'N/A')}")
|
||||
print(f" subdomains: {d.get('include_subdomains', False)}")
|
||||
print(f" preload dir: {d.get('preload', False)}")
|
||||
print(f" Preload List: {r['preload']['status']}")
|
||||
print(f" HTTP->HTTPS: {r['redirect']['upgrades_to_https']}")
|
||||
print(f" Mixed Content: {r['mixed_content']['http_reference_count']} refs")
|
||||
print(f" SSL Strip Risk: {r['ssl_strip_risk']}")
|
||||
sh = r["security_headers"]
|
||||
missing = [h for h, v in sh.items() if not v]
|
||||
if missing:
|
||||
print(f" Missing Headers: {', '.join(missing)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
targets = sys.argv[1:] if len(sys.argv) > 1 else ["example.com"]
|
||||
results = run_assessment(targets)
|
||||
print_report(results)
|
||||
Reference in New Issue
Block a user