当前位置:   article > 正文

Java代码审计&Mybatis注入&文件上传&下载&读取_若依 java审计

若依 java审计

目录

0x00 前言

0x01 Mybatis注入审计 - 若依(Ruoyi)后台管理系统 4.6.0

1、项目介绍与部署 - Ruoyi

2、若依 Ruoyi - Mybatis注入 - 代码审计

3、代审常搜词 - Java SQL 注入

0x02 文件上传漏洞审计 - Inxedu && Tmall

1、项目介绍与部署 - Inxedu && Tmall

2、Inxedu - 前台文件上传 - 代码审计

3、Tmall - 后台文件上传 - 代码审计

0x03 文件下载漏洞审计 - 若依(Ruoyi)后台管理系统 4.5.0

1、项目介绍与部署

2、若依 Ruoyi - 文件下载 - 代码审计

0x04 文件读取漏洞审计 - Oasys

1、项目介绍与部署

2、Oasys - 文件读取 - 代码审计

3、代审常搜词 - 文件上传&下载&读取


0x00 前言

希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢! 

个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog

0x01 Mybatis注入审计 - 若依(Ruoyi)后台管理系统 4.6.0

1、项目介绍与部署 - Ruoyi

若依(Ruoyi)是一个开源的后台管理系统,可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。

版本:RuoYi-v4.6.0

项目部署:

  • 修改 application-druid.yml 中的数据库连接密码,在 application.yml 中可修改服务器默认端口(默认 80)
  • 创建名为 ry 的数据库,导入 quartz.sql、ry_20201214.sql 两个 SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/admin123

2、若依 Ruoyi - Mybatis注入 - 代码审计

2.1、明确项目框架及使用组件

首先要做的是明确项目的框架以及有没有用到 Mybatis 组件,当看到 controller、service、mapper 推测项目为 Spring 框架搭建

并且,在 External Libraries 看到项目有用到 Mybatis 和 Spring 相关组件,更加确定了我们的想法。

2.2、Mapper->Service->Controller->得到Mapping路由信息

我之前的文章提到 Mybatis 下的 SQL 注入有 3 种: order by 注入、搜索框 like 注入、in 之后多个参数的注入

总的来说,要找 Mybatis 注入点只需要全局搜索含有 ${ 的 Mapper 文件即可,全局搜索快捷键:Ctrl+Shift+F

选择跟进 SysDeptMapper.xml,很明显这里存在 in 的注入

来到 SysDeptMapper.xml,由 SQL 语句得知是与更新相关的操作,并且得知可控变量为 ${ancestors}。

Ctrl+左键点击 updateDeptStatus 跟进到 SysDeptMapper.java 可以看到该 Mapper 方法的声明,看到其传入了一个 SysDept 类。

Ctrl+左键点击 SysDept,跟进到该类得知其含有名为 ancestors 的成员变量,于是便知晓了 SysDeptMapper.xml 里可控变量 ${ancestors} 就是 SysDept 类的成员变量。

选中 updateDeptStatus - 右键 - Find Usages,在 Unclassified 下面定位到引用 updateDeptStatus 的文件,得知该文件为 SysDeptServiceImpl.java。

而 SysDeptServiceImpl.java 是一个 Service 层的文件,如果想要知道漏洞功能点的路由信息要到 Controller 层去找,所以还要继续跟进 updateParentDeptStatus(同样 Find Usages)

于是跟进到了 SysDeptServiceImpl.java,很明显这还是 Service 层的文件,同样的方法继续跟进。

最终跟进到了 SysDeptController.java,这才是我们需要的 Controller 层的文件,可以得知以下信息:

  • 该功能点为部门管理相关操作,由注释"保存"推测大概率为编辑功能
  • 结合上下代码,得知完整 Mapping 路由为:/system/dept/edit
  • 由 PostMapping 知,提交方式为 POST
  • 前端会传入一个 SysDept 类的对象 dept,得知注入点为 dept.ancestors,也就是在 POST 请求体里的 ancestors 字段写入 Payload

2.3、漏洞验证 - Ruoyi Mybatis 注入

因为该功能点提交方式为 POST,所以如果直接访问 /system/dept/edit 是不行的,这里根据之前得知的信息,我们可以定位到部门管理的编辑操作。

打开 Burp 抓包,填写好编辑的信息并提交,找到 URL 为 /system/dept/edit 的数据包,发送到 Repeater 模块。

发现 POST 请求体里没有 ancestors 字段,于是尝试将 POST 请求体替换为以下 POC。

  1. POC:
  2. DeptName=1&DeptId=100&ParentId=12&Status=0&OrderNum=1&ancestors=0)or(extractvalue(1,concat((select user()))));#

