1. 程式人生 > 實用技巧 >[網鼎杯 2020 玄武組]SSRFMe

[網鼎杯 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.
?>

程式碼審計

  1. 接受使用者傳入的url,判斷其不為空後經函式處理
  2. check_inner_ip函式判斷其是否為合法內網ip,並使用http或gopher等協議
  3. 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地址

專案1

專案2

首先開linux靶機,redis-rogue-server.py無法執行,坑了好久發現linux靶機的python環境是3.5,此專案需要3.6+.這個專案不需要了,也就是說redis-rogue-server這個專案我們只需要把預設的exp.so放在redis-ssrf-master這個專案下!

我們用到的是

  1. 小號開linux靶機,ssh連線,把這兩個py檔案和exp.so傳至同一目錄下

  2. 修改ssrf-redis中的三處

    125行改成linux靶機的ip,command改成想要執行的命令,139行ip因為要繞過之前ssrf的限制使用0.0.0.0,159行password改成之前提示的root

  3. 生成payload,因為還需要在url中傳參,會解碼一次,所以還需要url編碼一次

  4. 在linux伺服器上使用rogue建立從節點

  5. 將生成的payload打過去

exp.so被成功執行

舒服了

總結思路

程式碼審計->看到curl_exec想到ssrf->打內網->根據提示redisgetshell->生成rogueserver(vps或buu中的linux靶機)->利用gopher協議生成payload或者直接反彈shell

知識點

  • 程式碼審計
  • ssrf
  • redis4.x/5.xRCE漏洞