typecho ssrf 分析
typecho 在2017年10月左右爆出過一個ssrf漏洞,可用於攻擊內網服務。本文從php程式碼層面分析了一下漏洞的觸發原理,希望能對閱讀者有一定幫助。
通過diff發現var\Widget\XmlRpc.php檔案有如下修改:
舊版本2048行:
新版本則吧這個檢查放在了pingbackPing函式的開頭:
XmlRpc是方便第三方工具管理typecho的介面,當其被呼叫時,首先會執行XmlRpc.php的2189行:
public function action()
.....
在2249行new了一個IXR_Server,隨即走到了他的建構函式:
然後跟入serve函式:
可以看見我們post的內容都傳入了$GLOBALS['HTTP_RAW_POST_DATA'],然後賦值給$data,後面new了一個IXR_Message並把$data作為引數傳入,跟入parse():
這個函式在新建一個xml直譯器,xml程式碼為我們post的內容。
xml_set_element_handler設定了xml文件中的起始和終止呼叫的函式,這裡就是'tag_open'和'tag_close'。
xml_set_character_data_handler函式規定當解析器在 XML 檔案中找到字元資料時所呼叫的函式。
關鍵程式碼如下(由於程式碼較長,所以只貼出關鍵程式碼),位於tag_close函式的142行
function tag_close($parser, $tag) {
當有一個標籤為methodName時,_currentTagContents也就是methodName的內容會賦值給$this->methodName。
而當標籤為string時,內容賦值給$value並在163行:
$this->params[] = $value;
往後執行到server.php的call函式:
其中$methodname和$args都是我們通過xml標籤傳遞的值,在最後一行call_user_func_array中,即可呼叫相應的函式。
然後回到漏洞觸發點:
var\Widget\XmlRpc.php 的2049行:
if (!($http = Typecho_Http_Client::get())) {
這裡呼叫的get方法載入了var\Typecho\Http\Client\Adapter\Curl.php和ar\Typecho\Http\Client\Adapter\Socket.php兩個檔案,當發起請求時首先會嘗試使用curl,否則使用Socket。
緊接著後面:
$http->setTimeout(5)->send($source);
$source為我們可傳入字元,跟蹤send函式:
public function send($url)
{
$params = parse_url($url);
if (!empty($params['host'])) {
$this->host = $params['host'];
.....
用parse_url拆分傳入的url,並依次新增到$this中,除此外還添加了cookie和hearder,在338行:
前面都在設定curl選項,然後在最後執行,一路暢通無阻,所以造成ssrf。
在XmlRpc.php的2058行:
可看見response如果狀態為200,且x-pingback為空、原地址不支援PingBack,就返回源地址不支援PingBack,否則會返回源地址伺服器錯誤。
所以我們可以通過輸出來探測ip和埠,如果返回源地址伺服器錯誤,則主機/埠關閉,如果返回源地址不支援PingBack,則主機/埠存在。
當然不光是埠和主機探測,我們也可以進一步盲打內網中的redis和FastCGI。
payload
post以下內容到http://127.0.0.1:8888/typecho/index.php/action/xmlrpc:
其中http://127.0.0.1:80就是上文中的$source。