在 Response 里观察到 @localhost,说明确实存在注入,漏洞验证成功。

3、代审常搜词 - Java SQL 注入
  1. Statement
  2. createStatement
  3. PrepareStatement
  4. like '%${
  5. in(${
  6. in (${
  7. select
  8. update
  9. insert
  10. delete
  11. ${
  12. order by
  13. setObject(
  14. setInt(
  15. setString(
  16. setSQLXML(
  17. createQuery(
  18. createSQLQuery(
  19. createNativeQuery
  20. .......

0x02 文件上传漏洞审计 - Inxedu && Tmall

1、项目介绍与部署 - Inxedu && Tmall

项目介绍:因酷时代 Inxedu 在线教育系统 V2.0.6 是一个开源的网校项目,Tmall 是一个模拟天猫购物的项目,在我之前的文章里有提到过(SpringBoot安全&Mybatis注入&Actuator泄露&Swagger自动化 – CH4SER的个人BLOG

Inxedu V2.0.6 部署:

  • IDEA 打开 demo_inxedu_open,选择 Maven Project
  • 修改 project.properties 中的 username、password、host(数据库主机地址)
  • 导入 SQL 文件 demo_inxedu_v2_0_open.sql 执行(高版本 MySQL 会出错,我用的 MySQL 5.2.17)
  • Add Configurations - Tomcat Server - 选择 Local(Remote 应该也可以)
  • Tomcat 9.0.80 - Edit Configurations - Server - 修改 HTTP port 和 URL 为 82(默认),点击弹出来的 Fix 按钮
  • Tomcat 9.0.80 - Edit Configurations - Deployment - 设置 Application context 为 / (和配置文件里的项目路径保持一致)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/111111,某普通学员账号 lmx193@162.com/123456

Tmall 部署:

  • 修改 application.properties 数据库连接配置(使用 MySQL 5.7.26)
  • 创建数据库 tmalldemodb,导入 SQL 文件 tmalldemodb.sql 执行
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/123456,某普通用户账号 MRJIANG/123456
  • 前台地址:http://localhost:8088/tmall
  • 后台地址:http://localhost:8088/tmall/admin

2、Inxedu - 前台文件上传 - 代码审计

2.1、审计思路:

寻找并测试文件上传功能点,抓包得到对应路由等信息,从而定位到功能实现的具体代码(代码溯源),然后审计其是否存在漏洞。

2.2、审计流程

登录学员账号 - 个人资料设置 - 个人头像,尝试上传头像同时 BurpSuite 抓包,得到上传头像路由信息为 "/image/gok4","fileType=jpg,gif,png,jpeg"

在项目代码中全局搜索 "/image/gok4" 或 "fileType=jpg,gif,png,jpeg",定位到的都是 jsp 或 js 文件,没有太大价值。

实际上这个项目是将处理文件上传的代码封装到了一个 Jar 包然后引用的,一般情况下如果碰到搜不到的情况,就去 pom.xml 里看看有没有声明依赖的 Jar 包,如下:

IDEA 自带反编译功能,能够将 Class 文件转换为 Java 文件,所以点进 Jar 包能看到 Java 代码

处理文件上传的代码一般放在 controller 里面,由此定位到 ImageUploadController.class

搜索路由 "/gok4",定位到处理文件上传的方法,具体代码如下:

  1. 该方法的逻辑如下:
  2. 1、检查上传文件的大小,如果超过4M,则返回错误信息。
  3. 2、根据fileType参数判断文件类型是否符合要求,如果文件类型不符合或者后缀为jsp,则返回错误信息。
  4. 3、根据上传文件的后缀和param参数,确定上传文件的保存路径。
  5. 4、创建保存文件的目录(如果目录不存在)。
  6. 5、将上传文件保存到指定的路径。
  7. 6、返回上传成功的响应信息,包括文件路径和状态码。
  8. 7、如果发生异常,记录错误日志,并返回上传失败的错误信息。

上图代码中,关键点为 if (fileType.contains(ext) && !"jsp".equals(ext)),即如果文件类型符合且后缀不为 JSP 才进行下一步的上传操作。
跟进 "ext",其来自于 FileUploadUtils.getSuffix(uploadfile.getOriginalFilename()),于是跟进 "getSuffix" 方法,其代码中没有过滤逻辑,只是简单获取后缀名。

跟进 "fileType" 对象,发现其来自于 Request 提交的变量 "fileType",也就是之前 BurpSuite 抓包发现的 "fileType=jpg,gif,png,jpeg"

将已知的信息串联起来,总结这段代码的判断逻辑为:文件后缀包含 jpg,gif,png,jpeg,且不为 jsp 即进行下一步上传操作。

2.3、漏洞利用

对于 "fileType" 显然是可以抓包修改的,所以得出漏洞利用的思路为:抓包修改 "fileType=jpg,gif,png,jpeg,jspx" ,上传 jspx 的 webshell 即可(我用的冰蝎自带的)

点击发包,在后续包中又观察到了上传的位置 http://127.0.0.1:82/images/upload/temp/20231219/1702990600563.jspx

冰蝎连接成功,如下:

3、Tmall - 后台文件上传 - 代码审计

3.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

3.2、审计流程

搜索 "new file(" 关键字 - 定位到 controller 层文件 AccountController.java,从注释和路由信息("admin/uploadAdminHeadImage")推测该功能点大概率是在后台。

为了方便阅读,我重新加上了注释,如下:

跟进文件保存的路径:"filePath" <- "fileName" <- "extension" <- "originalFileName.substring" <- "file.getOriginalFileName" <- "@RequestParam MultipartFile file"

看来好像没有做过滤,怀疑是否重写了 new File() 将过滤加在里面,跟进之后发现是 Java 原生的,所以总的来说这段代码实质上就是没有任何过滤的。

问题来了,这个漏洞是后台的,如果只有普通用户权限,进不去后台,那么该如何利用呢?

这里我的思路是继续审计过滤器 filter 有无鉴权漏洞,所以定位到 AdminPermissionFilter.java,审计其核心方法 doFilter()。

为了方便阅读,我重新加上了注释,如下:

这里鉴权逻辑存在问题,只要 URI 含有 "/admin/login" 或 "/admin/account" 就放行了,显然是不合理的。

于是想到构造 URI 类似:/admin/login/../../tmall/admin/uploadAdminHeadImage

3.3、漏洞利用

首先用管理员账号登录后台测试,发现确实存在文件上传漏洞,成功上传 jsp 文件。

接下来注销管理员账号,再次发包,发现提示我们需要登录,无法上传。

根据代码的鉴权逻辑,构造 URI 类似:/admin/login/../../tmall/admin/uploadAdminHeadImage,重新发包,成功上传 webshell

这里有 JS 验证限制只能选择图片上传,随便绕一下即可。

冰蝎连接成功,如下:

0x03 文件下载漏洞审计 - 若依(Ruoyi)后台管理系统 4.5.0

1、项目介绍与部署

若依(Ruoyi)是一个开源的后台管理系统,可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。

版本:RuoYi-v4.5.0(不用 4.6.0 版本的原因是修复了下述的文件下载漏洞)

项目部署:

  • 修改 application-druid.yml 中的数据库连接密码,在 application.yml 中可修改服务器默认端口(默认 80)
  • 创建名为 ry 的数据库,导入 quartz.sql、ry_20201214.sql 两个 SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认管理员账号密码:admin/admin123

2、若依 Ruoyi - 文件下载 - 代码审计

2.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

2.2、审计流程

全局搜索 "new FileInputStream(" ,定位到 FileUtils.java 的 writeBytes 方法,根据其代码得知是与文件输出相关的操作。

选中 writeBytes 方法 Find Usages,定位到 CommonController.java 的 resourceDownload 方法,其路由为 "/common/download/resource"

该方法调用 writeBytes 传入了 downloadPath, response.getOutputStream() 两个参数,即下载文件的路径、输出流对象,重点应该关注 "downloadPath" 是怎么来的。

跟踪得知,"downloadPath" 由 localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 拼接而成,

localPath 来自 Global.getProfile(),跟进 "getProfile" 得知其返回的是一个全局变量,将其调试打印输出得知为 "E:/xxxxxx/RuoYi-v4.5.0/files"(application.yml 里可以修改)

跟进 "substringAfter",其代码如下所示:(若字符串 str 和分隔符 separator 不为空,则截取分隔符之后的字符串返回)

现在问题来到了 StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 传入的两个参数:resource, Constants.RESOURCE_PREFIX

其中 "resource" 是 GET 请求传入的参数,而对于 "RESOURCE_PREFIX" ,跟进后发现其等于固定值 "/profile",如下所示:

由上图知 StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX) 实际上是截取分隔符 "/profile" 之后的 "resource" 字符串

所以 downloadPath 实际等于 "E:/xxxxxx/RuoYi-v4.5.0/files" + 经过处理后的 GET 请求传入的参数 resource 二者拼接而成,最后下载的文件也就是这个路径所对应的文件。

反观整个代码段,关键就在于有没有对 GET 请求传入的参数 resource 做过滤,显然这里并没有,如此一来便可以在 GET 请求传入的参数 resource 做手脚。

2.3、漏洞利用

尝试下载数据库配置文件 application-druid.yml,已知其路径为:E:/xxxxxx/RuoYi-v4.5.0/ruoyi-admin/src/main/resources/application-druid.yml

则需构造 resource = /profile/../ruoyi-admin/src/main/resources/application-druid.yml,经过 "/profile" 截取处理后,

此时 downloadPath = E:/xxxxxx/RuoYi-v4.5.0/files/../ruoyi-admin/src/main/resources/application-druid.yml(localPath + resource),才能下载到 application-druid.yml

构造 payload 如下:

/common/download/resource?resource=/profile/../ruoyi-admin/src/main/resources/application-druid.yml

成功拿下数据库配置文件 application-druid.yml,如下:

0x04 文件读取漏洞审计 - Oasys

1、项目介绍与部署

Oasys 是一个 OA 办公自动化系统,基于 Springboot 框架开发,使用 Maven 进行项目管理,前端采用freemarker模板引擎,集成 JPA、Mybatis 等框架。

项目部署:

  • 修改 application.properties 中的数据库连接密码和服务器默认端口(默认 8088)
  • 创建名为 oasys 的数据库,导入 oasys.sql SQL 文件执行(MySQL 版本推荐 5.7.26)
  • Maven clean && install,启动项目即可(注意 Project Structure SDK 版本最好为 1.8)
  • 默认账号密码:soli/123456

2、Oasys - 文件读取 - 代码审计

2.1、审计思路

通过搜索 Java 文件操作常用函数,定位到功能点对应代码段,审计其是否存在漏洞(常规审计思路)

2.2、审计流程

全局搜索 "new FileInputStream(" ,定位到 UserpanelController.java 的 image 方法,结合前后代码得到路由为 "/image/**"

着重关注 IOUtils.readFully(input, data),该代码为读取文件内容,其中 "input" 参数为所要读取的文件(FileInputStream 流),而 "data" 参数是为之分配的内存空间。

继续跟进 "input",由于 FileInputStream input = new FileInputStream(f.getPath()),所以跟进到 File f = new File(rootpath, path)

跟进参数 "rootpath",发现其在 application.properties 里声明为固定值:"E:/xxxxxx/oa_system-master/src/main/resources/static/images"

跟进参数 "path",发现其等于 "startpath" 将字符串 "/image" 替换为空之后的字符串,而 "startpath" 则来自 Request 请求的 URI

所以 File f = new File(rootpath, path) 返回的其实是 "E:/xxxxxx/oa_system-master/src/main/resources/static/images" + 经处理后的 URI 二者拼接成的文件路径对应的文件,这样一来 f.getPath() 返回的自然也是这个路径。

反观整个代码段,关键就在于有没有对 URI 做过滤,显然这里并没有,如此一来便可以在 Request 请求的 URI 做手脚。

2.3、漏洞利用

考虑读取数据库配置文件 application.properties,已知其绝对路径为:E:\xxxxxx\oa_system-master\src\main\resources\application.properties

最终构造 Payload 如下:(但不知道为啥没读取到,有无大佬告诉一下?)

/image//image..//image../application.properties

3、代审常搜词 - 文件上传&下载&读取
  1. new File(
  2. String path
  3. String fileName
  4. new FileInputStream(
  5. new FileOutputStream(
  6. new FileReader
  7. response.setContentType("application/octet-stream;
  8. file.delete();
  9. FileUtils.
  10. new ZipEntity(
  11. file.getName(
  12. .unzip(
  13. .mkdirs(
  14. stream.write(
  15. save2File(
  16. fos、fis.close()
  17. MultipartFile(
  18. file.getOriginalFilename(
  19. IOUtil
  20. FileUtil
  21. download
  22. fileName
  23. filePath
  24. write
  25. getFile
  26. getPath
  27. getWriter
  28. 上传 // 搜注释
  29. 下载 // 搜注释
  30. ........

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/682154
推荐阅读
相关标签
  

闽ICP备14008679号