XRAY爬虫模式实战:构建企业内网Web资产自动化漏洞巡检流水线

📅 2026/6/29 8:32:11
XRAY爬虫模式实战:构建企业内网Web资产自动化漏洞巡检流水线
1. 项目概述从单点扫描到自动化资产巡检的转变在安全测试的日常工作中我们常常面临一个矛盾手头有像XRAY这样强大的被动扫描工具但它默认的工作模式是代理模式需要手动配置浏览器代理然后一个个页面去点击、触发流量。当面对一个庞大的企业内网有成百上千个Web应用、管理后台、API接口需要做初步的安全体检时这种“人肉驱动”的方式效率极其低下几乎不可能完成。这就是为什么我们需要探索XRAY的“爬虫模式”并将其与批量检测、报告自动化结合起来构建一套轻量级但高效的内网Web资产漏洞巡检流水线。简单来说这个项目的核心目标就是让XRAY从一个被动的“监听者”变成一个主动的“探索者”和“检查员”。我们不再需要手动浏览每一个页面而是通过一个起始URL列表让XRAY自动去爬取、去发现、去测试。这听起来像是AWVS、AppScan这类商业扫描器的功能但XRAY的优势在于它轻量、免费、高度可定制并且其漏洞检测能力尤其是逻辑漏洞和新型漏洞在社区中备受认可。通过爬虫模式配合批量任务我们可以快速对内网大量Web资产进行一次“普查”筛选出高风险目标再投入精力进行深度手工测试极大地提升了安全工作的覆盖面和响应速度。2. 核心思路与方案设计为什么是爬虫模式批量2.1 爬虫模式 vs. 代理模式适用场景深度剖析首先我们必须彻底理解XRAY两种核心工作模式的本质区别这决定了我们整个方案的设计基础。代理模式是XRAY最经典、最强大的模式。它作为一个中间人代理拦截并分析所有经过它的HTTP/HTTPS流量。这种模式的优点是“所见即扫描”。你在浏览器或APP里的每一个操作点击的每一个链接提交的每一个表单都会被XRAY捕获并深度分析。它特别适合深度手工测试测试复杂的业务逻辑流程如购物车、支付、订单状态修改。需要登录认证的应用配置好浏览器代理和XRAY的认证信息后可以无缝扫描需要Cookie/Session的页面。AJAX/WebSocket等动态内容能实时捕获前端脚本发起的请求。但它的缺点也很明显严重依赖人工操作。扫描范围完全取决于测试人员点击了哪里。对于内网中大量存在的静态官网、信息展示页、文档系统等一个个去点开是不现实的。爬虫模式则完全不同。你可以把它理解为XRAY内置了一个简单的、专注于安全测试的Web爬虫。你给它一个或多个起始URL它会自动解析页面中的链接如a hrefform actionscript src等并递归地访问这些新发现的链接从而不断扩大扫描范围。在这个过程中它会对每一个请求和响应进行漏洞检测。它的优势在于自动化与广度覆盖无需人工干预即可自动发现和扫描一个站点内的大量页面。适合资产普查快速对一个域名或IP下的Web应用进行漏洞“初筛”。与批量任务天然契合可以很容易地编写脚本为资产列表中的每一个目标启动一个爬虫扫描任务。所以对于“批量检测企业内网漏洞”这个场景爬虫模式是唯一高效的选择。我们的方案就是准备一份内网Web资产清单URL列表 - 编写脚本循环调用XRAY爬虫模式 - 收集并解析每个任务的扫描结果 - 聚合生成统一的HTML报告。2.2 工具链选型与准备工作工欲善其事必先利其器。除了XRAY本身我们还需要一些辅助工具来搭建这个流水线。XRAY核心程序从官方渠道获取最新版本的社区版或高级版二进制文件。确保你对其基础配置有了解特别是config.yaml文件中关于插件启用、扫描速度、代理设置等部分。资产清单管理一个文本文件如targets.txt是最简单的形式每行一个目标URL。更高级的可以用Excel/CSV或者从资产管理系统、CMDB中通过API导出。目标格式应为http://ip:port或https://hostname。任务调度与脚本这是自动化的核心。Bash Shell脚本Linux/Mac或Batch/PowerShell脚本Windows是轻量级的选择。如果需要更复杂的错误处理、并发控制和状态管理可以用Python编写它拥有丰富的库支持。报告处理工具XRAY爬虫模式默认输出的是JSON格式的结果文件。我们需要将其转换为更易读的HTML报告。XRAY本身提供了xray webscan命令可以指定输出HTML报告。我们将利用这一点并在此基础上进行批量报告的合并与美化。运行环境一台可以访问内网所有目标资产的服务器或虚拟机。Linux环境通常是首选因为其命令行工具强大且稳定。注意在开始批量扫描前务必获得书面授权。即使是内网安全巡检也必须由安全部门或上级领导发起明确扫描范围和时间窗口避免对业务系统造成意外影响如扫描压力导致服务缓慢。3. 实操详解构建批量爬虫扫描流水线理论清晰后我们进入实战环节。我将以一个基于Linux Shell脚本的简单、高效的流水线为例拆解每一个步骤。3.1 第一步准备扫描目标与XRAY配置假设我们有一个内网资产文件internal_targets.txt内容如下http://192.168.1.100 https://oa.internal.company.com http://192.168.1.150:8080 http://confluence.internal.company.com首先我们需要对XRAY进行一些基础配置以优化爬虫扫描效果。编辑XRAY目录下的config.yaml文件plugins: # 启用常见的Web漏洞插件根据实际情况调整 sqldet: true # SQL注入 cmd_injection: true # 命令注入 dirscan: true # 目录扫描 xss: true # 跨站脚本 path_traversal: true # 路径穿越 ... mitm: restriction: # 限制爬虫和扫描的范围非常重要避免爬出目标域名造成风险。 includes: # 使用正则表达式只扫描目标域下的链接 - “.*\.internal\.company\.com.*” - “192\.168\.1\..*” scan: crawler: max_depth: 5 # 爬虫最大深度防止陷入无限循环 max_count_of_links: 1000 # 最大爬取链接数控制扫描规模 ...关键配置解读restriction.includes这是安全红线。必须根据你的资产列表精确设置确保XRAY只爬取和扫描你授权的目标。例如如果你只扫描oa.internal.company.com但该页面有一个外链到www.github.com没有这个限制爬虫可能会爬出去这是绝对不允许的。max_depth和max_count_of_links用于控制扫描的“量”。内网系统可能相互链接复杂设置上限可以防止单次扫描任务耗时过长或消耗过多资源。3.2 第二步编写批量扫描Shell脚本创建一个名为batch_xray_crawl.sh的脚本#!/bin/bash # 批量XRAY爬虫扫描脚本 # 作者你的名字 # 说明遍历目标列表对每个目标执行爬虫扫描并生成独立报告 XRAY_PATH./xray_linux_amd64 # XRAY二进制文件路径 TARGET_FILE./internal_targets.txt # 目标列表文件 REPORT_DIR./reports/$(date %Y%m%d_%H%M%S) # 按时间创建报告目录 LOG_FILE${REPORT_DIR}/scan.log # 总日志文件 # 创建报告目录 mkdir -p ${REPORT_DIR} echo “批量爬虫扫描开始于: $(date)” | tee -a ${LOG_FILE} echo “报告将保存至: ${REPORT_DIR}” | tee -a ${LOG_FILE} # 初始化计数器 TOTAL$(wc -l ${TARGET_FILE}) COUNT0 # 逐行读取目标文件 while IFS read -r TARGET; do # 去除行首尾空白字符 TARGET$(echo ${TARGET} | xargs) # 跳过空行和以#开头的注释行 if [[ -z “${TARGET}” ]] || [[ “${TARGET}” \#* ]]; then continue fi ((COUNT)) # 为目标生成一个安全的文件名用于报告 # 将‘://‘, ‘:‘, ‘/‘, ‘.‘ 等字符替换为下划线 SAFE_NAME$(echo ${TARGET} | sed ‘s/[:\/.]/_/g’) REPORT_PREFIX“${REPORT_DIR}/${SAFE_NAME}” echo “[${COUNT}/${TOTAL}] 正在扫描: ${TARGET}” | tee -a ${LOG_FILE} # 核心命令启动XRAY爬虫扫描 # –basic-crawler: 启用爬虫模式 # –url: 指定起始URL # –html-output: 生成HTML报告 # –json-output: 同时生成JSON报告用于后续处理 timeout 1800 ${XRAY_PATH} webscan –basic-crawler ${TARGET} –html-output ${REPORT_PREFIX}_report.html –json-output ${REPORT_PREFIX}_result.json 21 | tee -a ${LOG_FILE} SCAN_EXIT_CODE${PIPESTATUS[0]} # 检查扫描结果 if [[ ${SCAN_EXIT_CODE} -eq 0 ]]; then echo “ [] 扫描完成: ${REPORT_PREFIX}_report.html” | tee -a ${LOG_FILE} elif [[ ${SCAN_EXIT_CODE} -eq 124 ]]; then echo “ [!] 扫描超时30分钟: ${TARGET}” | tee -a ${LOG_FILE} else echo “ [-] 扫描可能出错退出码: ${SCAN_EXIT_CODE}” | tee -a ${LOG_FILE} fi echo “—————————————————————” | tee -a ${LOG_FILE} # 可选每次扫描后暂停一下避免对网络和设备造成瞬时压力 sleep 5 done “${TARGET_FILE}” echo “批量扫描全部结束于: $(date)” | tee -a ${LOG_FILE} echo “所有报告已保存至: ${REPORT_DIR}” | tee -a ${LOG_FILE}脚本关键点解析目录组织使用$(date %Y%m%d_%H%M%S)为每次扫描任务创建带有时间戳的唯一报告目录便于归档和追溯。目标处理使用while read循环逐行处理并过滤空行和注释以#开头增加了脚本的灵活性。安全文件名URL中包含的://、:等字符在文件系统中不友好用sed命令将其替换为下划线避免创建文件失败。核心命令xray webscan –basic-crawler –url –html-output –json-output是爬虫扫描的核心。同时输出HTML和JSONHTML用于人工查看JSON用于后续可能的自动化分析。超时控制使用timeout 1800命令限制单次扫描最长运行时间为30分钟。对于未知大小的站点这是一个必要的保护措施防止某个目标卡住整个批量任务。状态记录与暂停详细记录日志并在每个目标扫描后sleep 5秒这是一种简单的“礼貌扫描”策略可以稍微降低对目标服务器的并发压力。3.3 第三步执行扫描与初步报告生成给脚本添加执行权限并运行chmod x batch_xray_crawl.sh ./batch_xray_crawl.sh脚本运行后你会在reports/20231027_143022/这样的目录下看到如下文件192_168_1_100_report.html192_168_1_100_result.jsonoa_internal_company_com_report.htmloa_internal_company_com_result.jsonscan.log此时你已经拥有了每个目标的独立HTML报告。双击HTML文件即可在浏览器中查看XRAY生成的报告界面清晰会按漏洞风险等级高危、中危、低危、信息列出发现的问题并包含请求、响应等详细信息便于复现。4. 报告生成技巧从独立报告到聚合仪表盘独立的报告对于分析单个目标很方便但作为一次批量巡检的输出我们需要一份能总览全局的报告。例如安全负责人可能只关心“这次扫了100个系统有多少个存在高危漏洞分别是哪些” 我们需要将分散的JSON结果聚合起来。4.1 使用Python聚合JSON结果并生成总览报告我们可以编写一个Python脚本来解析所有*_result.json文件生成一个汇总的HTML仪表盘。这里提供一个简化版的思路和核心代码片段。首先安装可能需要的Python库pip install jinja2一个流行的模板引擎。创建脚本generate_summary.py#!/usr/bin/env python3 import json import os import glob from jinja2 import Template from datetime import datetime def parse_xray_json(json_file_path): “”“解析单个XRAY JSON结果文件”“” with open(json_file_path, ‘r’, encoding‘utf-8’) as f: data json.load(f) target data.get(‘target’, {‘url’: ‘Unknown’}).get(‘url’, ‘Unknown’) vulnerabilities [] for item in data.get(‘vulnerabilities’, []): vuln { ‘plugin’: item.get(‘plugin’, ‘’), ‘detail’: item.get(‘detail’, {}), ‘risk’: ‘高危’ if ‘high’ in item.get(‘plugin’, ‘’).lower() else ‘中危’ if ‘medium’ in item.get(‘plugin’, ‘’).lower() else ‘低危’ if ‘low’ in item.get(‘plugin’, ‘’).lower() else ‘信息’, ‘url’: item.get(‘detail’, {}).get(‘addr’, ‘’), ‘payload’: item.get(‘detail’, {}).get(‘payload’, ‘’), } # 这里可以提取更多你需要的信息 vulnerabilities.append(vuln) return { ‘target’: target, ‘vulnerabilities’: vulnerabilities, ‘vuln_count’: len(vulnerabilities), ‘high_count’: sum(1 for v in vulnerabilities if v[‘risk’] ‘高危’), ‘medium_count’: sum(1 for v in vulnerabilities if v[‘risk’] ‘中危’), ‘low_count’: sum(1 for v in vulnerabilities if v[‘risk’] ‘低危’), ‘info_count’: sum(1 for v in vulnerabilities if v[‘risk’] ‘信息’), ‘report_file’: os.path.basename(json_file_path).replace(‘_result.json’, ‘_report.html’) } def main(): # 假设报告目录是当前目录下的最新一个reports子目录 report_dirs glob.glob(‘./reports/*’) if not report_dirs: print(“未找到报告目录”) return latest_report_dir max(report_dirs, keyos.path.getmtime) json_files glob.glob(os.path.join(latest_report_dir, ‘*_result.json’)) all_results [] total_high total_medium total_low total_info 0 for jf in json_files: result parse_xray_json(jf) all_results.append(result) total_high result[‘high_count’] total_medium result[‘medium_count’] total_low result[‘low_count’] total_info result[‘info_count’] # 按高危漏洞数量降序排序 all_results.sort(keylambda x: x[‘high_count’], reverseTrue) # 使用Jinja2模板生成HTML html_template “”“ !DOCTYPE html html head meta charset“utf-8” title内网漏洞批量扫描总览报告/title style body { font-family: sans-serif; margin: 20px; } .summary { background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .risk-high { color: #dc3545; font-weight: bold; } .risk-medium { color: #fd7e14; } .risk-low { color: #ffc107; } .risk-info { color: #6c757d; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #e9ecef; } tr:hover { background-color: #f8f9fa; } a { text-decoration: none; } /style /head body h1企业内网Web资产漏洞扫描总览/h1 p生成时间{{ scan_time }}/p div class“summary” h2扫描统计/h2 p扫描目标总数strong{{ total_targets }}/strong/p p漏洞统计 span class“risk-high”高危 {{ total_high }}/span | span class“risk-medium”中危 {{ total_medium }}/span | span class“risk-low”低危 {{ total_low }}/span | span class“risk-info”信息 {{ total_info }}/span /p /div h2目标详情/h2 table thead tr th目标/th th漏洞总数/th th高危/th th中危/th th低危/th th信息/th th详细报告/th /tr /thead tbody {% for result in results %} tr td{{ result.target }}/td td{{ result.vuln_count }}/td td class“risk-high”{{ result.high_count }}/td td class“risk-medium”{{ result.medium_count }}/td td class“risk-low”{{ result.low_count }}/td td class“risk-info”{{ result.info_count }}/td tda href“{{ result.report_file }}” target“_blank”查看/a/td /tr {% endfor %} /tbody /table /body /html ”“” template Template(html_template) html_output template.render( scan_timedatetime.now().strftime(‘%Y-%m-%d %H:%M:%S’), total_targetslen(all_results), total_hightotal_high, total_mediumtotal_medium, total_lowtotal_low, total_infototal_info, resultsall_results ) summary_report_path os.path.join(latest_report_dir, ‘00_扫描总览.html’) with open(summary_report_path, ‘w’, encoding‘utf-8’) as f: f.write(html_output) print(f“聚合报告已生成: {summary_report_path}”) if __name__ ‘__main__’: main()运行这个脚本python3 generate_summary.py它会在最新的报告目录中生成一个名为00_扫描总览.html的文件。打开这个文件你将看到一个清晰的仪表盘展示了所有扫描目标的漏洞分布情况并可以一键链接到每个目标的详细报告。4.2 报告优化与定制技巧上面的聚合报告只是一个起点。在实际工作中你可以根据团队需求进行大量定制风险评分排序不要只看高危数量。可以设计一个简单的风险评分公式例如风险分 高危数*10 中危数*4 低危数*1然后按风险分排序更能反映目标的整体风险状况。漏洞类型统计在总览页增加一个“最常见漏洞类型”的图表如使用Chart.js让团队一眼看出当前内网最普遍的安全问题是什么是SQL注入、XSS还是信息泄露。历史对比如果定期扫描可以将本次结果与上次结果进行对比用箭头↑↓显示风险变化突出风险加剧的系统。负责人关联如果你的资产清单中包含了系统负责人信息可以在聚合报告中加入一列“负责人”并自动将报告通过邮件发送给对应的负责人。报告样式专业化使用更专业的CSS框架如Bootstrap来美化报告使其更接近正式的审计报告格式。5. 进阶技巧与避坑指南掌握了基础流程后下面这些从实战中总结的经验和技巧能让你把这件事做得更专业、更稳健。5.1 提升爬虫扫描效率与覆盖率的技巧巧用–plugins参数不是每次普查都需要启用所有插件。对于初步筛查可以只启用sqldet,xss,dirscan,brute_force等高风险插件能显著缩短扫描时间。命令如xray webscan –basic-crawler http://target –plugins sqldet,xss –html-output report.html。设置合理的请求间隔在config.yaml的http部分可以设置max_qps来限制每秒最大请求数。对于内网环境可以适当调高如10-20但也要避免把老旧服务器打挂。处理登录认证爬虫模式也支持认证。对于需要登录的系统你可以先手动登录然后使用–browser-crawler模式需要配合浏览器驱动或者将登录后的Cookie通过–headers “Cookie: xxxyyy”参数传递给爬虫。这是扫描覆盖面的关键。利用–url-file批量扫描子路径如果你知道目标有很多固定路径如/admin,/phpmyadmin,/backup可以将这些路径保存到一个文件然后使用–url-file参数让爬虫从这些入口点开始爬提高针对性。5.2 企业内网扫描的特殊注意事项网络可达性与DNS确保你的扫描主机能解析内网域名如oa.internal.company.com。可能需要配置内部DNS服务器地址或修改本地的/etc/hosts文件。避开生产敏感时段与业务部门沟通将批量扫描安排在业务低峰期例如深夜或周末。识别和过滤非Web资产你的资产清单里可能有单纯的IP地址。XRAY会尝试连接80/443端口。如果该IP运行的是数据库或中间件服务可能会返回非HTTP响应导致XRAY报错或卡住。可以在脚本中加入预处理用curl -I –connect-timeout 3先快速检查一下端口是否开放HTTP服务。处理自签名证书内网很多HTTPS站点使用自签名证书。XRAY默认会验证证书导致连接失败。需要在config.yaml中设置mitm: ssl_insecure: true来跳过证书验证。5.3 常见问题与排查实录扫描速度极慢或卡住可能原因目标网站有无限循环的链接如日历控件触发了WAF或CC防护网络延迟大。排查查看XRAY实时输出或日志看它卡在哪个URL上。用–max-depth 3和–max-count 200先做限制扫描。检查目标服务器负载。爬虫爬到了授权范围外的网站可能原因restriction.includes配置错误或未配置目标页面有大量外链。解决立即停止扫描重新检查并收紧includes规则。这是最严重的安全合规问题。生成的HTML报告打开是空白或乱码可能原因报告文件路径包含中文或特殊字符生成过程中被中断。解决确保脚本中生成的文件名是安全的如我们之前用sed处理过。检查文件大小如果太小如几KB可能是扫描过程出错查看对应的JSON文件是否有内容。漏报问题认知必须清醒认识到自动化工具的漏报是必然的。爬虫模式无法触发需要复杂交互如拖拽、上传、多步骤状态转换的漏洞。定位爬虫模式的核心价值是“广度覆盖”和“发现常见漏洞”。对于关键业务系统必须在其基础上进行深度手工测试。误报问题处理XRAY的扫描结果尤其是中低危漏洞存在一定误报率。生成报告后需要安全工程师进行人工复核确认Triaging将确认的漏洞录入漏洞管理系统误报的则标记忽略。这个过程无法完全自动化。5.4 将流水线集成到工作流中一个成熟的流程不会止步于脚本。你可以考虑定时任务使用Linux的cron或Windows的计划任务每周或每月自动执行一次批量扫描。与资产管理系统联动编写脚本定期从CMDB拉取最新的Web资产列表更新targets.txt。结果自动推送扫描结束后脚本可以自动将聚合报告通过邮件发送给安全团队甚至通过企业微信/钉钉机器人发送一条摘要消息如“本次内网巡检完成扫描50个目标发现3个高危漏洞”。漏洞生命周期管理编写更复杂的解析脚本将XRAY的JSON结果自动转换为Jira、禅道等工单系统的任务或导入到OpenVAS、Nexpose等漏洞管理平台实现从发现到修复的闭环跟踪。这套基于XRAY爬虫模式的批量检测方案本质上是用自动化脚本将一个个孤立的工具能力串联起来形成适合自己工作环境的“生产力工具链”。它可能没有商业扫描器那么华丽的界面和全自动的管理但其高度的灵活性、可控性和近乎零的成本使得它成为许多安全团队进行常态化、广覆盖内网巡检的利器。