php反序列化之字符串逃逸詳解
php反序列化–字符串逃逸
PHP反序列化的字符串逃逸,一共分有兩種情況,情況一:過(guò)濾后字符串變多,情況二:過(guò)濾后字符變少(本篇文章默認(rèn)已有反序列化相關(guān)知識(shí)基礎(chǔ))
過(guò)濾后字符串變多
以ctfshow-web262為例講解:
error_reporting(0); class message{ public $from; public $msg; public $to; public $token='user'; public function __construct($f,$m,$t){ $this->from = $f; $this->msg = $m; $this->to = $t; } } $f = $_GET['f']; $m = $_GET['m']; $t = $_GET['t']; if(isset($f) && isset($m) && isset($t)){ $msg = new message($f,$m,$t); $umsg = str_replace('fuck', 'loveU', serialize($msg)); setcookie('msg',base64_encode($umsg)); echo 'Your message has been sent'; } highlight_file(__FILE__);
這段代碼,首先要get傳入3個(gè)參數(shù),然后序列化傳入的包含有這三個(gè)參數(shù)的msg函數(shù),之后將里面包含的fuck字符串替換成為loveU,重新賦值給umsg變量,并將該變量base64編碼,設(shè)置為cookie
根據(jù)題中注釋提示,得到message.php內(nèi)容,為
highlight_file(__FILE__); include('flag.php'); class message{ public $from; public $msg; public $to; public $token='user'; public function __construct($f,$m,$t){ $this->from = $f; $this->msg = $m; $this->to = $t; } } if(isset($_COOKIE['msg'])){ $msg = unserialize(base64_decode($_COOKIE['msg'])); if($msg->token=='admin'){ echo $flag; } }
如果設(shè)置了cookie且msg中的token為admin,即可輸出flag
由index.php內(nèi)容可知,進(jìn)行了一步replace,導(dǎo)致每輸入一個(gè)fuck,就會(huì)多生成一位,故我們可以利用這個(gè)特點(diǎn)進(jìn)行字符串逃逸,首先本地嘗試一下
由題可知,我們需要修改原class類中的token值為admin,然后一起傳入三個(gè)參數(shù),f,m,t,我們可以利用其中一個(gè)參數(shù),這里利用的參數(shù)是m,為了避免需要逃逸的字符串太多,我們可以先寫f t參數(shù),本地隨便傳入值,輸出序列化結(jié)果
下圖中";s:2:"to";s:1:"1";s:5:"token";s:5:"admin";}
即為我們要逃逸的部分,一共44個(gè)字符,故我們需要m輸入44個(gè)fuck來(lái)逃逸
逃逸成功,上下兩個(gè)字符串均為正常的序列化字符串,復(fù)制payload前往執(zhí)行
字符串變多原理詳解
這道題就用到了php反序列化中字符串逃逸的知識(shí)
首先看本地實(shí)驗(yàn)的正常返回結(jié)果
當(dāng)傳入x時(shí),定義的替換函數(shù),將一個(gè)x替換為兩個(gè)x后得到的 o l d 的 值 為 ‘ a : 2 : i : 0 ; s : 4 : " h a n x x " ; i : 1 ; s : 7 : " I a m 11 " ; ‘ , 長(zhǎng) 度 不 匹 配 , 會(huì) 出 現(xiàn) 報(bào) 錯(cuò) , 進(jìn) 而 導(dǎo) 致 old的進(jìn)一步反序列化失敗
當(dāng)然如果我們可以將hanx
的字符串長(zhǎng)度由4改為5時(shí),雖然最開始輸入了4個(gè)字符但正常執(zhí)行,并且name由hanx
變?yōu)榱?code>hanxx
PHP 在反序列化時(shí),底層代碼是以 ;
作為字段的分隔,以 }
作為結(jié)尾(字符串除外),并且是根據(jù)長(zhǎng)度判斷內(nèi)容的 ,同時(shí)反序列化的過(guò)程中必須嚴(yán)格按照序列化規(guī)則才能成功實(shí)現(xiàn)反序列化 。
由上面的輸出結(jié)果可以看到x被換成了xx,然而序列化的結(jié)果中數(shù)值仍然是原來(lái)的4,我們可以根據(jù)字符串在經(jīng)過(guò)過(guò)濾函數(shù)后字符串變多的特點(diǎn)找到漏洞
漏洞原理:我們可以利用等長(zhǎng)的可以用來(lái)閉合的字符串傳入數(shù)據(jù),假設(shè)我們需要傳入age為woaini,故我們可以利用";i:1;s:6:"woaini";}
這個(gè)字符串,該字符串一共20位,我們可以通過(guò)補(bǔ)充20個(gè)x來(lái)實(shí)現(xiàn)字符串逃逸,最終構(gòu)造的payload如下:
name=maoxxxxxxxxxxxxxxxxxxxx";i:1;s:6:"woaini";}
因?yàn)轭}中已知會(huì)將一個(gè)x替換為兩個(gè)x,故我們可以令x的數(shù)量與上面payload中";i:1;s:6:"woaini";}
的數(shù)量相等,這樣既滿足了,序列化之前,name的長(zhǎng)度為40(不算前面的mao),又滿足了替換后x擴(kuò)大一倍,導(dǎo)致引號(hào)閉合,那么長(zhǎng)度仍為40位,但是我們通過(guò)字符串逃逸,傳入了想要的age的值
由圖可知,傳入的age值成功溢出,字符串逃逸成功!
過(guò)濾后字符串變少
本地測(cè)試如上,初始時(shí)name和sign沒有賦值,number為2020,存在字符串逃逸漏洞,假設(shè)我們通過(guò)構(gòu)造反序列化字符串逃逸,使number值由2020變?yōu)?002為成功,則可以嘗試構(gòu)造序列化字符串
首先代碼中通過(guò)get傳入name和sign參數(shù),之后進(jìn)行反序列化,并將反序列化的結(jié)果進(jìn)行字符串替換,輸出替換后的結(jié)果,把反序列化的結(jié)果賦值給fake,分別輸出經(jīng)過(guò)改造后的name
、sign
、number
值
正常輸入得到正常輸出:
當(dāng)輸入包含有l(wèi)emon或者shy時(shí),會(huì)替換為空,字符串變短導(dǎo)致代碼中反序列化失敗,輸出錯(cuò)誤:
在上面的反序列化字符串中,控制number值的字符串為";s:6:"number";s:4:"2020";}
總長(zhǎng)為27,所以我們需要在name變量中設(shè)置被過(guò)濾的字符進(jìn)行置空,該置空部分的字符串,需要保證我們?cè)诘诙€(gè)變量輸入人為補(bǔ)充的序列化字符串時(shí),位數(shù)正好,不報(bào)錯(cuò)
這里sign輸入了YKing";s:4:"sign";s:4:"evan";s:6:"number";s:4:"2002";}
其中,YKing用于湊字?jǐn)?shù),補(bǔ)充前面的name變量的長(zhǎng)度,保證后續(xù)可以正常反序列化,然后輸入了手工構(gòu)造的sign變量,并賦值,值為多少無(wú)所謂,保證序列化正確即可,最后將我們想要的number值2002,補(bǔ)充到sign變量中,并通過(guò)}
閉合,導(dǎo)致原題中的2020無(wú)法反序列化,進(jìn)而實(shí)現(xiàn)number值的覆蓋
name變量的長(zhǎng)度,保證后續(xù)可以正常反序列化,然后輸入了手工構(gòu)造的sign變量,并賦值,值為多少無(wú)所謂,保證序列化正確即可,最后將我們想要的number值2002,補(bǔ)充到sign變量中,并通過(guò)}
閉合,導(dǎo)致原題中的2020無(wú)法反序列化,進(jìn)而實(shí)現(xiàn)number值的覆蓋
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
PHP獲取當(dāng)前頁(yè)面完整URL的實(shí)現(xiàn)代碼
本篇文章是對(duì)利用PHP獲取當(dāng)前頁(yè)面完整URL的實(shí)現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP保存Base64圖片base64_decode的問(wèn)題整理
在本篇文章里小編給大家整理的是關(guān)于PHP保存Base64圖片base64_decode的問(wèn)題,需要的朋友們參考下。2019-11-11php運(yùn)行出現(xiàn)Call to undefined function curl_init()的解決方法
curl_init -- 初始化一個(gè)CURL會(huì)話,如果提示Call to undefined function curl_init那么需要如下操作即可。2010-11-11編寫Smarty插件在模板中直接加載數(shù)據(jù)的詳細(xì)介紹
本篇文章是對(duì)編寫Smarty插件在模板中直接加載數(shù)據(jù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP實(shí)現(xiàn)根據(jù)瀏覽器跳轉(zhuǎn)不同語(yǔ)言頁(yè)面代碼
以下是對(duì)使用PHP實(shí)現(xiàn)根據(jù)瀏覽器跳轉(zhuǎn)不同語(yǔ)言頁(yè)面的代碼進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下2013-08-08九個(gè)你必須知道而且又很好用的php函數(shù)和特點(diǎn)
以下小編就為大家介紹一個(gè)九個(gè)你必須知道而且又很好用的php函數(shù)和特點(diǎn)。非常實(shí)用哦!需要的朋友可以過(guò)來(lái)參考下2013-08-08