1. 什么是序列化和反序列化
序列化是將對象狀態轉換為可保持或可傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為對象。這兩個過程結合起來,可以輕松地存儲和傳輸數據。
2. 序列化和反序列化的格式:
類型:d ->d代表一個整型數字
O:d -> 對象 ->d代表該對象類型的長度,例如上述的azhe類對象長度為4,原生類對象Error長度為5
a:d -> 數組 ->d代表數組內部元素數量,例如array('a'=>'b','x'=>1)有兩個元素
s:d -> 字符串 -dN代表字符串長度,例如abc序列化后為s:3:"abc";
i:d -> 整型 ->d代表整型變量的值,例如300序列化后的值則為i:300;
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
class Xlh{
public $test=123;
protected $test2='123';
private $test3=array(1,2,'san');
}
$xlh= new Xlh();
$xlh=serialize($xlh);
echo $xlh."<br>";
$fxlh=unserialize($xlh);
print_r($fxlh);
/*
$aaa=123;
i:123
$bb="123";
s:2:"123";
*/
結果:
O:3:"Xlh":3:{s:4:"test";i:123;s:8:"%00*%00test2";s:3:"123";s:10:"%00Xlh%00test3";a:3:{i:0;i:1;i:1;i:2;i:2;s:3:"san";}}
Xlh Object ( [test] => 123 [test2:protected] => 123 [test3:Xlh:private] => Array ( [0] => 1 [1] => 2 [2] => san ) )
序列化的格式:不同的類型序列化之后的表示方式大同小異;
序列化與json的選擇:
json數據的格式:
json{
"key1":"value1",
"key2":"value2"
}
-
序列化使用serialize,特別是對象的存儲。這是其存在的意義。
-
與對象無關的數據存儲可以使用json,
-
數據交換時使用JSON,這也是其定義所在。
-
目前JSON是能用於UTF-8編碼的數據。沒辦法進行對象的存儲
3.session序列化引擎
php對session的處理有三種引擎分別為php、php_serialize、php_binary.經過這三者處理后的session結構都不相同。
php_serialize ->與serialize函數序列化后的結果一致
a:1:{s:4:"name";s:4:"asdf";}
php ->key|serialize后的結果
name|s:4:"asdf";
php_binary ->鍵名的長度對應的ascii字符+鍵名+serialize()函數序列化的值
names:4:"asdf";(前面的電就是asc字符)
names:7:"a s d f";
4.常見函數——魔術方法
__wakeup() //使用unserialize時觸發
__sleep() //使用serialize時觸發
__destruct() //對象被銷毀時觸發
__call() //在對象上下文中調用不可訪問的方法時觸發——對象調用一個沒有聲明的方法時,觸發
__callStatic() //在靜態上下文中調用不可訪問的方法時觸發
__get() //用於從不可訪問的屬性讀取數據
__set() //用於將數據寫入不可訪問的屬性
__isset() //在不可訪問的屬性上調用isset()或empty()觸發
__unset() //在不可訪問的屬性上使用unset()時觸發
__toString() //把類當作字符串使用時觸發 echo 對象; $text=$test+$對象;
__invoke() //當腳本嘗試將對象調用為函數時觸發
5.常見的漏洞利用
1. 字符串逃逸:
反序列化
原理:類似於SQL注入,都是因為對用戶輸入過濾嚴謹造成的封閉,而造成的命令執行:
反序列化底層實現邏輯:
反序列化:
a:4:{i:0;i:123;i:1;s:3:"abc";i:2;s:4:"abcd";i:3;s:5:"abcde";}???asdfe65ff31
a:4:{i:0;i:123;i:1;s:3:"abc";i:2;s:4:"abcd";i:3;s:5:"abcde";}???
反序列化完成之后,就不在反序列化其它內容了,也就是說,后面的三個問號(任意字符都可以)不會被反序列化。
反序列化的實現底層是匹配的開始幾個字符;只要能夠匹配成功,那么就不再管后面的了。
反序列化會嚴格的按照字符串的格式(類型:長度:"變量名"; 類型:長度:"數據(可以是其它類型變量)"; 數字類型:數字; )進行,當正確的讀取到 } 時,就不會再讀取后面的數據了,因為正確的讀取到},就代表着結束。加入在過程中有任何錯誤,那么反序列化過程就會終止
**例題: **
逃逸:ctfshow web入門 web262
問題:在進行replace時,前后替換的長度有了變換,所以能夠進行簡單的字符串逃逸
逃逸:buu安洵杯第一題:
問題:全部替換
2. CVE-2016-7124:__wakeup()函數漏洞
通過修改反序列化字符串的名稱,內容的數字來進行錯誤的喚醒,錯誤喚醒,但是程序不會終止,而是繼續進行,雖然錯誤了,也會有一個對象被喚醒
影響版本:PHP5<5.6.25 PHP7<7.0.10
例題:
功放世界第一個反序列化的題,
bugku安慰獎
3. 偽協議的利用
1. 常見文件利用
考點:php偽協議利用 利用data://偽協議傳數據,利用php://filter偽協議讀取文件數據
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
file=php://filter/read=convert.base64-encode/resource=useless.php
2.PHAR偽協議利用
作用:phar文件是php的打包文件,在php.ini中可以通過設置phar.readonly來控制phar文件是否為只讀,若非只讀(phar.readonly=Off)則可以生成phar文件.
phar文件結構
四部分,stub、manifest、contents、signature
1.stub
phar文件標志,必須包含<?php __HALT_COMPILER(); ?>,PHP結束標志?>可以省略,但語句結束符;與stub的結尾之間不能超過兩個空格。在生成phar之前應先添加stub.<?php __HALT_COMPILER(); ?>之前也可添加其他內容偽造成其他文件,比如GIF89a<?php __HALT_COMPILER(); ?>
2.manifest
存放phar歸檔信息.Manifest結構如下圖
所有未使用的標志保留,供將來使用,並且不得用於存儲自定義信息。使用每個文件的元數據功能來存儲有關特定文件的自定義信息.
<?php
class Test{
public $test="prprpr999888";
function __destruct(){
echo $this->test."<br>";
}
}
$phar = new Phar("test.phar"); //后綴名必須為phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //設置stub
$o = new Test();
$phar->setMetadata($o); //將自定義的meta-data存入manifest
$phar->addFromString("test.txt", "test");
//添加要壓縮的文件,將test文件的數據添加到test.php文件中去
//由於只是需要構造payload,所以這里的test文件不存在也行
$phar->stopBuffering(); //簽名自動計算
file_get_contents('phar://test.phar/test.txt');
//這里是上一次運行代碼生成的test.phar和test.txt
echo"done.<br>";
?>
例題:CISCN2019 華北賽區 Day1 Web1 Dropbox
考點:phar文件,pop鏈構造
pop鏈:
可以簡單理解為解題鏈,一環套一環,從一個文件中,找到下一個文件或者上一個文件是不是對本文件的內容進行了利用;例如例題中的:pop鏈構造:User(類)->filelsit(類)->file(類)(filename=flag.php)->close()(函數)
4.session反序列化
需要知道session_start()
這個函數已經這個函數所起的作用:
當會話自動開始或者通過 session_start() 手動開始的時候, PHP 內部會依據客戶端傳來的PHPSESSID來獲取現有的對應的會話數據(即session文件), PHP 會自動反序列化session文件的內容,並將之填充到 $_SESSION 超級全局變量中。如果不存在對應的會話數據,則創建名為sess_PHPSESSID(客戶端傳來的)的文件。如果客戶端未發送PHPSESSID,則創建一個由32個字母組成的PHPSESSID,並返回set-cookie。
提示:
一般如果是session漏洞,源碼中一般有session_hanlder='php_serialize'的設置和session_start()的提示
例題:
ctfshow web入門反序列化 web 263
5. 其它類型的組合拳
考點:強弱類型比較,php7.1+對類的屬性(公有私有保護)不敏感
注意:
- protected和private的%00截斷在復制粘貼之后可能消失,需要手動添加
- ``反引號,可以作為系統命令輸出給var_dump
- 如果不能使用%00就使用\00來進行截斷
- 傳遞進去的是字符串,在進行pop鏈的時候,想清楚反序列化的是什么
類型:
- 字符串逃逸
- 部分截斷(關鍵字替換的時候兩次長度不對等:少變長或者長變少)
- 全部截斷
- 偽協議:
- 一般的偽協議:data,php://filter等
- PHAR偽協議:用偽協議讀取的時候自動進行反序列化操作
- 本身的漏洞
- CVE-2016-7124:wakeup()的繞過
- php7.1+ ==>對類型不敏感
- session反序列化:自動進行反序列化操作
- ssrf+反序列化
- 過濾不嚴謹:
- 十六(使用大寫的S)進制繞過字符串過濾
- 正則表達式不嚴謹>'[o]:\d+' 繞過:在數字前面加上+形成結構>o:+\d+
- 在PHP中,對類的名字大小寫不敏感==>(car類和CAr類是等價的)
參考:
深入淺析PHP的session反序列化漏洞問題_php實例_腳本之家 (jb51.net)
CTF]PHP反序列化總結_Y4tacker的博客-CSDN博客_ctfshow 反序列化
https://www.bilibili.com/video/BV1bJ411C7xv?from=search&seid=2459185202854297460
https://www.bilibili.com/video/BV1JZ4y1c7ro?p=37