CTFer成長之路-Web進(jìn)階之SSRF漏洞

SSRF漏洞

SSRF(Server Side Request Forgery,服務(wù)端請求偽造)是一種攻擊者通過構(gòu)造數(shù)據(jù)進(jìn)而偽造服務(wù)器端發(fā)起請求的漏洞。因?yàn)檎埱笫怯蓛?nèi)部發(fā)起的,所以一般情況下,SSRF漏洞攻擊的目標(biāo)往往是從外網(wǎng)無法訪問的內(nèi)部系統(tǒng)。
SSRF漏洞形成的原因多是服務(wù)端提供了從外部服務(wù)獲取數(shù)據(jù)的功能,但沒有對目標(biāo)地址、協(xié)議等重要參數(shù)進(jìn)行過濾和限制,從而導(dǎo)致攻擊者可以自由構(gòu)造參數(shù),而發(fā)起預(yù)期外的請求。

SSRF的原理解析URL的結(jié)構(gòu)如下:
URI = scheme:[//authority]path[?query][#fragment]

authority組件又分為以下3部分

scheme:由一串大小寫不敏感的字符組成,表示獲取資源所需要的協(xié)議。
authority:認(rèn)證,userinfo遇到得比較少,這是一個可選項(xiàng),一般HTTP使用匿名形式來獲取數(shù)據(jù),如果需要進(jìn)行身份驗(yàn)證,格式為username:password,以@結(jié)尾。
host:表示在哪個服務(wù)器上獲取資源,一般所見的是以域名形式呈現(xiàn)的,如baidu.com,也有以IPv4、IPv6地址形式呈現(xiàn)的。
port:服務(wù)器端口。各協(xié)議都有默認(rèn)端口,如HTTP的為80、FTP的為21。使用默認(rèn)端口時,可以將端口省略。
path:指向資源的路徑,一般使用“/”進(jìn)行分層。
query:查詢字符串,用戶將用戶輸入數(shù)據(jù)傳遞給服務(wù)端,以“?”作為表示。例如,向服務(wù)端傳遞用戶名密碼為?username=admin&password=admin123
fragment:片段ID,與query不同的是,其內(nèi)容不會被傳遞到服務(wù)端,一般用于表示頁面的錨點(diǎn)。

SSRF漏洞的尋找和測試

SSRF漏洞一般出現(xiàn)在有調(diào)用外部資源的場景中,如社交服務(wù)分享功能、圖片識別服務(wù)、網(wǎng)站采集服務(wù)、遠(yuǎn)程資源請求(如wordpress xmlrpc.php)、文件處理服務(wù)(如XML解析)等。
在對存在SSRF漏洞的應(yīng)用進(jìn)行測試的時候,可以嘗試是否能控制、支持常見的協(xié)議,包括但不限于以下協(xié)議。
? file://:從文件系統(tǒng)中獲取文件內(nèi)容,如file:///etc/passwd。
? dict://:字典服務(wù)器協(xié)議,讓客戶端能夠訪問更多字典源。在SSRF中可以獲取目標(biāo)服務(wù)器上運(yùn)行的服務(wù)版本等信息。
? gopher://:分布式的文檔傳遞服務(wù),在SSRF漏洞攻擊中發(fā)揮的作用非常大。使用Gopher協(xié)議時,通過控制訪問的URL可實(shí)現(xiàn)向指定的服務(wù)器發(fā)送任意內(nèi)容,如HTTP請求、MySQL請求等,所以其攻擊面非常廣。

SSRF漏洞攻擊方式

內(nèi)部服務(wù)資產(chǎn)探測

SSRF漏洞可以直接探測網(wǎng)站所在服務(wù)器端口的開放情況甚至內(nèi)網(wǎng)資產(chǎn)情況,如確定該處存在SSRF漏洞,則可以通過確定請求成功與失敗的返回信息進(jìn)行判斷服務(wù)開放情況。例如,使用Python語言寫一個簡單的利用程序。

# encoding: utf-8
import requests as req
import time

ports = ['80','3306','6379','8080','8000']
session = req.Session()
for i in range(255):
    ip = '10.160.32.%d' % i
    for port in ports:
        url = 'http://example.com/?url=http://%s:%s' % (ip,port)
        try:
            res = session.get(url,timeout=3)
            if len(res.content) > 0:
                print(ip,port,'is open')
        except Exception as e:
            continue
print('DONE')

使用Gopher協(xié)議擴(kuò)展攻擊面

1.攻擊Redis

Redis一般運(yùn)行在內(nèi)網(wǎng),使用者大多將其綁定于127.0.0.1:6379,且一般是空口令。攻擊者通過SSRF漏洞未授權(quán)訪問內(nèi)網(wǎng)Redis,可能導(dǎo)致任意增、查、刪、改其中的內(nèi)容,甚至利用導(dǎo)出功能寫入Crontab、Webshell和SSH公鑰(使用導(dǎo)出功能寫入的文件所有者為redis的啟動用戶,一般啟動用戶為root,如果啟動用戶權(quán)限較低,將無法完成攻擊)。Redis是一條指令執(zhí)行一個行為,如果其中一條指令是錯誤的,那么會繼續(xù)讀取下一條,所以如果發(fā)送的報文中可以控制其中一行,就可以將其修改為Redis指令,分批執(zhí)行指令,完成攻擊。如果可以控制多行報文,那么可以在一次連接中完成攻擊。

2.攻擊MySQL

攻擊內(nèi)網(wǎng)中的MySQL,我們需要先了解其通信協(xié)議。MySQL分為客戶端和服務(wù)端,由客戶端連接服務(wù)端有4種方式:UNIX套接字、內(nèi)存共享、命名管道、TCP/IP套接字。我們進(jìn)行攻擊依靠第4種方式,MySQL客戶端連接時會出現(xiàn)兩種情況,即是否需要密碼認(rèn)證。當(dāng)需要進(jìn)行密碼認(rèn)證時,服務(wù)器先發(fā)送salt,然后客戶端使用salt加密密碼再驗(yàn)證。當(dāng)不需進(jìn)行密碼認(rèn)證時,將直接使用第4種方式發(fā)送數(shù)據(jù)包。所以,在非交互模式下登錄操作MySQL數(shù)據(jù)庫只能在空密碼未授權(quán)的情況下進(jìn)行。

3.PHP-FPM

攻擊利用條件如下:Libcurl,版本高于7.45.0;PHP-FPM,監(jiān)聽端口,版本高于5.3.3;知道服務(wù)器上任意一個PHP文件的絕對路徑。首先,F(xiàn)astCGI本質(zhì)上是一個協(xié)議,在CGI的基礎(chǔ)上進(jìn)行了優(yōu)化。
PHP-FPM是實(shí)現(xiàn)和管理FastCGI的進(jìn)程。在PHP-FPM下如果通過FastCGI模式,通信還可分為兩種:TCP和UNIX套接字(socket)。TCP模式是在本機(jī)上監(jiān)聽一個端口,默認(rèn)端口號為9000,Nginx會把客戶端數(shù)據(jù)通過FastCGI協(xié)議傳給9000端口,PHP-FPM拿到數(shù)據(jù)后會調(diào)用CGI進(jìn)程解析。

4.攻擊內(nèi)網(wǎng)中的脆弱

Web應(yīng)用內(nèi)網(wǎng)中的Web應(yīng)用因?yàn)闊o法被外網(wǎng)的攻擊者訪問到,所以往往會忽視其安全威脅。假設(shè)內(nèi)網(wǎng)中存在一個任意命令執(zhí)行漏洞的Web應(yīng)用,在本地監(jiān)聽任意端口,然后對此端口發(fā)起一次POST請求,以抓取請求數(shù)據(jù)包,將其改成Gopher協(xié)議的URL,改變規(guī)則同上。

