从代码审计的角度分析 Ruoyi v4.7.6 的任意文件下载漏洞

news2024/11/28 4:34:52

前言

Ruoyi 的 v4.7.6 是 2022 年 12 月 16 日发布的一个版本,而任意文件下载漏洞实际上 12 月底的时候就已经爆出了,也陆续有一些文章在写这个漏洞,但是 Ruoyi 一直没有更新修复。

上月中旬(2023 年 5 月),Ruoyi 更新了 v4.7.7 版本,通过加固了白名单限制,修复了该漏洞。
记得及时更新昂!

Ruoyi v4.7.7

更新日志:v4.7.7

更新之后,可以看到任意文件下载的 payload 已经被限制

在这里插入图片描述

Ruoyi v4.7.6 任意文件下载漏洞复现

代码下载&部署

  • 贴上 v4.7.6 版本的链接:Ruoyi v4.7.6

运行 Ruoyi,新建/修改定时任务

ruoYiConfig.setProfile("D:\\")
在这里插入图片描述

看一下我 D 盘下的文件,以这个 123.txt为例
在这里插入图片描述

手动触发定时任务

在这里插入图片描述

访问 common/download/resource 接口获取文件

http://localhost:8081/common/download/resource?resource=/profile/123.txt
关于为什么要访问这个 url,文件名前为什么要加 /profile/ 后面也会有详解
在这里插入图片描述

Ruoyi 的漏洞史

这里主要针对本次这个任意文件下载漏洞来说。
实际上这个漏洞,并不是 v4.7.5 … v4.7.6 的过程中出现的,它其实很早之前就出现了。

Ruoyi 的定时任务功能在最初上线不久就被爆出了远程代码执行漏洞
后期进行过多次修复

  • v4.6.2 — 定时任务屏蔽 rmi 远程调用
  • v4.7.0 — 定时任务屏蔽 ldap 远程调用; 定时任务屏蔽 http(s) 远程调用
  • v4.7.1 — 定时任务屏蔽违规字符
  • v4.7.3 — 定时任务目标字符串验证包名白名单;定时任务屏蔽违规的字符
  • v4.7.4 — 定时任务检查 Bean 包名是否为白名单配置
  • v4.7.6 — 定时任务违规的字符

从代码审计的角度来看漏洞是如何被发现的

