RuoYi4.7.0漏洞复现与保姆级代码审计

2024-12-20 6 0

漏洞复现

复现前准备:

1.在对应目录下创建一个1.txt,并随便写一些东西

2.你想下载哪个目录下的1.txt就更改ruoYiConfig.setProfile('C://Users//luche//Desktop//1.txt')里的格式

复现过程:

调用目标字符串:

ruoYiConfig.setProfile('c://1.txt')这里可更改为本地环境下的路径,例如我这里改为了ruoYiConfig.setProfile('C://Users//luche//Desktop//1.txt')就表示在该路径下,下载应用。

注意使用双反引号,因为单反引号可能会出错

cron表达式:

0/10 * * * * ?

最后访问下载地址:

http://127.0.0.1:88/common/download/resource?resource=C://1.txt

即可成功下载文件

代码审计

接下来我们进入代码审计的环节,我将一句一句的解析每一段代码,尽量保证每个人都能看懂。因为我

自己本身就是一个小白。所以更懂大家。

首先找到该页面的接口调用代码

从代码的层面可以看到,只有当if (!FileUtils.checkAllowDownload(resource))为不为true的时候才会进入到下载的方法。

我们首先传入的值,是传入到String resource。其他两个值可以不用管

那么我们进入FileUtils.checkAllowDownload,查看如何满足条件

通过方法追踪,成功找到该方法

注意前面方法中的逻辑是:if (!FileUtils.checkAllowDownload(resource)),if中有反逻辑号。所以当FileUtils.checkAllowDownload(resource)

返回为false的时候,其实是执行语句,也就是不允许下载。

那我们回到checkAllowDownload()方法中

只有当true的时候才可以下载目录。我们将这段代码解释一下,都写上注释了。

可以看到if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))是关键,只有当这个判断返回true,才可以下载。

那么我们进入到ArrayUtils.contains中的两个参数去查看具体的代码

那么我们进入到两个变量去查看

MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION

FileTypeUtils.getFileType(resource)

这里查看public static String getFileType(String fileName)的代码片段

通过MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION方法看到,可以任意下载的文件有图片、压缩文件、pdf、视频、word等。

那么举一反三,其实这个漏洞不仅仅是下载txt文件,想下载其他文件也可以通过该漏洞。

但也侧面说明了,该漏洞并不是任意文件下载,此任意文件下载还是有限制的。

细心的朋友可能已经发现FileTypeUtils类中,有两个一样名称的方法

这里涉及到一个JAVA的特性

方法重载

1.方法重载允许一个类中定义多个方法,方法名相同,但它们的参数列表必须不同(可以是参数的数               量、类型,或者顺序不同)。

2.当调用这些方法时,Java 编译器会根据传入的参数类型或数量来选择调用哪个重载的方法。

在这里,一个接受 File 对象,另一个接受 String 类型的文件名。

根据传入参数的类型,Java 编译器会自动选择调用哪个方法。

那在这个地方,我们传入的是什么?回到传入变量的地方,接口的地方,很明显,我们传入的是字符串类型

所以要关注的方法只有下面的这个

我们给这段方法加上注释

那么逻辑的很清晰了

假如我们要下载一个1.txt的文件,首先传入resourceDownload()函数中,然后将变量resource传入FileUtils.checkAllowDownload()中。

接着在checkAllowDownload()函数中判断是否可以下载文件【if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))】语句,那么变量就会进入FileTypeUtils.getFileType()函数中。

在该函数中成功传入getFileType(String fileName)函数中,通过语句判断,将传入的变量名如1.txt,的扩展名txt提取出来。

提取完成后,回到【if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))】返回true

返回true后成功跳过if (!FileUtils.checkAllowDownload(resource))该if语句判断

至此,我们终于过了第一个流程

此流程我们得到的情报有:

首先路径不能包含 .. 因为这样会进入到下载失败的判断

第二 能下载的文件只有DEFAULT_ALLOWED_EXTENSION数组中的,否则下载失败

// 图片

"bmp", "gif", "jpg", "jpeg", "png",

// word excel powerpoint

"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",

// 压缩文件

"rar", "zip", "gz", "bz2",

// 视频格式

"mp4", "avi", "rmvb",

// pdf

"pdf" };

