Ghostcat Tomcat


简介

AJP是Apache提供的完成与其它服务器通讯的一种协议,用的是二进制传输,比HTTP文本传输有更高的效率。

请求传输到tomcat的数据一般先经由tomcat中的连接器(connector),tomcat connector组件负责解析客户端发来的报文并封装成request对象,还负责组装响应回客户端的报文将其封装成Response对象。

HTTP协议的连接器默认监听8080端口,负责建立HTTP连接。通过浏览器访问Tomcat服务器的web应用时使用的就是HTTP Connector。

AJP协议的连接器默认监听8009端口,负责和其他HTTP服务器建立连接,在tomcat与其他HTTP服务器连接时用的就是,AJP Connector。

AJP与HTTP的配置在conf/server.xml中

img

漏洞利用流程跟踪

环境准备:

​ 首先下载tomcat存在AJP协议漏洞的版本源码文件并配置用idea打开项目,具体步骤可参考Tomcat源码编译,如果访问tomcat首页出现500错误可在org.apache.catalina.startup.ContextConfig 类中增加如下一行初始化jsp解析。

img

poc(https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi)

流程分析:

​ AJP协议的请求在tomcat中内的请求流程与HTTP相似,主要走向为AjpProcessor类->service()->prepareRequest()。而AJP协议漏洞产生是因为tomcat对ajp传递过来的数据处理存在问题,导致我们可以控制”javax.servlet.include.request_uri”,”javax.servlet.include.path_info”,”javax.servlet.include.servlet_path”,从而读取文件或者文件包含。

因此对流程分析时首先从AjpProcessor类的service()处断点开始debug然后在kali中运行poc发起ajp请求

img

在poc中我们设置了AJP协议的三个参数

img

而在tomcat对ajp请求处理流程中设置参数的位置在AjpProcessor.AjpProcessor()方法中

img

AjpProcessor.AjpProcessor()方法调用了request.setAttribute()方法来设置参数值,这次的AJP请求中该方法会被循环执行三次,这里我们可以继续跟入request.setAttribute()方法。

img

如上图requests.setAttribute()方法被循环三次的过程中,poc构造的三个参数会被存入attributes这个hashmap,这里就是漏洞触发的第一个点。

在继续后面servlet的分析之前可以复现一遍整个过程用wireshark抓取数据包观察

img

在请求中有四个重要参数,我们请求的URI是”/asdf”这是一个在后台中并不存在的servlet。Tomcat中有两个默认定义的servlet,一个是Defaultservlet另一个是Jspservlet,当URI无法匹配任何servlet时,会由Defaultservlet来处理。而DefaultServlet处理流程是DefaultServlet类->service()->doGet()/doPost(),这里使用的poc中默认get请求,所以直接在DfaultServlet类下的doGet()方法处断点然后执行poc发送请求。

img

doGet方法调用了saveResource()方法,跟进saveResource()方法发现serveResource()方法又调用了getRelativePath()方法来对请求的路径进行拼接

img

跟入getRelativePath()方法可以发现,这里就是将我们传入的path_info 、servlet_path 进行复制、拼接的地方,其中request_uri用来做判断,如果传递进来的request_uri为空则漏洞利用失败。

img

再来观察getResource方法

img

getResource调用了非法路径检测函数vaildate()并传入了path值来判断路径是否符合限制条件

img

在vaildate()方法中定义了传入path的限制,因此文件读取操作中不能由/../这形式

img

img

最后回到getResource()方法开始文件读取漏洞利用。

img

RCE

之前提到过tomcat默认的servlet有两个,触发文件读取的是Defaultservlet,当URI以.jsp结尾时默认匹配Jspservlet

1.根据JSP文件生成对应Servlet的Java代码(JSP文件生成类的父类我org.apache.jasper.runtime.HttpJspBase——实现了Servlet接口)

2.将Java代码编译为Java类。

3.构造Servlet类实例并且执行请求。

其实本质核心就是通过JspServlet来执行我们想要访问的.jsp文件

所以想要RCE的前提就是,先要想办法将写有自己想要执行的命令的文件(可以是任意文件后缀,甚至没有后缀)上传到webapps的目录下,才能访问该文件然后通过JSP模板的解析造成RCE。

参考文章

1、https://mp.weixin.qq.com/s/hH0dpRWml0Rt7FxFOsWcMg

2、https://xz.aliyun.com/t/7683

3、https://blog.csdn.net/qq_35262405/article/details/101780644


文章作者: jokerscar
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 jokerscar !
  目录