本次漏洞的爆发点其实还是在【定时任务】与【文件下载】功能,根本原因还是定时任务违规字符校验不完善,被绕过的问题。

  1. 先了解一下 Ruoyi 定时任务功能的作用和原理。

    • Ruoyi 默认提供了三个定时任务的示例(红框中的三个)。分别调用目标字符串 ryTask.ryNoParamsryTask.ryParams('ry')ryTask.ryMultipleParams('ry', true, 2000L, 316.50D, 100)
      在这里插入图片描述
    • 这三个调用字符串,特征很明显,分别在调用一个对象的无参方法有参方法多参方法
  2. 在源码中找到 ryTask 这个对象进行确认(在 idea 中直接连按两次 shift 搜索 ryTask 即可找到)
    在这里插入图片描述

  3. 尝试点击【执行一次】,发现控制台中成功输出内容,说明方法被正确调用
    在这里插入图片描述

  4. 这里简单科普一下这个 @Component("ryTask") 是什么,为什么可以通过 ryTask.xxx 调用这个方法?

    @ComponentJava Spring 中的一个注解,其作用就是定义 Spring 管理类,简而言之就是,被 @Component 注解标记的类,将交给 Spring 框架来自动管理。
    Web 开发过程中最常见的 @Controller@Service@Repository@Configuration 等等其实都是 @Component 的扩展。
    @Component("ryTask") 括号中的 ryTask 是定义的 Bean 的 id,如果不写的话,默认是短类名(类名首字母小写)

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
        @AliasFor(
            annotation = Component.class
        )
        String value() default "";
    }
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Configuration {
        @AliasFor(
            annotation = Component.class
        )
        String value() default "";
    
        boolean proxyBeanMethods() default true;
    }
    
  5. 看到这儿,就会萌生出一个大胆的猜测,是否可以利用【定时任务】调用任意被 @Controller@Component@Configuration 等注解标记的接口呢?

  6. 创建一个测试类,用 @Controller 注解标记尝试一下(修改完代码要重启服务)

    @Controller
    public class JobTest {
        public String hello(String words) {
            System.out.println("hello" + words);	// 在这里打个断点试试
            return words;
        }
    }
    
  7. 添加定时任意,尝试调用测试类
    在这里插入图片描述
    在这里插入图片描述
    进入了断点,并成功输出了 helloruoyi,由此验证,上面的猜想是正确的
    在这里插入图片描述

  8. 走读代码,整理出那些被 @Component 注解及其扩展注解标记的类,并且可能涉及到配置、越权、非公开方法之类的接口

    为什么主要关注 配置、越权、非公开方法 这三类呢?
    因为正常的接口本身就是有权限的,即使可以从这里调用执行,从安全角度讲,也没有很大的意义。
    而这三类就不一样了(主要是这三类,不代表只有这三类

    1. 配置文件是涉及到全局,如果被调用影响到,很可能会影响到其他用户,就会存在风险;
    2. 还有某些涉及到权限管控的接口,从这个定时任务这个入口调用,就有可能绕过原本的鉴权;
    3. 非公开的接口,简单举个例子,有些接口,可能不在 @Controller 中,那么就无法通过正常的 HTTP 请求从 Web 端去调用,但是却可以通过这里的定时任务间接调用执行,从而造成风险。

    相关的配置接口,还是挺多的,就不全部粘贴了,感兴趣的可以自己去整理一下试试玩儿,或许还有漏洞呢。
    这里就先贴出本次要讨论的这个漏洞相关的配置 —— 全局配置类 RuoYiConfig.java
    全局配置类共有 6 个 set 方法,本次漏洞利用的就是 setProfile 方法

    // 全局配置
    ruoYiConfig.setName(String name)
    ruoYiConfig.setVersion(String version)
    ruoYiConfig.setCopyrightYear(String copyrightYear)
    ruoYiConfig.setDemoEnabled(String demoEnabled)
    ruoYiConfig.setProfile(String profile)
    ruoYiConfig.setAddressEnabled(String addressEnabled)
    
  9. ruoYiConfig.setProfile 的作用

    setProfile 方法和 profile 属性,以及配置文件中的 ruoyi.profile 的关系,就不多说了,这些属于 Java 基础

    从方法内的注释结合配置文件中的注释,不难看出,profile 实际上是系统中文件的保存路径。
    Windows 下的默认值是 D:/ruoyi/uploadPathLinux 下的默认值是 /home/ruoyi/uploadPath
    在这里插入图片描述
    在这里插入图片描述

  10. 文件保存的默认目录可以被修改,那,被修改之后呢?还需要找一个访问这个目录下内容的方法。

    走读代码,在 CommonController.java 中,找到一个 resourceDownload 的方法

    在这里插入图片描述

    该方法内,先是进行了非法路径的检查

    在这里插入图片描述
    话说,这个目录穿越的检查,只检查 .. 符号,怎么感觉能绕过呢?
    在这里插入图片描述
    同时里面还有一个白名单(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)校验
    在这里插入图片描述

    然后执行 RuoYiConfig.getProfile()RuoYiConfig 中获取了 Profile 的值,并与传入的资源名称进行组合形成完整路径后进行下载。完美~~~

    在这里插入图片描述

  11. 至此,万事俱备,开始整活儿

  • 按照前 9 步的分析,我目前测试机是 Windows 机器,所以编写 payloadruoYiConfig.setProfile("D:\\"),尝试将文件默认路径设置为 D 盘根目录
    在这里插入图片描述

  • 点击执行,手动触发定时任务
    在这里插入图片描述

  • 构造下载链接,访问 D 盘中的资源

    String localPath = RuoYiConfig.getProfile();	// 刚才被篡改的地址。  现在应该是   D://
    String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
    

    Constans.RESOURCE_PREFIX 的值如下:

    /**
     * 资源映射路径 前缀
     */
    public static final String RESOURCE_PREFIX = "/profile";
    

    StringUtils.substringAfter 方法的源码如下:

    public static String substringAfter(String str, String separator) {
            if (isEmpty(str)) {
                return str;
            } else if (separator == null) {
                return "";
            } else {
            	// 从传入的路径中获取到分隔符 /profile 的位置
                int pos = str.indexOf(separator);	
                // 截取 /profile 所在位置的后面的内容。例如  /profile/1.txt  被截取之后就是 /1.txt
                return pos == -1 ? "" : str.substring(pos + separator.length());	
            }
        }
    

    所以,如果想下载 D://123.txt,那么最终构造的 url 就应该是

    http://localhost:8081/common/download/resource?resource=/profile/123.txt

  • 下载成功
    在这里插入图片描述

漏洞修复

截止发文日(2023.05.25),Ruoyi 官方已经于 2023.4.14 日针对 v4.7.6 版本的任意文件下载漏洞进行了修复。

在这里插入图片描述
通过Compare v4.7.7 和 v4.7.6 的代码变动情况,可以看出,官方的修复方案如下:
在这里插入图片描述
尝试在 v4.7.7 版本中复现,结果被成功拦截

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/572990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内网渗透(八十四)之ADCS配置启用基于SSL的LDAP(LDAPS)

ADCS配置启用基于SSL的LDAP(LDAPS) 打开AD CS,选择证书颁发机构 选择证书模板,右键管理 选择Kerberos身份验证,右键 复制模板 然后会有一个Kerberos身份验证的副本,右键更改名称,更改为LDAPS 选择LDAPS,右键属性 设置模板属性,请求处理——>允许导出私钥(O) 创建证书…

最快实现一个自己的扫地机

​ 作者:良知犹存 转载授权以及围观:欢迎关注微信公众号:羽林君 或者添加作者个人微信:become_me 扫地机介绍 扫地机器人行业本质是技术驱动型行业,产品围绕导航系统的升级成为行业发展的主旋律。按功能划分&a…

【武汉万象奥科】瑞芯微RK3568芯片

▎产品展示 RK3568核心板是基于Rockchip的RK3568设计的一款高性能核心板。该处理器集成了最新的高性能CPU、GPU,并拥有丰富的接口,非常适用于工业自动化控制、人机界面、中小型医疗分析器、电力等多种行业应用。 ▎RK3568产品特点 ▎高性能处理器 ○ 采用…

linuxOPS基础_vmware虚拟机安装及介绍

虚拟机概念 什么是虚拟机? 虚拟机,有些时候想模拟出一个真实的电脑环境,碍于使用真机安装代价太大,因此而诞生的一款可以模拟操作系统运行的软件。 虚拟机目前有2 个比较有名的产品:vmware 出品的vmware workstatio…

pix2pixHD---model---辨别器

搭建完生成器后搭建辨别器。 首先看辨别器的输入:分别是标签和生成器输出。 在训练时候,辨别器通道输入等于生成器的输出加上conditional即标签和实例的拼接。通道相加就是图片concat。 如果使用实例图片,那么辨别器输入通道数加1&#xff…

《Spring Guides系列学习》guide21 - guide25

要想全面快速学习Spring的内容,最好的方法肯定是先去Spring官网去查阅文档,在Spring官网中找到了适合新手了解的官网Guides,一共68篇,打算全部过一遍,能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gu…

这款高性价比商用笔记本值得入手

随话说:工欲善其事,必先利其器。 对于打工人的我来说,办公一定要有一款适合的笔记本,否则真的是事倍功半。近日入手了戴尔Latitude 3330这款笔记本,通过使用体验,感觉真是一款高性价比的笔记本了。 接下来…

分布式事务解决方案Seata 整合 Spring Cloud + Nacos

1. 简介 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 2. Docker 安装 Seata 2.1 下载镜像 docker pull seataio/se…

电子合同网页预览盖章效果实现

电子合同在现在应用越来越广,需求也就随之产生。 本篇文章主要记录两种网页盖章效果实现方式,自己记录一下, 也给需要的人提供一点思路和帮助。 效果 JqueryCSS实现 原理 通过定位盖章位置,之后操作图片悬浮到盖章位置 1.设置…

浙江大学计算机考研分析

关注我们的微信公众号 姚哥计算机考研 更多详情欢迎咨询 浙江大学(A)考研难度(☆☆☆☆☆☆) 浙江大学计算机科学与技术学院成立于1978年,始终秉承“人为本,和为贵,变则通”的文化理念&#…

SecureCRT日志设置每行时间

SecureCRT日志设置时针对每个会话单独设置的 下图两个串口打印的地方,每个是一个会话。 打开【选项】 按照如下选项进行配置: 每次断开重新链接都会重新存一个日志文件,文件生成时间以秒为最小单位。 并且每行都有时间记录。 一般使用”年…

聊聊得物数据研发优化策略 | 精选

1.前言 在离线数据研发中,随着业务的快速发展以及业务复杂度的不断提高,数据量的不断增长,尤其得物这种业务的高速增长,必然带来数据逻辑复杂度的提升,数据量越大,复杂度越高,对任务的性能的要…

【嵌入式Linux】源码菜单配置 | 编译 | 菜单配置的实现 | 源码编译的实现

源码配置编译 源码配置编译,要把中间各个环节都理清楚 厂商把自己增加的东西专门放了个文件独立,方便开发者发现变化 1.菜单配置 移植的第一步,就是选配,通过make menuconfig图形化界面选配 //载入配置 $ make ARCHarm64 tegra_defconfi…

JVM(HotSpot)

1、 类加载机制: 引导类(Bootstrap )加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如 rt.jar、charsets.jar等扩展类(Extension )加载器:负责加载支撑JVM运行的位于…

真题详解(哈希表)-软件设计(八十五)

真题详解(树的结点)-软件设计(八十四)https://blog.csdn.net/ke1ying/article/details/130869095 要求邮件加密方式传输,邮件最大附件内容可达500MB,发送者不可抵赖,若邮件被第三方截获,第三方…

有哪些pdf转word的免费软件?这个办法值得一试

在日常工作和学习中,我们经常需要将PDF文件转换为Word文档。尤其是在需要编辑PDF文档中的内容时,将其转换为Word文档是非常必要的。但是,很多人不知道该如何快速完成这项任务。在本文中,我们将介绍一些简单的转换方式,…

智能排班系统 【管理系统功能、操作说明——上篇】

文章目录 功能设计共有功能系统管理员企业管理员门店管理员门店员工 页面与功能展示用户登录企业注册系统首页系统管理员首页企业管理员首页门店管理员首页 个人中心菜单管理日志管理登录日志 功能设计 不同的角色关注的任务和功能不同,针对不同的角色,…

树莓派485转USB串口调试教程

步骤1:接线方式:485转USB 注意接线口是否对应:A1B1 步骤2:查看串口配置—映射关系是否正确 命令:ls -l /dev serial0即GPIO映射的串口,默认是ttyS0,即mini串口 serial1即板载蓝牙映射的串口&am…

人工智能(Pytorch)搭建模型7-改造后的新型RegNet设计空间模型的搭建与训练

大家好,我是微学AI,今天给大家带来人工智能(Pytorch)搭建模型7-新型的卷积神经网络RegNet模型的搭建与训练,RegNet是一种新颖的卷积神经网络架构,它的设计理念是通过稀疏网络结构和精细的正则化来实现高效的计算和更好的泛化能力。…

小白看了也会的Redux编程

目录 介绍 演示 异步action react-redux 多组件管理的react-redux 扩展 介绍 redux是专门用于集中式管理状态的javascript库,并不是react的插件库。 比如你有多个组件A-E都想要用同一个组件D中的状态: 1)像以前我们可以通过父子组件通…