<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
HTTP Connector很好理解,通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器;
AJP Connector是通过AJP协议和一个Web容器进行交互。在将Tomcat与其他HTTP服务器(一般是Apache )集成时,就需要用到这个连接器。AJP协议是采用二进制形式代替文本形式传输,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。
两个Connector的原理如下图所示:
我们的浏览器肯定是不支持AJP协议的,所以要在AJP Connector前面加一个apache server的反向代理,我们先将http请求交到反向代理服务器,反向代理服务器再通过ajp协议在8009端口向tomcat发出请求。
(2)Servlet(服务程序)
Servlet意为服务程序,也可简单理解为是一种用来处理网络请求的一套规范。主要作用是给上级容器(Tomcat)提供doGet()和doPost()等方法,其生命周期实例化、初始化、调用、销毁受控于Tomcat容器。有个例子可以很好理解:想象一下,在一栋大楼里有非常多特殊服务者Servlet,这栋大楼有一套智能系统帮助接待顾客引导他们去所需的服务提供者(Servlet)那接受服务。这里顾客就是一个个请求,特殊服务者就是Servlet,而这套智能系统就是Tomcat容器。
tomcat默认配置了两个Servlet,一个是Jsp Servlert,另一个是Default Servlet,第一个是专门负责处理jsp类型的文件的,除了jsp文件的全都交给Default Servlet处理。Tomcat中Servlet的配置是在conf/web.xml 下面。
<!-- The default servlet for all web applications, that serves static -->
<!-- resources. It processes all requests that are not mapped to other -->
<!-- servlets with servlet mappings. -->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
......
......
</servlet>
<!-- The JSP page compiler and execution servlet, which is the mechanism -->
<!-- used by Tomcat to support JSP pages. Traditionally, this servlet -->
<!-- is mapped to the URL pattern "*.jsp". -->
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
......
......
</servlet>
......
......
<!-- The mapping for the default servlet -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
由以上配置文件也可以看出,如果是jsp文件的请求,回交给Jsp Servlert,其他的都交给Default Servlet进行处理。
(3)tomcat内部处理流程
在这里简单介绍一下处理流程就好,便于理解后续漏洞的分析。
- 用户点击网页内容,请求被发送到本机端口8080,被Connector获得(Connector中的Processor用于封装Request,Adapter用于将封装好的Request交给Container)。
- Connector把该请求交给Container中的Engine来处理,并等待Engine的回应。
- Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
- Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为" "的Context去处理)。
- path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类(匹配不到指定Servlet的请求对应DefaultServlet类)。
- Wrapper是最底层的容器,负责管理一个Servlet。构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost(),执行业务逻辑、数据存储等程序。
- Context把执行完之后的HttpServletResponse对象返回给Host。
- Host把HttpServletResponse对象返回给Engine。
- Engine把HttpServletResponse对象返回Connector。
- Connector把HttpServletResponse对象返回给客户Browser。
在介绍漏洞之前还要配一下tomcat源码分析的环境,大家可以根据这篇博文Tomcat源码编译(IDEA)_tomcat 编译_ww0peo的博客-CSDN博客
来进行配置,配置的版本是apache-tomcat-8.5.46,配置好了之后就可以愉快的进行漏洞的代码分析了。
根据上文的Tomcat处理请求流程,请求首先到达Connector,Connector内使用AjpProcessor
解析Socket,将Socket中的内容封装到Request中。然后经过一系列的处理,到达Servlet。根据上文我们可以了解到,tomcat默认配置两个Servlet,一个是Default Servlet,另一个是Jsp Servlet,而这这里就分别对应了文件读取漏洞和任意代码执行漏洞。
1.文件读取漏洞
当url未匹配到Servlet时,回给到Default Servlet处理。
分析org.apache.catalina.servlets.DefaultServlet.java 。请求到达 DefaultServlet 后, 会执行 service() 方法,判断请求的 DispatcherType 是否为 ERROR ,若是则直接调用 doGet() 方法,否则调用父类的 Service() 方法。
DefaultServlet 的父类为 HttpServlet (javax.servlet.http.HttpServlet.java)。其 service() 方法根据请求方法(method)决定调用 doGet() 或是 doPost() ,代码如下。此 处我们是读取文件,使用的是 doGet 方法。
然后回到子类,查询doGet方法。 通过serveResource方法来获取资源。
在serveResource方法中,它定义了我们获取资源的路径
跟踪进去,
我们发现了三个重要的参数,
INCLUDE_REQUEST_URI, INCLUDE_PATH_INFO, INCLUDE_SERVLET_PATH
发现这三个参数可以控制我们请求资源的路径,继续跟踪,发现这三个属性都有默认值
static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
这里就是我们利用的重点,我们可以通过发送数据包来伪造这几个默认值,从而控制路径,到后面我会用wireshark抓包看一下。
由上面截图中的代码可知,当 request 中 javax.servlet.include.request_uri 不为空时,将 request 的 javax.servlet.include.path_info 与 javax.servlet.include.servlet_path 分别赋值给 path_info 和 servlet_path。 而后只要 path_info 与 servlet_path 的值不为空,就将 path_info 与 servlet_path 拼接起来赋值给 result。
回到serveResource 方法,获取到路径后创建资源的实例并且获取资源。
跟踪进去getResource方法,(位于 org.apache.catalina.webresources.StandardRoot.java中)
我们发现上述代码调用了validate进行判断,继续跟着
在这里有主要用了normalize方法来进行校验,其主要功能如下:
1.判断path中是否有’\‘,有就转换成’/';
2.判断path是否以’/‘开头,若不是则在前面加上’/';
3.判断path是否以’/.‘或’/…‘结尾,若是则结尾加一个’/';
4.判断path是否含有’//‘,有则替换成’/';
5.判断path是否含有’/./‘,若有直接截断并重新拼接,如’/./abc’变为’/abc’
6.判断path是否含有’/…/',若有则直接返回null;
首先补充一个知识,当我们访问tomcat时,它会默认访问取webapps下的默认文件,而在这里对相对路径的符号进行了限制,所以我们利用该漏洞只能访问webapps下的文件。
在验证完成之后 ,会继续将资源返回到输出流中,再交由tomcat的内部进行处理。
至此利用过程结束,而我们可以通过刚才在 DefaultServlet 的 getRelativePath() 中说过的三个参数进行访问资源路径的控制。而我们首先还需要让请求到达 DefaultServlet ,需要让请求的 url 为 “/asdf” ,此处的 asdf 为随机字符串,目的是让 Tomcat 找不到 webapps 下的至指定文件,从而请求会到 Tomcat 的默认目录。
若是想请求 webapps 目 录下的其他目录,则可以设置为 ‘/指定目录/asdf’,如’’/manager/asdf’。会访问到webapps/manager/下的目录,具体的文件看我们构造的参数。
如要访问”webapps/ROOT/WEB-INF/web.xml”,首先将请求 url 为’/asdf’,再将 javax.servlet.include.request_uri 值设置为’/‘(非空), javax.servlet.include.servlet_path 的值设置为 ‘/‘,javax.servlet.include.path_info 的值设置为 ‘WEB-INF/web.xml’。
poc的下载地址为GitHub - YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi: Tomcat-Ajp协议文件读取漏洞
但是在python3.7.9的版本下运行会报错,这里我修改了poc,修改的poc放在了tomcat_Ghostcat/ at main · fengdianxiong/tomcat_Ghostcat · GitHub 上,大家可以自取。
成功获取文件 。
我们再来看一下对应的数据包:
发现在poc的数据包中携带了我们上面三个重要的参数,从而实现文件读取。
2.任意代码执行漏洞
这个漏洞稍微有一点点鸡肋,需要提前先自己上传木马文件,然后利用文件包含漏洞来实现代码执行。
由上文可知,我们知道当请求jsp文件时,会走Jsp Servlet来进行处理。
首先来到JspServlert.java(位于org.apache.jasper.servlet.JspServlet.java),经过service方法处理,由标红部分可以看出,jspUri由servlet_path和path_info拼接而成。
然后进入到serviceJspFile方法中,方法利用 jspUri 生成 JspServletWrapper 实例,再到调用实例的 service() 方法。
获取到对应的Servlet
调用该Servlet的service方法
请求执行,从而造成文件包含。
利用过程简单就是,我们通过传入 servlet_path 和 path_info ,让其去将指定的文件作为 jsp 文件处理,Tomcat 会将根据指定的文件生成 java 代码并编译成 class ,而后加载 class 类实例化一个 servlet 并执行,从而造成文件包含。
在复现时,要修改一下poc的参数,然后在webapps目录下的ROOT下(apache-tomcat-8.5.46-source\catalina-home\webapps\ROOT),自己创建一个1.txt,
内容为
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
g.cn/img_convert/95608e9062782d28f4f04f821405d99a.png)
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-nIgd6IL4-1712903532199)]