mirror of
https://github.com/yyhuni/xingrin.git
synced 2026-02-02 20:53:13 +08:00
281 lines
10 KiB
Python
281 lines
10 KiB
Python
"""
|
||
扫描工具命令模板(简化版,不使用 Jinja2)
|
||
|
||
使用 Python 原生字符串格式化,零依赖。
|
||
"""
|
||
|
||
from django.conf import settings
|
||
|
||
# ==================== 路径配置 ====================
|
||
SCAN_TOOLS_BASE_PATH = getattr(settings, 'SCAN_TOOLS_BASE_PATH', '/opt/xingrin/tools')
|
||
|
||
# ==================== 子域名发现 ====================
|
||
|
||
SUBDOMAIN_DISCOVERY_COMMANDS = {
|
||
'subfinder': {
|
||
# 默认使用所有数据源(更全面,略慢),并始终开启递归
|
||
# -all 使用所有数据源
|
||
# -recursive 对支持递归的源启用递归枚举(默认开启)
|
||
'base': 'subfinder -d {domain} -all -recursive -o {output_file} -silent',
|
||
'optional': {
|
||
'threads': '-t {threads}', # 控制并发 goroutine 数
|
||
}
|
||
},
|
||
|
||
'amass_passive': {
|
||
# 先执行被动枚举,将结果写入 amass 内部数据库,然后从数据库中导出纯域名(names)到 output_file
|
||
# -silent 禁用进度条和其他输出
|
||
'base': 'amass enum -passive -silent -d {domain} && amass subs -names -d {domain} > {output_file}'
|
||
},
|
||
|
||
'amass_active': {
|
||
# 先执行主动枚举 + 爆破,将结果写入 amass 内部数据库,然后从数据库中导出纯域名(names)到 output_file
|
||
# -silent 禁用进度条和其他输出
|
||
'base': 'amass enum -active -silent -d {domain} -brute && amass subs -names -d {domain} > {output_file}'
|
||
},
|
||
|
||
'sublist3r': {
|
||
'base': 'python3 {scan_tools_base}/Sublist3r/sublist3r.py -d {domain} -o {output_file}',
|
||
'optional': {
|
||
'threads': '-t {threads}'
|
||
}
|
||
},
|
||
|
||
'assetfinder': {
|
||
'base': 'assetfinder --subs-only {domain} > {output_file}',
|
||
},
|
||
|
||
# === 主动字典爆破 ===
|
||
'subdomain_bruteforce': {
|
||
# 使用字典对目标域名进行 DNS 爆破
|
||
# -d 目标域名,-w 字典文件,-o 输出文件
|
||
'base': 'puredns bruteforce {wordlist} {domain} -r /app/backend/resources/resolvers.txt --write {output_file} --quiet',
|
||
'optional': {},
|
||
},
|
||
|
||
# === DNS 存活验证(最终统一验证)===
|
||
'subdomain_resolve': {
|
||
# 验证子域名是否能解析(存活验证)
|
||
# 输入文件为候选子域列表,输出为存活子域列表
|
||
'base': 'puredns resolve {input_file} -r /app/backend/resources/resolvers.txt --write {output_file} --wildcard-tests 50 --wildcard-batch 1000000 --quiet',
|
||
'optional': {},
|
||
},
|
||
|
||
# === 变异生成 + 存活验证(流式管道,避免 OOM)===
|
||
'subdomain_permutation_resolve': {
|
||
# 流式管道:dnsgen 生成变异域名 | puredns resolve 验证存活
|
||
# 不落盘中间文件,避免内存爆炸;不做通配符过滤
|
||
'base': 'cat {input_file} | dnsgen - | puredns resolve -r /app/backend/resources/resolvers.txt --write {output_file} --wildcard-tests 50 --wildcard-batch 1000000 --quiet',
|
||
'optional': {},
|
||
},
|
||
}
|
||
|
||
|
||
# ==================== 端口扫描 ====================
|
||
|
||
PORT_SCAN_COMMANDS = {
|
||
'naabu_active': {
|
||
'base': 'naabu -exclude-cdn -warm-up-time 5 -verify -list {domains_file} -json -silent',
|
||
'optional': {
|
||
'threads': '-c {threads}',
|
||
'ports': '-p {ports}',
|
||
'top_ports': '-top-ports {top_ports}',
|
||
'rate': '-rate {rate}'
|
||
}
|
||
},
|
||
|
||
'naabu_passive': {
|
||
'base': 'naabu -list {domains_file} -passive -json -silent'
|
||
},
|
||
}
|
||
|
||
|
||
# ==================== 站点扫描 ====================
|
||
|
||
SITE_SCAN_COMMANDS = {
|
||
'httpx': {
|
||
'base': (
|
||
'httpx -l {url_file} '
|
||
'-status-code -content-type -content-length '
|
||
'-location -title -server -body-preview '
|
||
'-tech-detect -cdn -vhost '
|
||
'-random-agent -no-color -json'
|
||
),
|
||
'optional': {
|
||
'threads': '-threads {threads}',
|
||
'rate_limit': '-rate-limit {rate_limit}',
|
||
'request_timeout': '-timeout {request_timeout}',
|
||
'retries': '-retries {retries}'
|
||
}
|
||
},
|
||
}
|
||
|
||
|
||
# ==================== 目录扫描 ====================
|
||
|
||
DIRECTORY_SCAN_COMMANDS = {
|
||
'ffuf': {
|
||
'base': 'ffuf -u {url}/FUZZ -se -ac -sf -json -w {wordlist}',
|
||
'optional': {
|
||
'delay': '-p {delay}',
|
||
'threads': '-t {threads}',
|
||
'request_timeout': '-timeout {request_timeout}',
|
||
'match_codes': '-mc {match_codes}',
|
||
'rate': '-rate {rate}'
|
||
}
|
||
},
|
||
}
|
||
|
||
|
||
# ==================== URL 获取 ====================
|
||
|
||
URL_FETCH_COMMANDS = {
|
||
'waymore': {
|
||
'base': 'waymore -i {domain_name} -mode U -oU {output_file}',
|
||
'input_type': 'domain_name'
|
||
},
|
||
|
||
'katana': {
|
||
'base': (
|
||
'katana -list {sites_file} -o {output_file} '
|
||
'-jc ' # 开启 JavaScript 爬取 + 自动解析 .js 文件里的所有端点(最重要)
|
||
'-xhr ' # 额外从 JS 中提取 XHR/Fetch 请求的 API 路径(再多挖 10-20% 隐藏接口)
|
||
'-kf all ' # 在每个目录下自动 fuzz 所有已知敏感文件(.env、.git、backup、config、ds_store 等 5000+ 条)
|
||
'-fs rdn ' # 智能过滤相对重复+噪声路径(分页、?id=1/2/3 这类垃圾全干掉,输出极干净)
|
||
'-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" ' # 固定一个正常 UA(Katana 默认会随机,但固定更低调)
|
||
'-silent ' # 安静模式(终端不输出进度条,只出 URL)
|
||
),
|
||
'optional': {
|
||
'depth': '-d {depth}', # 爬取最大深度(平衡深度与时间,默认 3,推荐 5)
|
||
'threads': '-c {threads}', # 全局并发数(极低并发最像真人,推荐 10)
|
||
'rate_limit': '-rl {rate_limit}', # 全局硬限速:每秒最多 N 个请求(WAF 几乎不报警,推荐 30)
|
||
'random_delay': '-rd {random_delay}', # 每次请求之间随机延迟 N 秒(再加一层人性化,推荐 1)
|
||
'retry': '-retry {retry}', # 失败请求自动重试次数(网络抖动不丢包,推荐 2)
|
||
'request_timeout': '-timeout {request_timeout}' # 单请求超时秒数(防卡死,推荐 12)
|
||
},
|
||
'input_type': 'sites_file'
|
||
},
|
||
|
||
'uro': {
|
||
'base': 'uro -i {input_file} -o {output_file}',
|
||
'optional': {
|
||
'whitelist': '-w {whitelist}', # 只保留指定扩展名的 URL(空格分隔)
|
||
'blacklist': '-b {blacklist}', # 排除指定扩展名的 URL(空格分隔)
|
||
'filters': '-f {filters}' # 额外的过滤规则(空格分隔)
|
||
}
|
||
},
|
||
|
||
'httpx': {
|
||
'base': (
|
||
'httpx -l {url_file} '
|
||
'-status-code -content-type -content-length '
|
||
'-location -title -server -body-preview '
|
||
'-tech-detect -cdn -vhost '
|
||
'-random-agent -no-color -json'
|
||
),
|
||
'optional': {
|
||
'threads': '-threads {threads}',
|
||
'rate_limit': '-rate-limit {rate_limit}',
|
||
'request_timeout': '-timeout {request_timeout}',
|
||
'retries': '-retries {retries}'
|
||
}
|
||
},
|
||
}
|
||
|
||
VULN_SCAN_COMMANDS = {
|
||
'dalfox_xss': {
|
||
'base': (
|
||
'dalfox --silence --no-color --no-spinner '
|
||
'--skip-bav '
|
||
'file {endpoints_file} '
|
||
'--waf-evasion '
|
||
'--format json'
|
||
),
|
||
'optional': {
|
||
'only_poc': '--only-poc {only_poc}',
|
||
'ignore_return': '--ignore-return {ignore_return}',
|
||
'blind_xss_server': '-b {blind_xss_server}',
|
||
'delay': '--delay {delay}',
|
||
'request_timeout': '--timeout {request_timeout}',
|
||
# 是否追加 UA 头,由 user_agent 是否存在决定
|
||
'user_agent': '--user-agent "{user_agent}"',
|
||
'worker': '--worker {worker}',
|
||
},
|
||
'input_type': 'endpoints_file',
|
||
},
|
||
'nuclei': {
|
||
# nuclei 漏洞扫描
|
||
# -j: JSON 输出
|
||
# -silent: 静默模式
|
||
# -l: 输入 URL 列表文件
|
||
# -t: 模板目录路径(支持多个仓库,多次 -t 由 template_args 直接拼接)
|
||
'base': 'nuclei -j -silent -l {endpoints_file} {template_args}',
|
||
'optional': {
|
||
'concurrency': '-c {concurrency}', # 并发数(默认 25)
|
||
'rate_limit': '-rl {rate_limit}', # 每秒请求数限制
|
||
'request_timeout': '-timeout {request_timeout}', # 请求超时秒数
|
||
'bulk_size': '-bs {bulk_size}', # 批量处理大小
|
||
'retries': '-retries {retries}', # 重试次数
|
||
'severity': '-severity {severity}', # 过滤严重性(info,low,medium,high,critical)
|
||
'tags': '-tags {tags}', # 过滤标签
|
||
'exclude_tags': '-etags {exclude_tags}', # 排除标签
|
||
},
|
||
'input_type': 'endpoints_file',
|
||
},
|
||
}
|
||
|
||
|
||
# ==================== 工具映射 ====================
|
||
|
||
COMMAND_TEMPLATES = {
|
||
'subdomain_discovery': SUBDOMAIN_DISCOVERY_COMMANDS,
|
||
'port_scan': PORT_SCAN_COMMANDS,
|
||
'site_scan': SITE_SCAN_COMMANDS,
|
||
'directory_scan': DIRECTORY_SCAN_COMMANDS,
|
||
'url_fetch': URL_FETCH_COMMANDS,
|
||
'vuln_scan': VULN_SCAN_COMMANDS,
|
||
}
|
||
|
||
# ==================== 扫描类型配置 ====================
|
||
|
||
# 执行阶段定义(按顺序执行)
|
||
EXECUTION_STAGES = [
|
||
{
|
||
'mode': 'sequential',
|
||
'flows': ['subdomain_discovery', 'port_scan', 'site_scan']
|
||
},
|
||
{
|
||
'mode': 'parallel',
|
||
'flows': ['url_fetch', 'directory_scan']
|
||
},
|
||
{
|
||
'mode': 'sequential',
|
||
'flows': ['vuln_scan']
|
||
},
|
||
]
|
||
|
||
|
||
def get_supported_scan_types():
|
||
"""
|
||
获取支持的扫描类型
|
||
|
||
Returns:
|
||
list: 支持的扫描类型列表(从 COMMAND_TEMPLATES 的 keys 获取)
|
||
"""
|
||
return list(COMMAND_TEMPLATES.keys())
|
||
|
||
|
||
def get_command_template(scan_type: str, tool_name: str) -> dict:
|
||
"""
|
||
获取工具的命令模板
|
||
|
||
Args:
|
||
scan_type: 扫描类型
|
||
tool_name: 工具名称
|
||
|
||
Returns:
|
||
命令模板字典,如果未找到则返回 None
|
||
"""
|
||
templates = COMMAND_TEMPLATES.get(scan_type, {})
|
||
return templates.get(tool_name)
|