[網鼎杯 2020 玄武組]SSRFMe
[網鼎杯 2020 玄武組]SSRFMe
目錄解題思路
開啟直接給原始碼,沒什麼說的,開審
<?php function check_inner_ip($url) { $match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url); if (!$match_result) { die('url fomat error'); } try { $url_parse=parse_url($url); } catch(Exception $e) { die('url fomat error'); return false; } $hostname=$url_parse['host']; $ip=gethostbyname($hostname); $int_ip=ip2long($ip); return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16; } function safe_request_url($url) { if (check_inner_ip($url)) { echo $url.' is inner ip'; } else { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); $output = curl_exec($ch); $result_info = curl_getinfo($ch); if ($result_info['redirect_url']) { safe_request_url($result_info['redirect_url']); } curl_close($ch); var_dump($output); } } if(isset($_GET['url'])){ $url = $_GET['url']; if(!empty($url)){ safe_request_url($url); } } else{ highlight_file(__FILE__); } // Please visit hint.php locally. ?>
程式碼審計
- 接受使用者傳入的url,判斷其不為空後經函式處理
- check_inner_ip函式判斷其是否為合法內網ip,並使用http或gopher等協議
- safe_request_url先用上一個函式判斷,不符合即會開啟curl會話,輸入值
看到curl_exec也比較明確是ssrf了,程式碼最後提示要從本地端訪問hint.php檔案,那麼繞過本地驗證即可,方法也有很多,我這裡使用
http://[0:0:0:0:0:ffff:127.0.0.1]//hint.php
來到下一層
<?php if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){ highlight_file(__FILE__); } if(isset($_POST['file'])){ file_put_contents($_POST['file'],"<?php echo 'redispass is root';exit();".$_POST['file']); }
一看到
file_put_contents($content,"<?php exit();".$content);
就知道考file_put_content死亡程式碼
具體總結見此部落格,非常詳細,可以學到很多東西
好吧好吧,打臉了打臉了,我本地測試了幾個payload,全都本地打出shell了,遠端打不通,又看到程式碼中輸出了redispass is root,那考點就不在這,應該是結合redis
redis主從複製
關於redis的主從複製我專門寫了一個部落格,詳見我另一篇,這裡只講利用流程了
坑點無數!!!!!!
兩篇需要的github地址
首先開linux靶機,redis-rogue-server.py無法執行,坑了好久發現linux靶機的python環境是3.5,此專案需要3.6+.這個專案不需要了,也就是說redis-rogue-server這個專案我們只需要把預設的exp.so放在redis-ssrf-master這個專案下!
我們用到的是
-
小號開linux靶機,ssh連線,把這兩個py檔案和exp.so傳至同一目錄下
-
修改ssrf-redis中的三處
125行改成linux靶機的ip,command改成想要執行的命令,139行ip因為要繞過之前ssrf的限制使用0.0.0.0,159行password改成之前提示的root
-
生成payload,因為還需要在url中傳參,會解碼一次,所以還需要url編碼一次
-
在linux伺服器上使用rogue建立從節點
-
將生成的payload打過去
exp.so被成功執行
舒服了
總結思路
程式碼審計->看到curl_exec想到ssrf->打內網->根據提示redisgetshell->生成rogueserver(vps或buu中的linux靶機)->利用gopher協議生成payload或者直接反彈shell
知識點
- 程式碼審計
- ssrf
- redis4.x/5.xRCE漏洞