mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-11 12:53:19 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
External Network Penetration Test — Automation Process
|
||||
|
||||
Automates reconnaissance, scanning, and reporting phases of an external
|
||||
network penetration test. Requires: nmap, subfinder, nuclei, python-nmap.
|
||||
|
||||
Usage:
|
||||
python process.py --target target.com --ip-range 203.0.113.0/24 --output ./results
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import socket
|
||||
import ssl
|
||||
import datetime
|
||||
import ipaddress
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def run_command(cmd: list[str], timeout: int = 300) -> tuple[str, str, int]:
|
||||
"""Execute a shell command and return stdout, stderr, return code."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout
|
||||
)
|
||||
return result.stdout, result.stderr, result.returncode
|
||||
except subprocess.TimeoutExpired:
|
||||
return "", f"Command timed out after {timeout}s", -1
|
||||
except FileNotFoundError:
|
||||
return "", f"Command not found: {cmd[0]}", -1
|
||||
|
||||
|
||||
def enumerate_subdomains(domain: str, output_dir: Path) -> list[str]:
|
||||
"""Enumerate subdomains using subfinder."""
|
||||
print(f"[*] Enumerating subdomains for {domain}...")
|
||||
subfinder_out = output_dir / "subdomains_subfinder.txt"
|
||||
|
||||
stdout, stderr, rc = run_command(
|
||||
["subfinder", "-d", domain, "-silent", "-o", str(subfinder_out)],
|
||||
timeout=600
|
||||
)
|
||||
|
||||
subdomains = set()
|
||||
if subfinder_out.exists():
|
||||
with open(subfinder_out) as f:
|
||||
subdomains.update(line.strip() for line in f if line.strip())
|
||||
|
||||
print(f"[+] Found {len(subdomains)} subdomains")
|
||||
return sorted(subdomains)
|
||||
|
||||
|
||||
def resolve_domains(subdomains: list[str], output_dir: Path) -> dict[str, list[str]]:
|
||||
"""Resolve subdomains to IP addresses."""
|
||||
print(f"[*] Resolving {len(subdomains)} subdomains...")
|
||||
resolved = {}
|
||||
for sub in subdomains:
|
||||
try:
|
||||
ips = [r[4][0] for r in socket.getaddrinfo(sub, None, socket.AF_INET)]
|
||||
resolved[sub] = list(set(ips))
|
||||
except socket.gaierror:
|
||||
continue
|
||||
|
||||
output_file = output_dir / "resolved_domains.json"
|
||||
with open(output_file, "w") as f:
|
||||
json.dump(resolved, f, indent=2)
|
||||
|
||||
unique_ips = set()
|
||||
for ips in resolved.values():
|
||||
unique_ips.update(ips)
|
||||
print(f"[+] Resolved to {len(unique_ips)} unique IPs")
|
||||
return resolved
|
||||
|
||||
|
||||
def nmap_scan(targets: str, output_dir: Path, scan_type: str = "quick") -> dict:
|
||||
"""Run nmap scan on target range."""
|
||||
print(f"[*] Running nmap {scan_type} scan on {targets}...")
|
||||
output_prefix = str(output_dir / f"nmap_{scan_type}")
|
||||
|
||||
if scan_type == "quick":
|
||||
cmd = ["nmap", "-sS", "-sV", "--top-ports", "1000", "-T4",
|
||||
"-oA", output_prefix, targets]
|
||||
elif scan_type == "full":
|
||||
cmd = ["nmap", "-sS", "-sV", "-p-", "-T4", "--min-rate", "1000",
|
||||
"-oA", output_prefix, targets]
|
||||
elif scan_type == "udp":
|
||||
cmd = ["nmap", "-sU", "--top-ports", "100", "-T4",
|
||||
"-oA", output_prefix, targets]
|
||||
elif scan_type == "scripts":
|
||||
cmd = ["nmap", "-sV", "-sC", "--script=vuln,exploit",
|
||||
"-oA", output_prefix, targets]
|
||||
else:
|
||||
cmd = ["nmap", "-sS", "-sV", "-T4",
|
||||
"-oA", output_prefix, targets]
|
||||
|
||||
stdout, stderr, rc = run_command(cmd, timeout=3600)
|
||||
|
||||
results = {
|
||||
"scan_type": scan_type,
|
||||
"targets": targets,
|
||||
"return_code": rc,
|
||||
"output_files": {
|
||||
"nmap": f"{output_prefix}.nmap",
|
||||
"xml": f"{output_prefix}.xml",
|
||||
"gnmap": f"{output_prefix}.gnmap",
|
||||
}
|
||||
}
|
||||
|
||||
if rc == 0:
|
||||
print(f"[+] Nmap {scan_type} scan completed successfully")
|
||||
else:
|
||||
print(f"[-] Nmap scan returned code {rc}: {stderr[:200]}")
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def check_ssl_tls(host: str, port: int = 443) -> dict:
|
||||
"""Check SSL/TLS configuration for a host."""
|
||||
result = {
|
||||
"host": host,
|
||||
"port": port,
|
||||
"ssl_version": None,
|
||||
"cipher": None,
|
||||
"cert_subject": None,
|
||||
"cert_issuer": None,
|
||||
"cert_expiry": None,
|
||||
"issues": []
|
||||
}
|
||||
|
||||
try:
|
||||
context = ssl.create_default_context()
|
||||
with socket.create_connection((host, port), timeout=10) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=host) as ssock:
|
||||
result["ssl_version"] = ssock.version()
|
||||
result["cipher"] = ssock.cipher()
|
||||
cert = ssock.getpeercert()
|
||||
if cert:
|
||||
result["cert_subject"] = dict(x[0] for x in cert.get("subject", []))
|
||||
result["cert_issuer"] = dict(x[0] for x in cert.get("issuer", []))
|
||||
result["cert_expiry"] = cert.get("notAfter")
|
||||
|
||||
# Check expiry
|
||||
expiry = datetime.datetime.strptime(
|
||||
cert["notAfter"], "%b %d %H:%M:%S %Y %Z"
|
||||
)
|
||||
if expiry < datetime.datetime.now():
|
||||
result["issues"].append("Certificate expired")
|
||||
elif expiry < datetime.datetime.now() + datetime.timedelta(days=30):
|
||||
result["issues"].append("Certificate expires within 30 days")
|
||||
|
||||
except ssl.SSLCertVerificationError as e:
|
||||
result["issues"].append(f"Certificate verification failed: {e}")
|
||||
except (socket.timeout, ConnectionRefusedError, OSError) as e:
|
||||
result["issues"].append(f"Connection failed: {e}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def run_nuclei_scan(targets_file: str, output_dir: Path) -> str:
|
||||
"""Run nuclei vulnerability scanner."""
|
||||
print("[*] Running nuclei vulnerability scan...")
|
||||
output_file = output_dir / "nuclei_results.json"
|
||||
|
||||
cmd = [
|
||||
"nuclei", "-l", targets_file,
|
||||
"-severity", "critical,high,medium",
|
||||
"-json", "-o", str(output_file),
|
||||
"-rate-limit", "50",
|
||||
"-bulk-size", "25",
|
||||
"-concurrency", "10"
|
||||
]
|
||||
|
||||
stdout, stderr, rc = run_command(cmd, timeout=3600)
|
||||
|
||||
if rc == 0:
|
||||
print(f"[+] Nuclei scan completed. Results: {output_file}")
|
||||
else:
|
||||
print(f"[-] Nuclei scan issue: {stderr[:200]}")
|
||||
|
||||
return str(output_file)
|
||||
|
||||
|
||||
def parse_nmap_gnmap(gnmap_file: str) -> list[dict]:
|
||||
"""Parse nmap gnmap output to extract open ports."""
|
||||
hosts = []
|
||||
try:
|
||||
with open(gnmap_file) as f:
|
||||
for line in f:
|
||||
if "Ports:" not in line:
|
||||
continue
|
||||
parts = line.split("\t")
|
||||
host_part = parts[0]
|
||||
ip = host_part.split(" ")[1]
|
||||
ports_part = [p for p in parts if p.startswith("Ports:")]
|
||||
if not ports_part:
|
||||
continue
|
||||
port_entries = ports_part[0].replace("Ports: ", "").split(", ")
|
||||
open_ports = []
|
||||
for entry in port_entries:
|
||||
fields = entry.strip().split("/")
|
||||
if len(fields) >= 5 and fields[1] == "open":
|
||||
open_ports.append({
|
||||
"port": int(fields[0]),
|
||||
"protocol": fields[2],
|
||||
"service": fields[4],
|
||||
"version": fields[6] if len(fields) > 6 else ""
|
||||
})
|
||||
if open_ports:
|
||||
hosts.append({"ip": ip, "open_ports": open_ports})
|
||||
except FileNotFoundError:
|
||||
print(f"[-] File not found: {gnmap_file}")
|
||||
|
||||
return hosts
|
||||
|
||||
|
||||
def generate_report(
|
||||
scan_results: dict,
|
||||
resolved: dict,
|
||||
ssl_results: list[dict],
|
||||
output_dir: Path
|
||||
) -> str:
|
||||
"""Generate a summary report in markdown format."""
|
||||
print("[*] Generating report...")
|
||||
report_file = output_dir / "pentest_report.md"
|
||||
timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
|
||||
|
||||
with open(report_file, "w") as f:
|
||||
f.write(f"# External Network Penetration Test Report\n\n")
|
||||
f.write(f"**Generated:** {timestamp}\n\n")
|
||||
f.write("---\n\n")
|
||||
|
||||
# Subdomain summary
|
||||
f.write("## Subdomain Enumeration\n\n")
|
||||
f.write(f"Total subdomains discovered: **{len(resolved)}**\n\n")
|
||||
unique_ips = set()
|
||||
for ips in resolved.values():
|
||||
unique_ips.update(ips)
|
||||
f.write(f"Unique IP addresses: **{len(unique_ips)}**\n\n")
|
||||
|
||||
if resolved:
|
||||
f.write("| Subdomain | IP Address(es) |\n")
|
||||
f.write("|-----------|---------------|\n")
|
||||
for sub, ips in sorted(resolved.items()):
|
||||
f.write(f"| {sub} | {', '.join(ips)} |\n")
|
||||
f.write("\n")
|
||||
|
||||
# Port scan summary
|
||||
f.write("## Port Scan Results\n\n")
|
||||
for scan_type, result in scan_results.items():
|
||||
f.write(f"### {scan_type.title()} Scan\n\n")
|
||||
gnmap = result.get("output_files", {}).get("gnmap")
|
||||
if gnmap and os.path.exists(gnmap):
|
||||
hosts = parse_nmap_gnmap(gnmap)
|
||||
if hosts:
|
||||
for host in hosts:
|
||||
f.write(f"**{host['ip']}**\n\n")
|
||||
f.write("| Port | Protocol | Service | Version |\n")
|
||||
f.write("|------|----------|---------|----------|\n")
|
||||
for port in host["open_ports"]:
|
||||
f.write(
|
||||
f"| {port['port']} | {port['protocol']} "
|
||||
f"| {port['service']} | {port['version']} |\n"
|
||||
)
|
||||
f.write("\n")
|
||||
else:
|
||||
f.write("No open ports discovered in this scan.\n\n")
|
||||
else:
|
||||
f.write(f"Scan output not available (return code: {result.get('return_code')})\n\n")
|
||||
|
||||
# SSL/TLS results
|
||||
f.write("## SSL/TLS Assessment\n\n")
|
||||
if ssl_results:
|
||||
f.write("| Host | SSL Version | Cipher | Expiry | Issues |\n")
|
||||
f.write("|------|-------------|--------|--------|--------|\n")
|
||||
for sr in ssl_results:
|
||||
issues = "; ".join(sr["issues"]) if sr["issues"] else "None"
|
||||
f.write(
|
||||
f"| {sr['host']} | {sr.get('ssl_version', 'N/A')} "
|
||||
f"| {sr.get('cipher', ('N/A',))[0] if sr.get('cipher') else 'N/A'} "
|
||||
f"| {sr.get('cert_expiry', 'N/A')} | {issues} |\n"
|
||||
)
|
||||
f.write("\n")
|
||||
|
||||
# Recommendations
|
||||
f.write("## Recommendations\n\n")
|
||||
f.write("1. Remediate all critical and high severity findings within 48 hours\n")
|
||||
f.write("2. Patch all identified CVEs on internet-facing services\n")
|
||||
f.write("3. Implement network segmentation for exposed services\n")
|
||||
f.write("4. Enable MFA on all externally accessible portals\n")
|
||||
f.write("5. Deploy WAF for web-facing applications\n")
|
||||
f.write("6. Review and harden TLS configurations\n")
|
||||
f.write("7. Remove unnecessary open ports and services\n")
|
||||
f.write("8. Implement rate limiting and account lockout policies\n\n")
|
||||
|
||||
f.write("---\n")
|
||||
f.write(f"*Report generated by external pentest automation tool*\n")
|
||||
|
||||
print(f"[+] Report generated: {report_file}")
|
||||
return str(report_file)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="External Network Penetration Test Automation"
|
||||
)
|
||||
parser.add_argument("--target", required=True, help="Target domain (e.g., target.com)")
|
||||
parser.add_argument("--ip-range", help="Target IP range in CIDR notation")
|
||||
parser.add_argument("--output", default="./results", help="Output directory")
|
||||
parser.add_argument("--skip-recon", action="store_true", help="Skip reconnaissance phase")
|
||||
parser.add_argument("--skip-scan", action="store_true", help="Skip scanning phase")
|
||||
parser.add_argument("--scan-type", default="quick",
|
||||
choices=["quick", "full", "udp", "scripts"],
|
||||
help="Nmap scan type")
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = Path(args.output)
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
(output_dir / "evidence").mkdir(exist_ok=True)
|
||||
(output_dir / "scans").mkdir(exist_ok=True)
|
||||
|
||||
print("=" * 60)
|
||||
print(" External Network Penetration Test")
|
||||
print(f" Target: {args.target}")
|
||||
print(f" Output: {output_dir.absolute()}")
|
||||
print(f" Started: {datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}")
|
||||
print("=" * 60)
|
||||
|
||||
# Phase 1: Reconnaissance
|
||||
resolved = {}
|
||||
if not args.skip_recon:
|
||||
subdomains = enumerate_subdomains(args.target, output_dir)
|
||||
resolved = resolve_domains(subdomains, output_dir)
|
||||
else:
|
||||
print("[*] Skipping reconnaissance phase")
|
||||
|
||||
# Phase 2: Scanning
|
||||
scan_results = {}
|
||||
ssl_results = []
|
||||
if not args.skip_scan:
|
||||
scan_target = args.ip_range or args.target
|
||||
scan_results[args.scan_type] = nmap_scan(
|
||||
scan_target, output_dir / "scans", args.scan_type
|
||||
)
|
||||
|
||||
# SSL/TLS checks on discovered web services
|
||||
ssl_hosts = [args.target]
|
||||
if resolved:
|
||||
ssl_hosts.extend(list(resolved.keys())[:20])
|
||||
for host in ssl_hosts:
|
||||
ssl_result = check_ssl_tls(host)
|
||||
if ssl_result["ssl_version"] or ssl_result["issues"]:
|
||||
ssl_results.append(ssl_result)
|
||||
else:
|
||||
print("[*] Skipping scanning phase")
|
||||
|
||||
# Phase 3: Nuclei scan
|
||||
targets_file = output_dir / "targets.txt"
|
||||
with open(targets_file, "w") as f:
|
||||
f.write(f"https://{args.target}\n")
|
||||
for sub in resolved:
|
||||
f.write(f"https://{sub}\n")
|
||||
run_nuclei_scan(str(targets_file), output_dir)
|
||||
|
||||
# Phase 4: Report generation
|
||||
report_path = generate_report(scan_results, resolved, ssl_results, output_dir)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print(" Penetration Test Automation Complete")
|
||||
print(f" Report: {report_path}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user