mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 06:04: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
178 lines
5.9 KiB
Python
178 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
# For authorized testing in lab/CTF environments only
|
|
"""SMB vulnerability assessment agent using Impacket for enumeration and signing checks."""
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import sys
|
|
from datetime import datetime
|
|
from typing import List
|
|
|
|
try:
|
|
from impacket.smbconnection import SMBConnection
|
|
from impacket import smbconnection
|
|
except ImportError:
|
|
sys.exit("impacket is required: pip install impacket")
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def check_smb_port(target: str, port: int = 445, timeout: int = 5) -> bool:
|
|
"""Check if SMB port is open on the target."""
|
|
import socket
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.settimeout(timeout)
|
|
s.connect((target, port))
|
|
s.close()
|
|
return True
|
|
except (socket.timeout, ConnectionRefusedError, OSError):
|
|
return False
|
|
|
|
|
|
def enumerate_smb(target: str, username: str = "", password: str = "",
|
|
domain: str = "") -> dict:
|
|
"""Enumerate SMB service information on a target host."""
|
|
result = {
|
|
"target": target,
|
|
"port_open": check_smb_port(target),
|
|
"os_info": "",
|
|
"smb_version": "",
|
|
"signing_required": True,
|
|
"shares": [],
|
|
"error": None,
|
|
}
|
|
if not result["port_open"]:
|
|
result["error"] = "SMB port 445 not reachable"
|
|
return result
|
|
|
|
try:
|
|
smb = SMBConnection(target, target, sess_port=445, timeout=10)
|
|
smb.negotiateSession()
|
|
result["signing_required"] = smb.isSigningRequired()
|
|
result["smb_version"] = f"SMBv{smb.getDialect()}"
|
|
|
|
if username:
|
|
smb.login(username, password, domain)
|
|
result["os_info"] = smb.getServerOS()
|
|
shares = smb.listShares()
|
|
for share in shares:
|
|
share_name = share["shi1_netname"][:-1]
|
|
share_type = share["shi1_type"]
|
|
result["shares"].append({
|
|
"name": share_name,
|
|
"type": share_type,
|
|
"remark": share["shi1_remark"][:-1] if share["shi1_remark"] else "",
|
|
})
|
|
smb.logoff()
|
|
else:
|
|
try:
|
|
smb.login("", "")
|
|
result["null_session"] = True
|
|
shares = smb.listShares()
|
|
for share in shares:
|
|
result["shares"].append({"name": share["shi1_netname"][:-1]})
|
|
smb.logoff()
|
|
except Exception:
|
|
result["null_session"] = False
|
|
|
|
smb.close()
|
|
except Exception as exc:
|
|
result["error"] = str(exc)
|
|
logger.warning("SMB enum failed on %s: %s", target, exc)
|
|
|
|
return result
|
|
|
|
|
|
def scan_network(targets: List[str], username: str = "", password: str = "",
|
|
domain: str = "") -> List[dict]:
|
|
"""Scan multiple targets for SMB services."""
|
|
results = []
|
|
for target in targets:
|
|
logger.info("Scanning %s...", target)
|
|
info = enumerate_smb(target, username, password, domain)
|
|
results.append(info)
|
|
return results
|
|
|
|
|
|
def find_relay_targets(results: List[dict]) -> List[str]:
|
|
"""Identify hosts where SMB signing is not required (relay targets)."""
|
|
targets = [r["target"] for r in results if not r.get("signing_required", True) and r["port_open"]]
|
|
logger.info("Found %d SMB relay targets (signing disabled)", len(targets))
|
|
return targets
|
|
|
|
|
|
def check_null_sessions(results: List[dict]) -> List[str]:
|
|
"""Identify hosts accepting null SMB sessions."""
|
|
return [r["target"] for r in results if r.get("null_session")]
|
|
|
|
|
|
def generate_report(results: List[dict]) -> dict:
|
|
"""Generate SMB vulnerability assessment report."""
|
|
smb_hosts = [r for r in results if r["port_open"]]
|
|
relay_targets = find_relay_targets(results)
|
|
null_hosts = check_null_sessions(results)
|
|
|
|
findings = []
|
|
if relay_targets:
|
|
findings.append(
|
|
f"HIGH: {len(relay_targets)}/{len(smb_hosts)} hosts have SMB signing disabled"
|
|
)
|
|
if null_hosts:
|
|
findings.append(
|
|
f"MEDIUM: {len(null_hosts)} hosts accept null SMB sessions"
|
|
)
|
|
|
|
all_shares = []
|
|
for r in smb_hosts:
|
|
for s in r.get("shares", []):
|
|
all_shares.append({"host": r["target"], "share": s["name"]})
|
|
|
|
return {
|
|
"assessment_date": datetime.utcnow().isoformat(),
|
|
"total_targets_scanned": len(results),
|
|
"smb_hosts_found": len(smb_hosts),
|
|
"signing_disabled_hosts": relay_targets,
|
|
"null_session_hosts": null_hosts,
|
|
"accessible_shares": all_shares,
|
|
"findings": findings,
|
|
}
|
|
|
|
|
|
def expand_cidr(cidr: str) -> List[str]:
|
|
"""Expand a CIDR range to individual IPs (supports /24 and smaller)."""
|
|
import ipaddress
|
|
try:
|
|
network = ipaddress.ip_network(cidr, strict=False)
|
|
return [str(ip) for ip in network.hosts()]
|
|
except ValueError:
|
|
return [cidr]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="SMB Vulnerability Assessment Agent")
|
|
parser.add_argument("--targets", nargs="+", required=True, help="Target IPs or CIDR ranges")
|
|
parser.add_argument("--username", default="", help="Domain username")
|
|
parser.add_argument("--password", default="", help="Password")
|
|
parser.add_argument("--domain", default="", help="Domain name")
|
|
parser.add_argument("--output", default="smb_report.json")
|
|
args = parser.parse_args()
|
|
|
|
all_targets = []
|
|
for t in args.targets:
|
|
all_targets.extend(expand_cidr(t))
|
|
|
|
results = scan_network(all_targets, args.username, args.password, args.domain)
|
|
report = generate_report(results)
|
|
|
|
with open(args.output, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
logger.info("Report saved to %s", args.output)
|
|
print(json.dumps(report, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|