#!/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)