Apache Axis1(<=1.4版本) RCE

2019-07-03 约 448 字 预计阅读 3 分钟

声明:本文 【Apache Axis1(<=1.4版本) RCE】 由作者 orich1 于 2019-07-03 08:43:00 首发 先知社区 曾经 浏览数 160 次

感谢 orich1 的辛苦付出!

前言

2019.6.16 发出了一则漏洞预警:
https://www.gdcert.com.cn/index/news_detail/W1BZRDEYCh0cDRkcGw

最近两天刚好在学习WebService相关知识,这个 axis 组件就是一个SOAP引擎,提供创建服务端、客户端和网关SOAP操作的基本框架,没见过这类漏洞,抱着学习的心态研究下

触发流程

第一次请求:
org.apache.axis.transport.http.AxisServlet#doPost
->
org.apache.axis.utils.Admin#processWSDD
->
org.apache.axis.AxisEngine#saveConfiguration

第二次请求:
org.apache.axis.transport.http.AxisServlet#doPost
->
freemarker.template.utility.Execute#exec
->
java.lang.Runtime#exec(java.lang.String)

分析过程

本地环境: jdk1.8_191 、Apache Axis1 1.4 、 Tomcat6

看了几个预警,大多描述的是 “Apache Axis 中的 FreeMarker 组件/插件存在相关漏洞”,我找了半天,没见着 FreeMarker 和 Axis 的配合使用呀emmm,这就让我更好奇了,因为之前也有过 FreeMarker 模板注入 bypass 的文章(https://xz.aliyun.com/t/4846)
难道是未授权访问到了 FreeMarker的模板解析流程?

在 ‘/services/FreeMarkerService’ 这个路径上浪费了许多时间,转头看向 ‘/services/AdminService’ 的未授权

全局搜一下,如下图:

完全和预警通告中的描述吻合,跟进 org.apache.axis.utils.Admin#AdminService 查看如下:

稍微了解过 WebService 的带哥可能此时就明白了,之前的那个 service-config.wsdd 配置文件展示的 service 标签就是一个个 WebService 发布的端口,其中 allowedMethods 则是发布的函数,如上图的 AdminService 函数,我们可以通过 SOAP 的方式去调用服务端的 AdminService 函数,需要构造的请求大致如下:

POST /services/AdminService …

他会自动处理我们传递的xml结构参数,上图中 xml[0] 内容是我们完全可控的,跟进 process 函数,如下:

首先调用了 verifyHostAllowd 函数进行验证,其验证内容大致如下:

大意是如果服务端该 WebService 端口的 enableRemoteAdmin 属性为 false 的话,则判断当前访问ip,如果是本机访问则放行,如果是远程访问就抛错

继续跟进 processWSDD 函数,如下:

protected static Document processWSDD(MessageContext msgContext,
                                          AxisEngine engine,
                                          Element root)
        throws Exception
    {
        Document doc = null ;
        String action = root.getLocalName();
        if (action.equals("passwd")) {
            [...]
        }
        if (action.equals("quit")) {
            [...]
        }
        if ( action.equals("list") ) {
            [...]
        }
        if (action.equals("clientdeploy")) {
            // set engine to client engine
            engine = engine.getClientEngine();
        }
        WSDDDocument wsddDoc = new WSDDDocument(root);
        EngineConfiguration config = engine.getConfig();
        if (config instanceof WSDDEngineConfiguration) {
            WSDDDeployment deployment =
                ((WSDDEngineConfiguration)config).getDeployment();
            wsddDoc.deploy(deployment);
        }
        engine.refreshGlobalOptions();
        engine.saveConfiguration();
        doc = XMLUtils.newDocument();
        doc.appendChild( root = doc.createElementNS("", "Admin" ) );
        root.appendChild( doc.createTextNode( Messages.getMessage("done00") ) );
        return doc;
    }

上述代码的几个 if 我都省略了,因为那不重要,不过 action 也是我们完全可控的,但是这几个if中的功能代码根本不痛不痒,不能做到 rce 的效果,此时我们能够完全掌控的就是 root 变量,它被带入了 WSDDDocument 构造函数中,跟进去如下:

诶,又对当前标签名作了一次判断,而且看见了 undeployment 和 deployment 这种和 WebService 密切相关的变量名,undeployment 不感兴趣,继续跟进 WSDDDeployment 构造函数:

public WSDDDeployment(Element e)
            throws WSDDException {
        super(e);
        [...]
        elements = getChildElements(e, ELEM_WSDD_SERVICE);
        for (i = 0; i < elements.length; i++) {
            try {
                WSDDService service = new WSDDService(elements[i]);
                deployService(service);
            } catch (WSDDNonFatalException ex) {
                // If it's non-fatal, just keep on going
                log.info(Messages.getMessage("ignoringNonFatalException00"), ex);
            } catch (WSDDException ex) {
                // otherwise throw it upwards
                throw ex;
            }
        }
        [...]
    }

还记得之前的 server-config.wsdd 文件对 service 的描述内容吗,如下:

<service name="AdminService" provider="java:MSG">
 <namespace>http://xml.apache.org/axis/wsdd/</namespace>
 <parameter name="allowedMethods" value="AdminService"/>
 <parameter name="enableRemoteAdmin" value="ture"/>
 <parameter name="className" value="org.apache.axis.utils.Admin"/>
</service>

如上配置代码,是直接用 service 标签包裹的,所以我们在 WSDDDeployment 构造函数中直接瞄准 service 关键词,上面贴出来的代码中,ELEM_WSDD_SERVICE 意义如下:

首先,这个类型为 Element 的 e 变量是我们从客户端传递的,所以完全可控,在WSDDDeployment 构造函数中,只要 e 的子节点中含有 service 标签就将其还原成 WSDDService 对象,并且调用 deployService 函数,一路跟进到 WSDDService 的 deployToRegistry 函数中,如下:

基本上就没有过多的操作了,我们先停一停,首先这个初始化过程仅仅是做了注册操作,虽然我们构造的参数被注册了,但是目前还没有下一步触发的地方,回到org.apache.axis.utils.Admin#processWSDD 中

如上,我们控制的 service 已经在 wsddDoc 中注册了,最后会调用一此 engine.refreshGlobalOptions 和 saveConfiguration ,这意味着刚刚的初始化操作很有可能会被保存进配置文件中,那么回想下 axis 的 WebService 操作似乎确实是由配置文件控制,那么到下次访问该服务的时候,是不是会刷新我们自己注册的 service 呢?

测试流程

先下载 Apache Axis 1.4 版本的源码或者是安装包
源码在GitHub上有,安装包在:http://apache.fayea.com/axis/axis/java/1.4/

然后启动项目,直接访问 localhost:8080/servlet/AxisServlet

当前只有两个 WebService 端口,在 WEB-INF/server-config.wsdd 中也只有两个 service 标签,如下:

(其 enableRemoteAdmin 已经被我改成 ture,默认为 false)

那么此时我们随便构造一个POST包,发过去看看能不能新建一个 WebService 端口

访问刚刚的网页:

已经含有报错,此时看看server-config.wsdd 文件中的 service 标签:

如上图,确实是我们自己添加的内容,那么访问一下 /services/a?wsdl

虽然报错了,但是这表明,我们在 POST 自定义配置过后,是可以立刻生效的,这估计也是 Asix 基于配置文件驱动有关。

那么我们现在可以干什么,这就需要对 WebService 有一定的了解了,可以将 WebService 看作一个个微型服务端口,只要有相关配置,可以做到单个函数级别的调用。那么在我们完全可控配置文件的情况下,这就意味着我们可以调用”任意函数”

不能完全做到随心所欲,需要满足 WebService 的规则,比如 端口类 需要有一个 public 的无参构造函数,还要需要当前 ClassLoader 能够找得到指定类,最后也是最麻烦的则是指定函数的参数匹配,没有详细研究这个老框架,不知道复杂类型的传参是否允许

利用

现在我们知道可以在有限条件下调用任意函数,那么如何利用?还有和通告中的 freemarker 有啥关系?

在腾讯云的预警中找到了一句:

Apache AXIS中的freemarker组件中调用template.utility.Execute类时存在远程命令执行攻击

查看 Execute 类:

直接将传递进来的参数作为命令执行的参数,而且参数类型是 List ,那么基本可以确定这个应该可以利用(List在xml结构中可以看作Array结构)

不过似乎少个public无参构造函数?查看一下字节码:

原来只是没有反编译出来而已

那么我们就可以构造两个POST包:

第一个包设置配置文件,将 freemarker.template.utility.Execute 作为一个 WebService 的端口,并且开放 exec 函数,第二个包访问设定的 WebService 端口,并且发送SOAP操作,调用服务端的 freemarker.template.utility.Execute#exec 函数

效果如下:

第一次请求:

第二次请求:

(以上流程我是将freemarker-2.3.23.jar 添加进 WEB-INF/lib 中的,Axis 本身没有这个jar包)
当然也可以在 Axis 自带的 libs 中搜寻利用类,所需条件上文已经阐述过

总结

其实这个漏洞和 freemarker 没有啥必然联系,主要是因为 Axis 的未授权访问,可是默认配置下是不允许远程访问 AdminService 端口的,不过还是学习了 Axis 的处理方式,之前所了解到的 WebService 都是通过注解操作,但其实反过来想想,注解或是配置文件都一样,都需要框架底层自行实现解析流程

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now