AjpProcessorprepareRequest() 中,恶意攻击者可通过控制请求内容,为request对象任意的设置属性。
switch/case 判断中,当attributeCode=10 时,将调用 request.setAttribute 方法存入。
4. AJP漏洞 - 图1
所以在此攻击者拥有了可控的点,这个点该如何利用呢?

DefaultServlet

$CATALINA_BASE/conf/web.xml 中默认配置了如下内容:
4. AJP漏洞 - 图2
可以看到这是一个默认的Servlet,这个 DefaultServlet 服务于全部应用,当客户端请求不能匹配其他所有Servlet时,将由此Servlet处理,主要用来处理静态资源。使用 serveResource() 方法提供资源文件内容:
4. AJP漏洞 - 图3
会调用 getRelativePath() 方法获取请求资源路径:
4. AJP漏洞 - 图4
这个方法存在一个判断,如图中红框位置标出:如果 request.getAttribute()javax.servlet.include.request_uri 不为空,则会取 javax.servlet.include.path_infojavax.servlet.include.servlet_path 的值,并进行路径拼接,返回路径结果。
这个结果 path 会被带入到 getResource() 方法中返回结果,只要文件存在,即可读取其中内容。
4. AJP漏洞 - 图5
由此可见,配合AJP协议中的缺陷,可以控制attribute中的内容,造成任意文件读取漏洞。
但是需要注意的是,在读取资源文件的过程中,会调用org.apache.tomcat.util.http.RequestUtil.normalize() 方法来对路径的合法性进行校验,如果存在 ./../ 则会返回 null ,在后续流程中会抛出一个非法路径的异常终止文件读取操作。
4. AJP漏洞 - 图6
因此我们无法使用 ../ 跳出目录,只能读取Web应用目录下的文件。

JspServlet

同样的在$CATALINA_BASE/conf/web.xml 中,对访问以 .jsp/*.jspx 后缀结尾的请求,调用 JspServlet 处理请求。
4. AJP漏洞 - 图7
看一下重点的 service(),代码如下图,在attribute中含有如下 javax.servlet.include.servlet_pathjavax.servlet.include.path_info 时,将会取出并拼接为文件路径 jspUri
4. AJP漏洞 - 图8
拼接成 jspUri 后,调用 serviceJspFile() ,将此文件解析为jsp文件并执行。
4. AJP漏洞 - 图9
因此这就构成了一个文件包含漏洞。在文件内容可控的情况下,就可以延伸为任意代码执行漏洞,所以网上有的分析文章也出现了任意代码执行、任意命令执行漏洞的字眼。