更新: 359 个文件 - 2026-03-16 23:30:01
这个提交包含在:
@@ -30,13 +30,22 @@ import socket
|
||||
import ssl
|
||||
import warnings
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Set
|
||||
import sys
|
||||
|
||||
warnings.filterwarnings("ignore", message="urllib3 v2 only supports OpenSSL")
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[2] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import add_common_args, emit_report, make_report, write_evidence # noqa: E402
|
||||
|
||||
|
||||
DEFAULT_PORTS = [80, 443, 8080, 8443]
|
||||
|
||||
|
||||
@@ -226,6 +235,7 @@ def main() -> int:
|
||||
action="store_true",
|
||||
help="确认目标属于自有资产或已明确授权",
|
||||
)
|
||||
add_common_args(parser, include_network=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.ack_authorized:
|
||||
@@ -267,11 +277,25 @@ def main() -> int:
|
||||
"related_hosts": sorted(related_hosts),
|
||||
}
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(report, indent=2, ensure_ascii=True))
|
||||
else:
|
||||
print(render_text(report))
|
||||
return 0
|
||||
evidence_refs = []
|
||||
ref = write_evidence(args, "site-scope-map.json", report)
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
payload = make_report(
|
||||
tool="site-scope-mapper",
|
||||
mode="single-target-scope-map",
|
||||
target=args.target,
|
||||
status="verified" if report["http"] or report["tls"] else "needs-review",
|
||||
severity="low",
|
||||
payload_or_probe=report,
|
||||
request_summary={"ports": ports, "target_type": target_type},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="low",
|
||||
args=args,
|
||||
)
|
||||
if args.json and args.format == "text":
|
||||
args.format = "json"
|
||||
return emit_report(args, payload, render_text(report).splitlines())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Misconfiguration Lab Tool
|
||||
|
||||
LAB ONLY | AUTHORIZED TARGETS ONLY
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[3] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import add_common_args, emit_report, ensure_authorized, make_report, parse_headers, write_evidence # noqa: E402
|
||||
|
||||
|
||||
DEFAULT_PATHS = [
|
||||
"/.env",
|
||||
"/server-status",
|
||||
"/actuator/health",
|
||||
"/swagger-ui.html",
|
||||
"/phpinfo.php",
|
||||
"/admin/",
|
||||
"/debug",
|
||||
]
|
||||
|
||||
|
||||
def probe(target: str, timeout: float, headers: Dict[str, str]) -> List[Dict[str, Any]]:
|
||||
results = []
|
||||
for path in DEFAULT_PATHS:
|
||||
url = urljoin(target if target.endswith("/") else target + "/", path.lstrip("/"))
|
||||
try:
|
||||
response = requests.get(url, timeout=timeout, headers=headers, verify=False)
|
||||
results.append(
|
||||
{
|
||||
"path": path,
|
||||
"url": url,
|
||||
"status_code": response.status_code,
|
||||
"server": response.headers.get("Server"),
|
||||
"content_type": response.headers.get("Content-Type"),
|
||||
"body_excerpt": response.text[:300],
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
results.append({"path": path, "url": url, "error": str(exc)})
|
||||
return results
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Misconfiguration Lab Tool")
|
||||
parser.add_argument("--target", required=True, help="目标 URL")
|
||||
parser.add_argument("--timeout", type=float, default=8.0, help="请求超时时间")
|
||||
add_common_args(parser)
|
||||
args = parser.parse_args()
|
||||
ensure_authorized(args, parser)
|
||||
|
||||
headers = parse_headers(args.header)
|
||||
results = probe(args.target, args.timeout, headers)
|
||||
evidence_refs = []
|
||||
ref = write_evidence(args, "misconfig-lab.json", {"results": results})
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
suspicious = [item for item in results if item.get("status_code") in {200, 401, 403}]
|
||||
report = make_report(
|
||||
tool="misconfig-lab",
|
||||
mode="misconfiguration-surface-check",
|
||||
target=args.target,
|
||||
status="verified" if suspicious else "needs-review",
|
||||
severity="medium" if suspicious else "info",
|
||||
payload_or_probe={"results": results, "suspicious": suspicious},
|
||||
request_summary={"timeout": args.timeout, "paths": DEFAULT_PATHS},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="low",
|
||||
args=args,
|
||||
)
|
||||
text_lines = [
|
||||
"=" * 60,
|
||||
"Misconfiguration Lab Tool",
|
||||
"=" * 60,
|
||||
f"Target: {args.target}",
|
||||
f"Paths Checked: {len(DEFAULT_PATHS)}",
|
||||
f"Suspicious Responses: {len(suspicious)}",
|
||||
]
|
||||
return emit_report(args, report, text_lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -27,6 +27,14 @@ import time
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[2] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import add_common_args, emit_report, ensure_authorized, make_report, write_evidence # noqa: E402
|
||||
|
||||
|
||||
class Colors:
|
||||
@@ -229,37 +237,54 @@ def main():
|
||||
parser.add_argument("-t", "--threads", type=int, default=100, help="线程数")
|
||||
parser.add_argument("--timeout", type=float, default=1.0, help="超时时间")
|
||||
parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
|
||||
add_common_args(parser, include_network=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
ensure_authorized(args, parser)
|
||||
|
||||
scanner = PortScanner(threads=args.threads, timeout=args.timeout)
|
||||
if args.format != "text":
|
||||
scanner.print_result = lambda *_args, **_kwargs: None # type: ignore[assignment]
|
||||
|
||||
if args.top_ports:
|
||||
ports = scanner.top_ports[: args.top_ports]
|
||||
else:
|
||||
ports = scanner.parse_ports(args.ports)
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}Port Scanner{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
scanner.print_result("INFO", f"目标: {args.host}")
|
||||
scanner.print_result("INFO", f"端口: {len(ports)} 个")
|
||||
scanner.print_result("INFO", f"线程: {args.threads}")
|
||||
|
||||
results = scanner.scan_host(args.host, ports, args.verbose)
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
if results:
|
||||
scanner.print_result("SUCCESS", f"发现 {len(results)} 个开放端口:")
|
||||
print(f"\n{'PORT':<10} {'SERVICE':<15} {'BANNER'}")
|
||||
print("-" * 60)
|
||||
for r in sorted(results, key=lambda x: x["port"]):
|
||||
banner = r["banner"][:40] if r["banner"] else r["service"]
|
||||
print(f"{r['port']:<10} {r['service']:<15} {banner}")
|
||||
else:
|
||||
scanner.print_result("INFO", "未发现开放端口")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
evidence_refs = []
|
||||
ref = write_evidence(args, "port-scan-results.json", {"results": results, "ports": ports})
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
status = "verified" if results else "needs-review"
|
||||
severity = "medium" if results else "info"
|
||||
report = make_report(
|
||||
tool="port-scanner",
|
||||
mode="minimal-port-scan",
|
||||
target=args.host,
|
||||
status=status,
|
||||
severity=severity,
|
||||
payload_or_probe={"ports": ports, "open_ports": results},
|
||||
request_summary={"threads": args.threads, "timeout": args.timeout},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="low",
|
||||
args=args,
|
||||
)
|
||||
text_lines = [
|
||||
"=" * 60,
|
||||
"Port Scanner",
|
||||
"=" * 60,
|
||||
f"Target: {args.host}",
|
||||
f"Ports Checked: {len(ports)}",
|
||||
f"Open Ports: {len(results)}",
|
||||
f"Status: {status}",
|
||||
]
|
||||
emit_report(args, report, text_lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -26,6 +26,14 @@ import re
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
from datetime import datetime
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[2] / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from tool_contract import add_common_args, emit_report, ensure_authorized, make_report, write_evidence # noqa: E402
|
||||
|
||||
|
||||
class Colors:
|
||||
@@ -271,74 +279,45 @@ def main():
|
||||
parser.add_argument("-u", "--url", required=True, help="目标 URL 或主机名")
|
||||
parser.add_argument("-p", "--port", type=int, default=443, help="端口 (默认: 443)")
|
||||
parser.add_argument("--timeout", type=int, default=10, help="超时时间")
|
||||
add_common_args(parser, include_network=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
ensure_authorized(args, parser)
|
||||
|
||||
hostname = args.url.replace("https://", "").replace("http://", "").split("/")[0]
|
||||
|
||||
scanner = TLSScanner(timeout=args.timeout)
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}TLS Scanner{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
scanner.print_result("INFO", f"目标: {hostname}:{args.port}")
|
||||
|
||||
print(f"\n{Colors.CYAN}[*] 扫描协议支持...{Colors.END}")
|
||||
results = scanner.scan(hostname, args.port)
|
||||
|
||||
print(f"\n{Colors.CYAN}协议支持:{Colors.END}")
|
||||
for proto, supported in results["protocols"].items():
|
||||
status = (
|
||||
f"{Colors.GREEN}支持{Colors.END}"
|
||||
if supported
|
||||
else f"{Colors.RED}不支持{Colors.END}"
|
||||
)
|
||||
if supported and proto in ["SSLv2", "SSLv3"]:
|
||||
status = f"{Colors.RED}支持 (不安全){Colors.END}"
|
||||
elif supported and proto in ["TLSv1.0", "TLSv1.1"]:
|
||||
status = f"{Colors.YELLOW}支持 (过时){Colors.END}"
|
||||
print(f" {proto:<10} {status}")
|
||||
|
||||
if results["cipher"]:
|
||||
print(f"\n{Colors.CYAN}当前密码套件:{Colors.END}")
|
||||
cipher_name, cipher_proto, cipher_bits = results["cipher"]
|
||||
print(f" 名称: {cipher_name}")
|
||||
print(f" 协议: {cipher_proto}")
|
||||
print(f" 密钥长度: {cipher_bits} bits")
|
||||
|
||||
if results["certificate"]:
|
||||
print(f"\n{Colors.CYAN}证书信息:{Colors.END}")
|
||||
cert = results["certificate"]
|
||||
print(f" 主题: {cert['subject'].get('commonName', 'N/A')}")
|
||||
print(f" 颁发者: {cert['issuer'].get('commonName', 'N/A')}")
|
||||
print(f" 有效期: {cert['not_before']} - {cert['not_after']}")
|
||||
|
||||
print(f"\n{Colors.CYAN}HSTS:{Colors.END}")
|
||||
if results["hsts"]["enabled"]:
|
||||
print(f" 状态: {Colors.GREEN}已启用{Colors.END}")
|
||||
print(f" Max-Age: {results['hsts']['max_age']} 秒")
|
||||
print(
|
||||
f" IncludeSubDomains: {'是' if results['hsts']['include_subdomains'] else '否'}"
|
||||
)
|
||||
print(f" Preload: {'是' if results['hsts']['preload'] else '否'}")
|
||||
else:
|
||||
print(f" 状态: {Colors.RED}未启用{Colors.END}")
|
||||
|
||||
print(f"\n{Colors.CYAN}安全问题:{Colors.END}")
|
||||
if results["issues"]:
|
||||
for issue in sorted(results["issues"], key=lambda x: x["severity"]):
|
||||
color = (
|
||||
Colors.RED
|
||||
if issue["severity"] in ["CRITICAL", "HIGH"]
|
||||
else Colors.YELLOW
|
||||
)
|
||||
print(f" {color}[{issue['severity']}]{Colors.END} {issue['issue']}")
|
||||
print(f" 建议: {issue['recommendation']}")
|
||||
else:
|
||||
print(f" {Colors.GREEN}未发现安全问题{Colors.END}")
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
evidence_refs = []
|
||||
ref = write_evidence(args, "tls-results.json", results)
|
||||
if ref:
|
||||
evidence_refs.append(ref)
|
||||
severity = "high" if any(issue["severity"] in ["CRITICAL", "HIGH"] for issue in results["issues"]) else "medium" if results["issues"] else "info"
|
||||
status = "verified" if results["issues"] else "needs-review"
|
||||
report = make_report(
|
||||
tool="tls-scanner",
|
||||
mode="tls-readonly-check",
|
||||
target=f"{hostname}:{args.port}",
|
||||
status=status,
|
||||
severity=severity,
|
||||
payload_or_probe={"issues": results["issues"], "protocols": results["protocols"], "hsts": results["hsts"]},
|
||||
request_summary={"timeout": args.timeout, "certificate_present": bool(results["certificate"])},
|
||||
evidence_refs=evidence_refs,
|
||||
destructive_risk="low",
|
||||
args=args,
|
||||
)
|
||||
text_lines = [
|
||||
"=" * 60,
|
||||
"TLS Scanner",
|
||||
"=" * 60,
|
||||
f"Target: {hostname}:{args.port}",
|
||||
f"Issues: {len(results['issues'])}",
|
||||
f"HSTS Enabled: {'yes' if results['hsts']['enabled'] else 'no'}",
|
||||
f"Status: {status}",
|
||||
]
|
||||
emit_report(args, report, text_lines)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
在新工单中引用
屏蔽一个用户