当启动 第一种开在8080端口,用于平常的 我们知道运行在 而 从 重点来看看 其中 根据最开始安恒发出文章讲到 我们就开始分析为什么这三个属性会被控制? 从调用栈可以看到,消息先是被 继续往下调试,跟进位于 可以看到 直接去找设置 跳到 继续循环, 当三个属性赋值完成后,就进入了 一直跟进 分析到这里,可能有同学就会发现和正常的http请求部分的调用栈开始重合了,没错,到了这里就会进入一系列的 来到 继续跟进 发现在获取资源之前, 继续跟进: 跟到 接着传入到 The Apache Tomcat Connectors - AJP Protocol Reference
1. 前置知识
1. AJP协议
tomcat时,tomcat会暴露两种连接方式:<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
http请求,以8080端口作为web服务时,tomcat不仅接管静态文件的解析,如:html、js、图片等,而且处理后端动态请求。但是由于tomcat对于静态文件的处理比不上apache等,所以设计者想出了一个办法将tomcat与其他的web服务器连接起来,即:例如apache专门用于处理静态文件,而tomcat用来处理servlet请求。而将两者连接起来的便是AJP协议。tomcat服务器上的是servlet就是一个个小程序,用于处理到来的请求。web服务器会将会将消息分为不同的种类发送给servlet container,类型如下:Code Type of Packet Meaning
2 Forward Request Begin the request-processing cycle with the following data
7 Shutdown The web server asks the container to shut itself down.
8 Ping The web server asks the container to take control (secure login phase).
10 CPing The web server asks the container to respond quickly with a CPong.
none Data Size (2 bytes) and corresponding body data.
servlet container在处理完对应的消息后,也会将消息以不同类型的种类发送给web服务器:Code Type of Packet Meaning
3 Send Body Chunk Send a chunk of the body from the servlet container to the web server (and presumably, onto the browser).
4 Send Headers Send the response headers from the servlet container to the web server (and presumably, onto the browser).
5 End Response Marks the end of the response (and thus the request-handling cycle).
6 Get Body Chunk Get further data from the request if it hasn't all been transferred yet.
9 CPong Reply The reply to a CPing request
web服务器到servlet container的消息会以0x1234作为开头然后是length和code type:
从servlet container到web服务器则会以0xAB开头然后是length和code type:
Foward Request类型的结构体:AJP13_FORWARD_REQUEST :=
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (integer)
is_ssl (boolean)
num_headers (integer)
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF
----------------------------------------------------------
The request_headers have the following structure:
req_header_name :=
sc_req_header_name | (string) [see below for how this is parsed]
sc_req_header_name := 0xA0xx (integer)
req_header_value := (string)
----------------------------------------------------------
The attributes are optional and have the following structure:
attribute_name := sc_a_name | (sc_a_req_attribute string)
attribute_value := (string)
method又有如下类型:Command Name Code
OPTIONS 1
GET 2
HEAD 3
POST 4
PUT 5
DELETE 6
TRACE 7
PROPFIND 8
PROPPATCH 9
MKCOL 10
COPY 11
MOVE 12
LOCK 13
UNLOCK 14
ACL 15
REPORT 16
VERSION-CONTROL 17
CHECKIN 18
CHECKOUT 19
UNCHECKOUT 20
SEARCH 21
MKWORKSPACE 22
UPDATE 23
LABEL 24
MERGE 25
BASELINE_CONTROL 26
MKACTIVITY 27
attribute的类型:Information Code Value Note
?context 0x01 Not currently implemented
?servlet_path 0x02 Not currently implemented
?remote_user 0x03
?auth_type 0x04
?query_string 0x05
?route 0x06
?ssl_cert 0x07
?ssl_cipher 0x08
?ssl_session 0x09
?req_attribute 0x0A Name (the name of the attribut follows)
?ssl_key_size 0x0B
?secret 0x0C
?stored_method 0x0D
are_done 0xFF request_terminator
2. DefaultServlet
DefaultServlet配置位于tomcat的conf/web.xml中,这个web.xml用来弥补我们开发程序中web.xml没有写到的地方,比如:一些静态资源我们并没有去匹配的url,这时default servlet就派上用场了。 <servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3. JspServlet
JspServlet同样位于tomcat的conf/web.xml中,用于处理后缀为jsp、jspx的请求: <servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
2. webapp目录下的任意文件下载分析
AJP程序处理后的消息可以控制request的三个属性:javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path
socket程序处理,然后才传递到AjpProcesser:
跟到org/apache/coyote/ajp/AjpProcessor.class:122可以看到传入的消息类型是2,正好是Forward Request类型
org/apache/coyote/ajp/AjpProcessor.class:169的函数:this.prepareRequest()
prepareRequest()函数用于设置Forward Request结构体:
attribute的地方,可以看到在org/apache/coyote/ajp/AjpProcessor.class:391属性的值为10,根据之前讲到的来看10代表req_attribute,即用来设置request对象的属性:
org/apache/coyote/ajp/AjpProcessor.class:433,可以看到javax.servlet.include.request_uri被赋值为/:
javax.servlet.include.path_info 被赋值为WEB-INF/web.xml:
javax.servlet.include.servlet_path 被赋值为/:
servlet的映射,跟进org/apache/coyote/ajp/AjpProcessor.class:187的this.getAdapter().service(this.request, this.response)函数:
invoke函数,然后来到org/apache/catalina/core/StandardContextValve.class:26,可以看到这里对WEB-INF和META-INF进行了限制,这就是我们为什么不能直接访问WEB-INF目录的原因:
value类和filter类,最后把请求传入到DefaultServlet类:
org/apache/catalina/servlets/DefaultServlet.class:275的doGet()函数,继续跟进this.serveResource(request, response, true, this.fileEncoding)方法:
org/apache/catalina/servlets/DefaultServlet.class:486的this.resources.getResource(path)函数:
tomcat还会对传入的路劲进行一次合法性验证,看到:org/apache/catalina/webresources/StandardRoot.class:205的validate()函数:
org/apache/catalina/webresources/StandardRoot.class:213的RequestUtil.normalize(path, false)函数,可以看到normalize函数会对目录穿越符号../或者./进行修正,这也就解释了我们为什么跳不到更上一级的目录去读文件:
3. 任意文件包含分析
/org/apache/jasper/servlet/JspServlet.class:171的service函数,可以看到jsp文件的路径会取javax.servlet.include.servlet_path和javax.servlet.include.path_info的拼接:
org/apache/jasper/servlet/JspServlet.class:201的this.serviceJspFile(request, response, jspUri, precompile)去编译:
4. 参考
Tomcat源码分析之 doGet方法
Web.xml详解
【WEB安全】Tomcat-Ajp协议漏洞分析
CNVD-2020-10487-Tomcat-Ajp-lfi
Tomcat-AJP协议漏洞分析
发布于 2020-02-22 3305 次阅读 Java Web 安全
Comments NOTHING