ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RuoYi框架安全攻防:从漏洞挖掘到加固实践

RuoYi框架安全攻防:从漏洞挖掘到加固实践 这套系统有个老版本部署特别多所以挖这类目标的时候第一件事就是判断版本。框架本身一直在更新但真正跑在公网上的大量还是停留在两三年以前的版本那批版本里的问题基本是明牌。2.1 先看懂攻击链路请求进来之后发生了什么一套ruoyi后端典型的请求链路是Nginx - Spring Boot应用 - Shiro/Spring Security过滤器链 - Controller - Service - MapperMyBatis- MySQL/Redis等存储组件。要挖漏洞就要在链路的每一环找可被操纵的点。有相当一部分注意力放在权限控制层。老版本用的是Apache Shiro新版本里有Spring Security版本两者的鉴权机制差别很大。Shiro那条线核心在ShiroConfig里配置的匿名URL和过滤器链顺序Spring Security那条线核心在SecurityConfig里对/login、/register、验证码接口这些白名单路径的放行方式。这里经常出现的低级问题就是开发为了让某个接口不被拦截直接加到anonymous或permitAll列表里结果这个接口本身是敏感接口比如查询全部用户、修改配置。还有一种很容易被忽视的情况是拦截器/注解的覆盖范围不一致。框架里接口权限用的是PreAuthorize(ss.hasPermi(system:user:list))这类注解但Controller层如果漏写注解而全局配置又没有兜底策略这个接口就变成了登录即可访问甚至未登录即可访问。我在实际测试里见过不少这类案例业务方为了省事在自定义Controller里直接调用SysUserService的敏感方法却没加任何权限注解。2.2 核心组件的老化程度Shiro之外的定时炸弹除开鉴权组件还有几个组件的高频问题值得关注Quartz定时任务框架自带定时任务管理页面允许管理员配置cron表达式、调用目标bean和方法。核心风险在于任务调用的目标是反射拼接的如果某个版本的配置校验不够严格就可以调用到一些危险类的危险方法。虽然这个功能需要管理员权限但配合越权或弱口令就能形成完整攻击链。更重要的是Quartz本身还涉及反序列化问题org.quartz.impl.jdbcjobstore如果用了JDBCJobStore且库里的QRTZ_JOB_DETAILS表能被通过SQL注入等方式写入恶意序列化数据那也是RCE不过这条链路的利用门槛比Shiro反序列化高不少。Druid监控页面框架带Druid数据库连接池druid.stat.view.servlet如果暴露出去未授权就能看到SQL监控、Session监控等敏感信息有时候还能直接看到内网地址。老版本里默认路径是/druid且部分部署连登录页都没配置。这不算多高级的漏洞但在SRC上报里属于有效信息CNVD也认。Redis新版配置里Redis密码是硬编码在application-druid.yml里的如果Redis端口暴露到公网、密码是弱口令攻击者可以通过Redis写文件或者Spring Session反序列化进一步控制应用。这类问题在部署不规范的目标里很常见虽然根因不在ruoyi框架本身但框架默认给你配好了用的人没有安全意识就白给了。2.3 代码生成器与在线用户管理被人忽视的信息泄露口框架自带的代码生成器tool/gen相关接口在老版本里是/tool/gen新版是/tool/gen基础上加了权限在默认情况下需要管理员权限但如果版本较老或权限校验缺失就可能未授权访问直接把数据表的字段结构、注释、实体类代码全部暴露出来。数据库表结构本身就是很有价值的信息表字段就是攻击者的地图。在线用户管理/monitor/online会展示当前登录用户的Session ID和登录IP如果这个接口未授权可访问攻击者可以直接强退他人会话甚至结合Session固定思路做进一步利用。这些点都不是拿shell级别的漏洞但它们是漏洞挖掘里很好的敲门砖能帮你快速积累对目标系统的认知判断后续往哪个方向深挖。3. 五类高频漏洞形态与触发逻辑下面结合我在授权测试和个人研究里的实际观察梳理五类在ruoyi里反复出现的高频漏洞。每一类我都说一下触发逻辑尽量不写具体利用代码重点讲怎么发现和判断因为防御方更需要的是识别能力。3.1 反序列化Shiro默认密钥与硬编码AES Key老版本ruoyi使用Shiro而Shiro的RememberMe功能使用了AES-CBC加密序列化数据密钥写在ShiroConfig里。框架历史上有一段时间用的是官方文档里的默认值fCq/xW489hGYDVHRVFcNQ不同版本有不同默认值很多部署根本没改。攻击者只要用这个密钥自己构造恶意序列化对象加密后放进Cookie服务器就会在反序列化时执行命令。这个漏洞的检测很简单请求/login时往Cookie里塞一个用默认密钥加密的序列化对象观察响应是否异常。修复方案就是生成随机Key升级Shiro版本新版框架已移除Shiro。我在实际测试中遇到最难缠的情况是目标改了默认Key但只改了这一个Keyorg.apache.shiro:shiro-core里的其他反序列化gadget链仍然存在只是没了入口。这种改了一半的情况很常见。新版框架如果迁移到了Spring Security这类漏洞就自然消失了但对应地会出现Spring Security自身的配置风险比如HttpSecurity.authorizeRequests()规则写错。3.2 定时任务表达式注入与危险调用Quartz定时任务模块在框架里叫定时任务页面里可以新建任务填写调用目标比如ryTask.ryParams和cron表达式。框架做了很多安全过滤比如限制包名前缀、校验cron表达式等但版本的演进过程中都有对应的绕过方式。我印象比较深的是某个版本里调用目标的类名过滤是基于黑名单的把javax.naming、org.apache.commons.collections这些常见的危险包给拦了但漏了JDK自带的com.sun.rowset.JdbcRowSetImplJNDI注入配合Spring Boot内置的Tomcat可以走ELProcessor表达式执行。修复方案也很简单把调用目标的解析改成白名单只允许调用预设的Service方法。从漏洞挖掘角度看这类型问题需要注意的前提是定时任务管理页面本身需要管理员权限。所以绝大多数情况下它的利用路径是先拿到管理员会话再通过定时任务getshell或者存在越权普通用户也能访问该接口。如果目标系统能未授权直接访问定时任务页面那价值就非常高了。3.3 文件上传后缀校验与路径穿越的组合拳框架自带的文件上传一般走/common/upload存储路径在配置文件里。这类漏洞的核心难点不在于能不能传而在于传上去之后能不能被解析成代码。漏洞挖掘里常见的问题是校验只防了后缀没防Content-Type或者校验了后缀但没防大小写.JSP、.PhP在被解析时可能因为Tomcat配置而被识别为jsp。上传接口对路径参数校验不严存在路径穿越可以把文件写到webapps/ROOT外的任意目录。上传后文件名用了原始文件名导致恶意文件直接落在静态资源目录下可访问。我在给一套自建系统做授权测试时遇到过ruoyi的上传接口本身没什么问题但业务方在代码里自定义了一个上传接口直接copy框架代码把校验逻辑删得只剩if (file.isEmpty())这就全白给了。3.4 SQL注入别只盯着MyBatis的${}MyBatis框架本身对#{}做了预编译所以注入点往往在${}拼接的地方比如排序字段、表名、IN语句参数、LIKE模糊搜索的拼接逻辑。ruoyi的BaseEntity里有params字段常用作查询条件比如params[beginTime]、params[dataScope]如果开发图省事直接在Mapper.xml里做了${params.dataScope}拼接立刻就是SQL注入。还有一类容易被忽略的是**druid监控页面的SQL日志**它本身不执行SQL但会展示连接池执行过的SQL文本如果页面未授权访问且前端没有对拼接内容做转义攻击者可以通过构造畸形参数让SQL日志里出现特殊内容虽然这不算SQL执行漏洞但会泄露业务数据接口。3.5 越权与未授权低危名称下的高影响力框架的自带功能里我建议重点看两个方向一是IDOR/水平越权。框架很多实体都继承了BaseEntity主键用的是自增ID或雪花ID自定义接口经常直接用前端传的ID去查询。比如/system/notice/notice/1可以查公告那改成/2、/3呢业务方如果不做数据权限过滤就是水平越权。二是垂直越权/未授权访问。框架提供了一堆/monitor/*、/tool/*开头的接口有些版本在配置匿名URL时把整个/monitor/**放行了里面的/monitor/online、/monitor/cache都能未授权访问。这些信息看似不痛不痒但能帮助进一步攻击。4. 授权范围内从零到一的完整挖掘流程接下来按实操顺序把整个挖掘流程走一遍。前提所有操作都在授权范围内进行最好有书面授权书遵守《网络安全法》及相关法规。4.1 指纹识别先确认它确实是ruoyi第一步永远是判断目标是不是ruoyi。有几种可靠的识别方式访问/login页面看HTML源码里有没有ry-logo、vue项目编译后的资源路径、#/login这类特征。请求/prod-api/前缀新版前后端分离默认路由前缀下的接口看响应头或错误信息。直接访问/druid/index.html如果返回200基本实锤是Java系且大概率ruoyi。登录页面的验证码接口GET /captchaImage返回一张base64图片和一个uuid这也是ruoyi的特征。查看/favicon.ico的MD5如果没被改网上已经有ruoyi默认图标的Hash库。判断完版本范围之后再去做下一步。4.2 API路径测绘把路由面拉出来老版本的前端页面和后端接口是分离的接口文档在/swagger-ui.html或/doc.htmlknife4j。如果这两个页面能访问那接口列表直接是白给下面的步骤都可以简化。如果文档被关闭了可以按下面的方式来测绘先确定接口前缀新版是/prod-api老版本有的用/有的自己配了server.servlet.context-path。使用常规的轻量级目录扫描工具比如dirsearch/ffuf字典里重点覆盖/system/user/list、/system/role/list、/tool/gen/list、/monitor/online/list、/common/download等框架常用路径。拦截器在响应header里可能泄露X-Requested-With: XMLHttpRequest也可作为判断接口是否为异步请求的辅助特征。测绘过程中我给个建议结合前端JS文件一起看。登录后把static/js目录下的app.js、chunk-*.js拉下来直接搜url:后面的字符串能拿到一版被注释掉的、被隐藏起来的接口列表这是纯黑盒目录扫描找不到的。4.3 验证与利用从可能到确定一个可疑接口确认漏洞通常需要三次请求未登录请求确认返回码若返回401或302说明有鉴权若返回200且带业务数据说明疑似未授权。带普通用户Token请求确认水平越权或垂直越权。针对具体漏洞类型的有效载荷请求比如SQL注入就构造成1 and 11与1 and 12看响应差异。这里要特别强调证据留存。完整记录请求包、响应包、时间戳这些是写报告、提交SRC时必须的材料。CNVD和SRC平台很看重可复现性你只写存在SQL注入是没有分量的得附上请求包、注入点、影响的表或payload示例注意脱敏。4.4 报告撰写决定漏洞能否落地报告的价值占整个漏洞挖掘工作的一半。一份好报告要讲清楚漏洞URL、参数、请求方法。影响的系统版本与组件版本便于修复方定位代码。完整的复现步骤截图或请求包。危害说明不浮夸也不贬低。修复建议尽量具体比如升级xx版本至x.x.x在ShiroConfig中将密钥改为随机值修改Druid监控页访问权限。提交SRC时漏洞等级判定主要看利用成本和影响范围。同样是Shiro反序列化如果目标在内网、无法访问分值和可利用性都有限如果直接暴露公网且能出网那就是严重。5. 我在实战中踩过的坑给你提个醒这部分内容是纯经验不写网上到处都是的东西只讲那些绕了很多弯路才明白的事情。5.1 版本差异导致的假阳性与假阴性有一次我测试一个目标时用老版本Shiro利用链打过去发现Cookie反序列化没有任何反应。我判断目标没有漏洞但后来仔细翻包发现目标根本没有优先加载Shiro的过滤器而是先被前端网关拦截了。也就是说目标系统可能套了一层其他代理我的payload根本没到后端。这种情况下报告写否就漏报了。反过来也有假阳性用扫描器扫出来某个接口疑似SQL注入但其实是该接口对畸形输入做了统一异常处理返回固定错误页面。所以所有自动扫描结果都必须手工复核这一步绝对不能省。5.2 开发环境与生产环境的版本漂移源码审计和在线测试对不上号的情况非常多。一套生产系统代码基于上游ruoyi二开但二开时把shiro.ini、application.yml改了很多甚至把某个功能模块从下游框架里抽出来重写了。这就导致你在Gitee上看的源码与目标实际情况完全两样。要避免这个问题尽量以在线行为观测为准源码分析只作为辅助判断。5.3 授权边界与测试范围保护自己才是第一要务很多做漏洞挖掘的新人容易忽略授权书里写的范围是哪个域名、哪些IP段、允许的时间窗口。有的目标因为业务联动会导致你访问到第三方系统比如CDN、OSS、第三方登录这些一旦越界麻烦非常大。我在实际操作中会用浏览器插件加一个当前测试目标的提示条看清域名才发请求同时所有非授权目标一律不碰。5.4 别把框架漏洞和业务漏洞混为一谈提交漏洞时尽量区分框架自身问题和业务方二开引入的问题。这两个的修复责任方不同前者是升级框架、打补丁后者是业务方在私有代码里改逻辑。有些SRC平台因为目标绑定的主体不同对两类漏洞的确认和打分差异很大。我在报告里会明确写该问题在框架默认配置下即存在或该问题由业务方自定义上传逻辑导致这样审核方省力自己也免得被驳回。6. 从防御视角看部署一套不好打的ruoyi要做哪些事如果你刚好是使用这套框架的运维或开发最后这部分是写给你们的。我在前面挖了这么多窟窿现在反过来给加固建议。6.1 版本升级是第一优先级框架的Gitee官方仓库持续在更新去掉了很多已知问题。别再守着老版本了。升级之前重点看两个东西数据库结构变化和配置项变化。老版本升到新版不只是替换jar包数据库里的sys_config、sys_menu可能会有增量数据菜单权限表也可能会变化升级前做好备份和测试环境演练。6.2 组件密钥与配置项的收敛逐一检查这些配置项ShiroConfig里的AES密钥如果用老版本改成随机生成长度至少16字节。Redis密码不要留空不要用123456最好用带特殊字符的长密码。druid.stat.view.servlet.enabled如果不需要监控页直接设为false需要的话加账号密码和IP白名单。application.yml里的server.servlet.session.timeout不要太长降低会话固定风险。6.3 网关/WAF层的防护不要只依赖框架自身的过滤器在Nginx层把该禁的路径先禁了对/druid/**、/swagger-ui.html、/v2/api-docs、/doc.html做访问限制或直接拒绝。自定义业务上传接口时尽量用对象存储OSS等别把文件落在本地web目录。配置限流防止登录接口被爆破登录接口加验证码框架自带这个功能一定要开启。6.4 日志与监控ruoyi自带/monitor/operlog和/monitor/logininfor能记录操作日志和登录日志。开启后能让你在攻击发生后的很短时间内发现问题。我在一次授权测试里刚扫完接口列表就在/monitor/operlog里看到了红字告警那是业务方自己接的日志系统弹出来的识别速度很快这也能看出来日志真正发挥作用时的价值。另外建议在Nginx层加一个“访问频率异常”的告警规则很多自动化攻击的特征就是短时间内大量请求不同的URL及时感知就能在漏洞被利用前切掉入口。写在最后把这套流程变成你自己的方法论这篇内容没有详细展开具体某个漏洞的完整利用路径因为公开环境下讨论利用细节的尺度需要克制而且脱离了授权场景讨论利用本身没有意义。我更希望传递的是一套“如何在合规前提下把一个开源框架的系统漏洞挖清楚、讲明白”的流程和思维。我自己在多年的测试里反复体会到的几件事拿出来共勉漏洞挖掘不是比谁工具多、跑的字典大而是比谁对系统原理理解更深。把框架生命周期、组件调用链、鉴权模型的底层逻辑吃透很多“看着没有漏洞”的系统其实到处是破绽。授权是底线报告是门面。一个漏洞无论多简单只要在授权范围内、报告写得清晰规范它就是有价值的成果反之没有授权的漏洞挖掘哪怕技术再炫也是害人害己。多关注上游更新和社区的通报很多漏洞不是“挖出来的”是“等出来的”。框架每次发版修复的问题往往就预示着同一个问题在所有运行实例里都还存在只是还没有人公开利用而已。如果你正准备入门漏洞挖掘拿ruoyi这套框架练手是很好的选择源码开放、案例丰富、社区活跃可以同时练习代码审计和黑盒测试。但记得在自己搭的靶场环境里练或者只针对有授权的目标安全这条红线什么时候都不能越。
返回列表