





2,修改一個屬性設置
https://github.com/apache/tomcat/commit/40d5d93bd284033cf4a1f77f5492444f83d803e2
強制設置認證secret,否則不啟動AJP Connector
3,添加一個新AJP屬性
https://github.com/apache/tomcat/commit/b99fba5bd796d876ea536e83299603443842feba
應該就是新屬性這里。
因為原本的代碼里面會把不識別的屬性添加進去,從而導致操縱內部數據。(但怎么操縱呢?)

注意公告里面的這句話
相關參數可控,構造特定參數”
與及兩種利用方式
1、利用DefaultServlet實現任意文件下載 (不帶后綴)
2、通過jspservlet實現任意后綴文件包含 (帶jsp后綴)
這下子就全明白了,接下來就是下載tomcat源碼調試了。
0x02 環境搭建
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.apache.tomcat</groupId> <artifactId>Tomcat7.0.99</artifactId> <name>Tomcat7.0.99</name> <version>7.0</version> <properties> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>ant</groupId> <artifactId>ant-apache-log4j</artifactId> <version>1.6.5</version> </dependency> <dependency> <groupId>ant</groupId> <artifactId>ant-commons-logging</artifactId> <version>1.6.5</version> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>javax.xml.rpc</groupId> <artifactId>javax.xml.rpc-api</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.eclipse.jdt.core.compiler</groupId> <artifactId>ecj</artifactId> <version>4.5.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>Tomcat7.0</finalName> <sourceDirectory>java</sourceDirectory> <resources> <resource> <directory>java</directory> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <encoding>UTF-8</encoding> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> </project>
成功跑起來(后補的圖)

回到正題,代碼太水,手擼時間花費太多了,直接找別人寫好的,github大法好,直接搜索ajp

接着研究一下代碼,改寫一下就可以發送我們自己的屬性了。
wireshark抓包,跟xray的poc一樣了
0x03 源碼調試

跟進,直接跟進到Decode extra attributes,也就是獲取解析屬性設置屬性的地方
循環獲取,switch判斷,看到如果case是屬性類型,在最后的一個else里面把沒有判斷到的屬性直接設置到request里面
代碼接着往下走,在預處理完了request headers之后,在adapter里面處理request
接着調用容器來處理
根據請求的url是否帶JSP后綴,tomcat會將request交由不同的servlet來處理
不帶jsp后綴的,直接用DefaultServlet來處理的情況(文件讀取)
在HttpServlet中根據請求方法調用不同的方法處理
這里方法是GET,一路跟進去
跟進,最后看到處理路徑的方法getRelativePath
也就是在這里對安恆說的那三個值進行判斷
當javax.servlet.include.request_uri不為空的時候,取javax.servlet.include.path_info和javax.servlet.include.servlet_path的值進行拼接,然后返回path,之后進入lookupCache方法
這里面的流程先是在緩存里面找,找不到了,然后在本地找,最終來到 org.apache.naming.resources.FileDirContext 的file方法,然后new一個File類對象。
在File構造函數中會對path進行凈化,限制了跨目錄
調用棧
file:811, FileDirContext (org.apache.naming.resources) doLookup:208, FileDirContext (org.apache.naming.resources) doLookupWithoutNNFE:494, BaseDirContext (org.apache.naming.resources) lookup:475, BaseDirContext (org.apache.naming.resources) lookupCache:1463, ProxyDirContext (org.apache.naming.resources) serveResource:831, DefaultServlet (org.apache.catalina.servlets) doGet:435, DefaultServlet (org.apache.catalina.servlets) service:621, HttpServlet (javax.servlet.http) service:415, DefaultServlet (org.apache.catalina.servlets) service:728, HttpServlet (javax.servlet.http) internalDoFilter:303, ApplicationFilterChain (org.apache.catalina.core) doFilter:208, ApplicationFilterChain (org.apache.catalina.core) invoke:219, StandardWrapperValve (org.apache.catalina.core) invoke:110, StandardContextValve (org.apache.catalina.core) invoke:492, AuthenticatorBase (org.apache.catalina.authenticator) invoke:165, StandardHostValve (org.apache.catalina.core) invoke:104, ErrorReportValve (org.apache.catalina.valves) invoke:1025, AccessLogValve (org.apache.catalina.valves) invoke:116, StandardEngineValve (org.apache.catalina.core) service:452, CoyoteAdapter (org.apache.catalina.connector) process:190, AjpProcessor (org.apache.coyote.ajp) process:654, AbstractProtocol$AbstractConnectionHandler (org.apache.coyote) run:317, JIoEndpoint$SocketProcessor (org.apache.tomcat.util.net) runWorker:1145, ThreadPoolExecutor (java.util.concurrent) run:615, ThreadPoolExecutor$Worker (java.util.concurrent) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:745, Thread (java.lang)
最后就是將讀取到的資源輸出回來
帶JSP后綴jspservlet處理情況(文件包含)
在jspservlet的service方法斷點,從request中屬性中取出org.apache.catalina.jsp_file的值放到jspFile中,之后傳入到serviceJspFile中處理。
繼續跟進,會先判斷jsp 文件是否存在,如果存在,隨后才會初始化wrapper,最后調用JspServletWrapper的service方法來解析。
這里繼續跟進getResource,當System.getSecurityManager()=true的時候,可從遠程加載文件
繼續走,先是對path進行規范化處理
繼續跟進,到最后同樣也是在org.apache.naming.resources.FileDirContext file方法中新創建一個File對象,判斷文件是否存在。
而其中base變量的值為訪問的容器的web根目錄
在org.apache.tomcat.util.http.mapper internalMapExtensionWrapper方法進行一系列判斷,設置wrapper,其中有判斷,根據后綴設置warpper,當后綴為jsp或jspx的時候都會用jspServlet來處理
調用棧如下:
internalMapExtensionWrapper:1170, Mapper (org.apache.tomcat.util.http.mapper) internalMapWrapper:945, Mapper (org.apache.tomcat.util.http.mapper) internalMap:874, Mapper (org.apache.tomcat.util.http.mapper) map:742, Mapper (org.apache.tomcat.util.http.mapper) postParseRequest:782, CoyoteAdapter (org.apache.catalina.connector) service:446, CoyoteAdapter (org.apache.catalina.connector) process:190, AjpProcessor (org.apache.coyote.ajp) process:654, AbstractProtocol$AbstractConnectionHandler (org.apache.coyote) run:317, JIoEndpoint$SocketProcessor (org.apache.tomcat.util.net) runWorker:1145, ThreadPoolExecutor (java.util.concurrent) run:615, ThreadPoolExecutor$Worker (java.util.concurrent) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:745, Thread (java.lang)
具體的處理邏輯就不說了