第三传入的文件名一定要带 . 例如:1.txt,如果是1txt则会下载失败,原因是这段代码

那么进入下一个代码

跟进代码RuoYiConfig.getProfile();

注意下面这个函数,这是漏洞造成的重要原因

查看这个变量哪里来的

看到是声明的一个静态变量,继续看这个变量哪里来的

噢,原来是使用的Sprint Boot得到的,内部的一个函数,我们无法更改,有兴趣可以详细搜搜看。

根据注释,那么这个变量应该在application.yml中。(值得注意的是,这里是一个伏笔,漏洞成因可不是

获取这里的profile值。)

果然在这

所以profile = D:/ruoyi/uploadPath

那么我继续进入到下一个函数,

解释一下这串代码的意思

那么我们进入到Constants.RESOURCE_PREFIX里面去看

所以代码逻辑是,最终得到String downloadPath= D:/ruoyi/uploadPathC://1.txt

StringUtils.substringAfter函数逻辑在这,像这类方法都是固定的,就是无法更改的。所以只需要记录作用即可。

我们继续看下一行代码,作用已经写明,所以dowloadName最后返回的是1.txt

StringUtils.substringAfterLast函数在这里

那么到此为止,这个流程就走完了,最后三段是下载代码,不会对结果产生什么影响。所以可以不用管他。

漏洞成因

那么整个流程我们重新梳理一下重要节点

1.if (!FileUtils.checkAllowDownload(resource)),这里判断文件类型,是否为合法类型,且对..进行了检测,防止目录遍历进行下载

2.String localPath = RuoYiConfig.getProfile();获取了profile值,此值是静态值,本来是固定好的,但由于public void setProfile(String profile)

方法的存在,导致漏洞形成(具体原因在后面篇幅)

其实整个漏洞的成因就以上两个原因问题

1.文件合法类型过于多了,造成我们可以遍历名称,下载各种方法。

2.由于public void setProfile(String profile)函数的存在,导致我们可以任意控制目录,最终造成可以下载目标服务器的任意文件

漏洞复现--代码层面

那我们以代码的视角走一遍吧

走代码之前,将明白public void setProfile(String profile)为什么是造成漏洞的原因

你看这个调用,是不是就是调用了setProfile函数,而这个函数的作用也很简单,就是给profile赋值,也就是现在profile的值为:

C://Users//luche//Desktop//1.txt了。

说明以后我们就以代码的视角复现一下这个漏洞吧

使用payload:http://127.0.0.1:88/common/download/resource?resource=C://1.txt

首先传入resource为C://1.txt

然后成功没有..且在白名单内,所以成功进入下一个方法

下一个方法通过刚刚我们说的public void setProfile(String profile)给予了profile值为C://Users//luche//Desktop//1.txt所以localPath

的值就是profile

带着这个值进入下一个方法

可以看到经过提取,最后dowloadPath的值为C://Users//luche//Desktop//1.txt

带着这个值我们继续往下走

最后成功下载对应的值文件。

至此这段代码审计便是完结了。第一次写文章,有写的不明白的地方请多多指教。

自我总结

当然有两坑没有解释:

1.为什么定时任务的设定可以影响到profile赋值,这个我还没弄明白,下一篇可以补充

2.为什么String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);

localPath的值是C://Users//luche//Desktop//1.txt

StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);的值是1.txt

那么他们相加不应该是C://Users//luche//Desktop//1.txt1.txt吗?为什么最后downloadPath的值是C://Users//luche//Desktop//1.txt

只能等我解决再讲了。

郑重声明,因为是第一次进行java的代码审计,全程都是靠chatgpt一边翻译理解一边审计的,所以可能很多东西表达是不规范的,错误的。希望各位佬多给点意见进行改正吧,希望大家都能早日成为白盒的黑阔高手。


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

Matildapp:针对Web 3.0环境的网络安全与渗透测试框架
Jumpserver_decrypto: 解密 Jumpserver ssh配置的开源工具
向日葵远程控制软件远程代码执行漏洞复现(CNVD-2022-10270, CNVD-2022-03672)
Kafka UI三大RCE高危漏洞分析
PbootCMS V3.2.9前台SQL注入漏洞(上)
修复秘籍:如何有效应对CVE-2024-20767和CVE-2024-21216漏洞

发布评论