自動組裝Gopher

目前已經(jīng)有人總結(jié)出多種協(xié)議并寫出自動轉(zhuǎn)化的腳本,所以大部分情況下不需要再手動進(jìn)行抓包與轉(zhuǎn)換。
推薦工具 https://github.com/tarunkant/Gopherus

SSRF的繞過

IP的限制

使用Enclosed alphanumerics代替IP中的數(shù)字或網(wǎng)址中的字母,或者使用句號代替點(diǎn)。
如果服務(wù)端過濾方式使用正則表達(dá)式過濾屬于內(nèi)網(wǎng)的IP地址,那么可以嘗試將IP地址轉(zhuǎn)換為進(jìn)制的方式進(jìn)行繞過,如將127.0.0.1轉(zhuǎn)換為十六進(jìn)制后進(jìn)行請求。
可以將IP地址轉(zhuǎn)換為十進(jìn)制、八進(jìn)制、十六進(jìn)制,分別為2130706433、17700000001、7F000001。在轉(zhuǎn)換后進(jìn)行請求時,十六進(jìn)制前需加0x,八進(jìn)制前需加0,轉(zhuǎn)換為八進(jìn)制后開頭所加的0可以為多個。
另外,IP地址有一些特殊的寫法,如在Windows下,0代表0.0.0.0,而在Linux下,0代表127.0.0.1,見圖2-1-23。所以,某些情況下可以用http://0進(jìn)行請求127.0.0.1。類似127.0.0.1這種中間部分含有0的地址,可以將0省略。

