208 lines
6.7 KiB
Python
208 lines
6.7 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
扫描结果 → 暴力破解 桥接工具
|
|||
|
|
================================
|
|||
|
|
从 01_扫描模块 的输出结果中提取 SSH 开放端口的 IP,
|
|||
|
|
生成暴力破解器可用的目标列表。
|
|||
|
|
|
|||
|
|
支持的输入格式:
|
|||
|
|
- 01_扫描模块 mumayi_full_scan.py 输出的 JSON
|
|||
|
|
- nmap XML 输出
|
|||
|
|
- masscan JSON 输出
|
|||
|
|
- 纯文本 IP 列表
|
|||
|
|
|
|||
|
|
用法:
|
|||
|
|
# 从扫描JSON导入
|
|||
|
|
python3 scan_to_brute.py --input ../01_扫描模块/results/scan_results.json --output targets.txt
|
|||
|
|
|
|||
|
|
# 从nmap XML导入
|
|||
|
|
python3 scan_to_brute.py --input scan.xml --format nmap --output targets.txt
|
|||
|
|
|
|||
|
|
# 从CSV导入(指定IP列和端口列)
|
|||
|
|
python3 scan_to_brute.py --input hosts.csv --format csv --ip-col ip --port-col port --output targets.txt
|
|||
|
|
|
|||
|
|
# 直接对接暴力破解
|
|||
|
|
python3 scan_to_brute.py --input scan.json --pipe | python3 ssh_bruter.py --targets /dev/stdin
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import csv
|
|||
|
|
import sys
|
|||
|
|
import argparse
|
|||
|
|
import xml.etree.ElementTree as ET
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# SSH 相关端口
|
|||
|
|
SSH_PORTS = {22, 2222, 22222, 10022, 20022, 222, 2022}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_from_json(filepath):
|
|||
|
|
"""从JSON扫描结果提取SSH目标"""
|
|||
|
|
targets = []
|
|||
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|||
|
|
data = json.load(f)
|
|||
|
|
|
|||
|
|
if isinstance(data, list):
|
|||
|
|
for item in data:
|
|||
|
|
ip = item.get("ip") or item.get("host") or item.get("address")
|
|||
|
|
if not ip:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# 查找SSH端口
|
|||
|
|
open_ports = item.get("open_ports") or item.get("ports") or []
|
|||
|
|
ssh_ports = []
|
|||
|
|
for p in open_ports:
|
|||
|
|
if isinstance(p, dict):
|
|||
|
|
port_num = p.get("port", 0)
|
|||
|
|
service = p.get("service", "").lower()
|
|||
|
|
if port_num in SSH_PORTS or "ssh" in service:
|
|||
|
|
ssh_ports.append(port_num)
|
|||
|
|
elif isinstance(p, int):
|
|||
|
|
if p in SSH_PORTS:
|
|||
|
|
ssh_ports.append(p)
|
|||
|
|
|
|||
|
|
if ssh_ports:
|
|||
|
|
for port in ssh_ports:
|
|||
|
|
targets.append(f"{ip}:{port}")
|
|||
|
|
# 如果没发现SSH端口但有该IP,默认加22
|
|||
|
|
elif item.get("ssh") or item.get("has_ssh"):
|
|||
|
|
targets.append(f"{ip}:22")
|
|||
|
|
|
|||
|
|
elif isinstance(data, dict):
|
|||
|
|
# 键值对格式 {ip: {ports: [...]}}
|
|||
|
|
for ip, info in data.items():
|
|||
|
|
if isinstance(info, dict):
|
|||
|
|
ports = info.get("ports") or info.get("open_ports") or []
|
|||
|
|
for p in ports:
|
|||
|
|
port_num = p if isinstance(p, int) else p.get("port", 0)
|
|||
|
|
if port_num in SSH_PORTS:
|
|||
|
|
targets.append(f"{ip}:{port_num}")
|
|||
|
|
|
|||
|
|
return targets
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_from_nmap_xml(filepath):
|
|||
|
|
"""从nmap XML输出提取SSH目标"""
|
|||
|
|
targets = []
|
|||
|
|
tree = ET.parse(filepath)
|
|||
|
|
root = tree.getroot()
|
|||
|
|
|
|||
|
|
for host in root.findall(".//host"):
|
|||
|
|
addr_elem = host.find("address[@addrtype='ipv4']")
|
|||
|
|
if addr_elem is None:
|
|||
|
|
continue
|
|||
|
|
ip = addr_elem.get("addr")
|
|||
|
|
|
|||
|
|
for port in host.findall(".//port"):
|
|||
|
|
portid = int(port.get("portid", 0))
|
|||
|
|
state = port.find("state")
|
|||
|
|
service = port.find("service")
|
|||
|
|
|
|||
|
|
if state is not None and state.get("state") == "open":
|
|||
|
|
svc_name = service.get("name", "") if service is not None else ""
|
|||
|
|
if portid in SSH_PORTS or "ssh" in svc_name.lower():
|
|||
|
|
targets.append(f"{ip}:{portid}")
|
|||
|
|
|
|||
|
|
return targets
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_from_masscan(filepath):
|
|||
|
|
"""从masscan JSON输出提取SSH目标"""
|
|||
|
|
targets = []
|
|||
|
|
with open(filepath, "r") as f:
|
|||
|
|
# masscan JSON格式可能不完全标准
|
|||
|
|
content = f.read().strip()
|
|||
|
|
if content.endswith(","):
|
|||
|
|
content = content[:-1]
|
|||
|
|
if not content.startswith("["):
|
|||
|
|
content = "[" + content + "]"
|
|||
|
|
data = json.loads(content)
|
|||
|
|
|
|||
|
|
for item in data:
|
|||
|
|
ip = item.get("ip")
|
|||
|
|
ports = item.get("ports", [])
|
|||
|
|
for p in ports:
|
|||
|
|
port_num = p.get("port", 0)
|
|||
|
|
if port_num in SSH_PORTS:
|
|||
|
|
targets.append(f"{ip}:{port_num}")
|
|||
|
|
|
|||
|
|
return targets
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_from_csv(filepath, ip_col="ip", port_col="port"):
|
|||
|
|
"""从CSV提取SSH目标"""
|
|||
|
|
targets = []
|
|||
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|||
|
|
reader = csv.DictReader(f)
|
|||
|
|
for row in reader:
|
|||
|
|
ip = row.get(ip_col, "").strip()
|
|||
|
|
port = row.get(port_col, "22").strip()
|
|||
|
|
if ip:
|
|||
|
|
port_num = int(port) if port.isdigit() else 22
|
|||
|
|
if port_num in SSH_PORTS:
|
|||
|
|
targets.append(f"{ip}:{port_num}")
|
|||
|
|
|
|||
|
|
return targets
|
|||
|
|
|
|||
|
|
|
|||
|
|
def extract_from_text(filepath):
|
|||
|
|
"""从纯文本提取(每行一个IP或IP:port)"""
|
|||
|
|
targets = []
|
|||
|
|
with open(filepath, "r") as f:
|
|||
|
|
for line in f:
|
|||
|
|
line = line.strip()
|
|||
|
|
if not line or line.startswith("#"):
|
|||
|
|
continue
|
|||
|
|
if ":" in line:
|
|||
|
|
targets.append(line)
|
|||
|
|
else:
|
|||
|
|
targets.append(f"{line}:22")
|
|||
|
|
return targets
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
parser = argparse.ArgumentParser(description="扫描结果转暴力破解目标列表")
|
|||
|
|
parser.add_argument("--input", "-i", required=True, help="输入文件路径")
|
|||
|
|
parser.add_argument("--format", "-f", choices=["json", "nmap", "masscan", "csv", "text"],
|
|||
|
|
default="json", help="输入格式 (默认 json)")
|
|||
|
|
parser.add_argument("--output", "-o", help="输出文件路径")
|
|||
|
|
parser.add_argument("--ip-col", default="ip", help="CSV中IP列名")
|
|||
|
|
parser.add_argument("--port-col", default="port", help="CSV中端口列名")
|
|||
|
|
parser.add_argument("--pipe", action="store_true", help="输出到stdout(管道模式)")
|
|||
|
|
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
# 提取目标
|
|||
|
|
fmt = args.format
|
|||
|
|
if fmt == "json":
|
|||
|
|
targets = extract_from_json(args.input)
|
|||
|
|
elif fmt == "nmap":
|
|||
|
|
targets = extract_from_nmap_xml(args.input)
|
|||
|
|
elif fmt == "masscan":
|
|||
|
|
targets = extract_from_masscan(args.input)
|
|||
|
|
elif fmt == "csv":
|
|||
|
|
targets = extract_from_csv(args.input, args.ip_col, args.port_col)
|
|||
|
|
elif fmt == "text":
|
|||
|
|
targets = extract_from_text(args.input)
|
|||
|
|
else:
|
|||
|
|
targets = extract_from_json(args.input)
|
|||
|
|
|
|||
|
|
# 去重
|
|||
|
|
targets = list(dict.fromkeys(targets))
|
|||
|
|
|
|||
|
|
print(f"[*] 提取到 {len(targets)} 个SSH目标", file=sys.stderr)
|
|||
|
|
|
|||
|
|
# 输出
|
|||
|
|
if args.pipe or not args.output:
|
|||
|
|
for t in targets:
|
|||
|
|
print(t)
|
|||
|
|
else:
|
|||
|
|
with open(args.output, "w") as f:
|
|||
|
|
for t in targets:
|
|||
|
|
f.write(t + "\n")
|
|||
|
|
print(f"[+] 已保存到 {args.output}", file=sys.stderr)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|