mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 13:44:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
150 lines
5.7 KiB
Python
150 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
# For authorized penetration testing and educational environments only.
|
|
# Usage against targets without prior mutual consent is illegal.
|
|
# It is the end user's responsibility to obey all applicable local, state and federal laws.
|
|
"""SSL stripping assessment agent using subprocess wrappers for bettercap and curl."""
|
|
|
|
import subprocess
|
|
import re
|
|
import json
|
|
import sys
|
|
|
|
|
|
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)
|