302跳轉(zhuǎn)

網(wǎng)絡(luò)上存在一個名叫xip.io的服務(wù),當(dāng)訪問這個服務(wù)的任意子域名時,都會重定向到這個子域名,如127.0.0.1.xip.io,這種方式可能存在一個問題,即在傳入的URL中存在關(guān)鍵字127.0.0.1,一般會被過濾,那么,我們可以使用短網(wǎng)址將其重定向到指定的IP地址,如短網(wǎng)址http://dwz.cn/11SMa
有時服務(wù)端可能過濾了很多協(xié)議,如傳入的URL中只允許出現(xiàn)“http”或“https”,那么可以在自己的服務(wù)器上寫一個302跳轉(zhuǎn),利用Gopher協(xié)議攻擊內(nèi)網(wǎng)的Redis。

URL的解析問題

如果傳入的URL為http://a@127.0.0.1:80@baidu.com,那么進(jìn)入safe_request_url后,parse_url取到的host其實(shí)是baidu.com,而curl取到的是127.0.0.1:80,所以實(shí)現(xiàn)了檢測IP時是正常的一個網(wǎng)站域名而實(shí)際curl請求時卻是構(gòu)造的127.0.0.1,以此實(shí)現(xiàn)了SSRF攻擊。
除了PHP,不同語言對URL的解析方式各不相同,進(jìn)一步了解可以參考:https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf。

DNS Rebinding

在某些情況下,針對SSRF的過濾可能出現(xiàn)下述情況:通過傳入的URL提取出host,隨即進(jìn)行DNS解析,獲取IP地址,對此IP地址進(jìn)行檢驗(yàn),判斷是否合法,如果檢測通過,則再使用curl進(jìn)行請求。那么,這里再使用curl請求的時候會做第二次請求,即對DNS服務(wù)器重新請求,如果在第一次請求時其DNS解析返回正常地址,第二次請求時的DNS解析卻返回了惡意地址,那么就完成了DNS Rebinding攻擊。

DNS重綁定的攻擊首先需要攻擊者自己有一個域名,通常有兩種方式。
第一種是綁定兩條記錄。這時解析是隨機(jī)的,但不一定會交替返回。所以,這種方式需要一定的概率才能成功。
第二種方式則比較穩(wěn)定,自己搭建一個DNS Server,在上面運(yùn)行自編的解析服務(wù),使其每次返回的都不同。

Redis的主從模式

Redis為了應(yīng)對讀寫量較大的問題,提供了一種主從模式,使用一個Redis實(shí)例作為主機(jī)只負(fù)責(zé)寫,其余實(shí)例都為從機(jī),只負(fù)責(zé)讀,主從機(jī)間數(shù)據(jù)相同,其次在Redis 4.x后新增加了模塊的功能,通過外部的擴(kuò)展可以實(shí)現(xiàn)一條新的Redis命令,因?yàn)榇藭r已經(jīng)完全控制了Redis,所以可以通過將此機(jī)設(shè)置為自己VPS的從機(jī),在主機(jī)上通過FULLSYNC同步備份一個惡意擴(kuò)展到從機(jī)上加載。
在Github上可以搜到關(guān)于該攻擊的exp,如https://github.com/n0b0dyCN/redis-rogue-server。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容