环境:
JDK 8u202
MySQL 5.5.29
RuoYi 4.7.6
参考公众号
https://mp.weixin.qq.com/s/IrqLp2Z3c941NiN0fFcDMA

这是一个最新版漏洞

其中关键请求需要3个(新增计划任务、执行计划任务、下文文件),没有给出内部实现关键信息,尝试审计

首先去官网下载最新版本

选择最新版本

解压并部署,只需配置好mysql数据库即可

导入sql数据

springboot启动!

看一下登录密码,先去登录界面

默认账户密码已经填写好了,输入验证码即可登录

找到定时任务

尝试一下默认计划任务,点击编辑,查看该功能的作用

发现计划任务可以调用bean或以包全称调用方法

执行一次试试

发现终端有输出

找到调用 ryTask.ryParams('ry') 的 bean

所以计划任务是可以直接调用bean并执行对应的方法的,那返回看公众号内发的请求,发现跟换指定的bean
、
去查看一下指定 ruoYiConfig 的 bean 中 setProfile 方法的作用

发现修改的是当前类属性

是一个上传路径

那一般情况下,上传路径都是在配置文件中提前配置好的,找到配置文件,发现默认是 D 盘的某目录下

回到计划任务页面,添加一个新任务

填写好对应参数,修改成我们要下载的文件地址,cron表示式按照原有的测试计划任务模板填写即可

提交,追踪请求,发现提交到 /monitor/job/add 路径下

追踪请求链

发现有很多过滤

最重要的是最后的黑白名单过滤,打断点

进入第一个黑名单判断

这里的 JOB_ERROR_STR 是黑名单列表

跟进到 containsAnyIgnoreCase 方法,发现只是对字符串进行黑名单判断,未作修改

继续跟进到下一个白名单判断

方法里面首先将传入的值进行了拆分,拆分后的值准备通过 getBean 的方式转换为 bean

这里成获取到对象,将转换为bean的对象再进行白名单检测

跟进 containsAuyIgnoreCase 方法,这里是将对象包名传了进来,用来判断调用的是不是顶级包下的对象

这里成功绕过,返回 true 绕过判断,进入到 service 层

发现只是将请求保存到了数据库

回到 计划任务页面,发现新增 Test 计划任务 成功

之前正常流程是需要执行一次计划任务,就会调用对应bean的方法,这里执行一次 Test 计划任务

发现请求到 /monitor/job/run 路径下
找到该路径

并打上断点,跟进到服务层

进入到服务层,首先通过ID取出之前存入的对象

跳到下一个断点,发现这里实际执行的是 StdScheduler 类的 triggerJob 方法

找到这个方法,发现是第三方包 quaryz 2.3.2 版本

去 google 查找到一下这个第三方包的文档,看实现的是什么功能,找到官方文档
https://javadoc.io/doc/org.quartz-scheduler/quartz/latest/index.html

就是以代理的方式去执行类的方法

执行成功,这里在完成最后一步操作,根据公众号发送的最后一个包,去请求文件

尝试访问,下载成功(这里这个文件实际存放在 C://Users/Test01/Desktop/target.txt ,之前由于我的环境没有E盘,所以前面的计划任务传参都要改成C盘,重新编辑计划任务后再执行一次即可,然后再下载)

但为什么这里要传 info.xml:.zip 呢,跟进到请求地址 /common/download/resource

这里有过滤,打上断点,进入一个判断

跟进 checkAllowDownload 方法,这里进行 .. 过滤,还进行了后缀名过滤

查看 DEFAULT_ALLOWED_EXTENSION 后缀名白名单有哪些

这里的匹配规则是取最后一个 . 的后缀,所以取得 zip 去比较,在范围内,绕过白名单


回到最上层方法,这里通过 RouYiConfig.getProfile() 获取我们之前计划任务修改的地址,也就是 C盘的指定地址
然后在通过 StringUtils.substringAfter() 拼接 路径 和 文件名

跟进 substringAfter 方法,这里做了文件名判断,判断是否包含 / profile 路径名称,找不到对应路径所以返回 -1,所以返回为空

所以和空拼接后根据路径没有变化

然后以最后一个 / 符号拆分出来文件名字
然后跟进 writeBytes 方法,其实该方法就是去请求 downloadPath 中对应的文件路径,并写入到 reponse 中并返回给用户

进入 write Bytes 方法,请求文件,并以 Stream 流的方式写入到 os 中,os 就是 reponse 用于返回给前端用户。

所以这里的请求只需要绕过白名单即可,请求文件名即可以是 xxx.html、yyy.ppt、zzz.mp4,便可绕过白名单判断,并绕过文件名的路径判断,返回为空后去拼接根目录,便完成任意文件下载漏洞。
更改路径名称一样也能访问该文件

芜湖完工!
总结:这种漏洞不可能通过黑盒测试出来,只能通过白盒测试,并且需要对站点代码和组件使用非常熟悉,才能通过代码审计的方式挖掘此洞。
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A