当启动 第一种开在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
Comments NOTHING