該題考察序列化反序列化及Linux命令執行相關知識。
題目
<?php
highlight_file(__FILE__);class ease{private $method;private $args;function __construct($method, $args) {$this->method = $method;$this->args = $args;}function __destruct(){if (in_array($this->method, array("ping"))) {call_user_func_array(array($this, $this->method), $this->args);}} function ping($ip){exec($ip, $result);var_dump($result);}function waf($str){if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {return $str;} else {echo "don't hack";}}function __wakeup(){foreach($this->args as $k => $v) {$this->args[$k] = $this->waf($v);}}
}$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>
開門見山給出代碼,考察代碼分析能力。
首先,代碼定義了一個名為ease
的類,其中__construct()
接收兩個參數$method
和$args
,并將它們賦值給對應的屬性。__destruct()
在對象銷毀時自動調用。它首先檢查$method
是否在可調用的方法數組中,如果是,則使用call_user_func_array()
函數調用ping()
方法,并將$args
作為參數傳遞進去。
方法ping($ip)
接收一個參數$ip
,使用exec()
函數執行$ip
命令,并將結果存儲在$result
數組中,最后通過var_dump()
打印出來。
方法waf($str)
用于簡單的Web應用防火墻(WAF)功能。它使用正則表達式檢測是否包含一些特定的關鍵字,如|
、&
、;
、/
、cat
、flag
、tac
、php
、ls
等。如果不包含這些關鍵字,則返回原始字符串;否則,輸出"don’t hack"。
__wakeup()
是一個魔術方法,用于在反序列化對象時自動調用。它遍歷$args
數組,并對其中的每個元素調用waf()
方法進行過濾。
也就是說,代碼通過接收名為ctf
的POST參數,對其進行base64解碼并反序列化。
那么思路就很清晰了:構造可進行命令執行的ping命令,并經過序列化、base64加密后賦值給參數ctf。由于ctf在解碼后會被反序列化,而反序列化時會執行wakeup魔術方法,即反序列化時會對ping命令中的關鍵字進行過濾來限制命令執行。所以我們可以使用雙引號閉合等的方式進行繞過。
查看目錄文件:
結果如下:
接下來就是訪問flag_1s_here,由于flag被過濾,用雙引號繞過。空格被過濾,用IFS進行繞過。(在PHP中,${}
語法是用于取變量的值,并可以在花括號中使用任意的表達式,IFS默認為空格)
構造POC后回顯如下:
傳參:
那么接下來要做的就是打印php中的內容
將
cat flag_1s_here /flag_831b69012c67b35f.php
變化為
c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp
$()用于執行命令并獲取其輸出結果,這里將 ASCII 碼為 57 的字符 /
通過 printf 命令輸出。
傳參: