0x01. 前言
時隔應該快一年了吧,具體ghost這個漏洞出來我也忘記了,由于我最近無聊,然后想起我使用的Tomcat有沒有漏洞,于是我就來試了試,順便分析一下這段已經時隔許久的漏洞,依稀記得上次的文章是簡單的復現~~ 反正是閑的無聊

0x02. 環境部署
idea2020.2 + tomcat7.0.99+jdk1.8
具體參考這篇文章,idea導入Tomcat源碼:
環境與exp打包好,在附件中~,收1金幣應該問題不大,我想社區幣去抽華子
https://blog.csdn.net/u013268035/article/details/81349341
https://www.cnblogs.com/r00tuser/p/12343153.html
0x03.漏洞的基礎
Tomcat部署的時候會有兩個重要的文件


而Tomcat在 server.xml中配置了兩種連接器。其中包含的是AJP Connector和HTTP Connector
AJP Connector說明啟用了8080和8009端口,這時候我們可以看一下

而相對于,8080我們是可以訪問的

也就是說,8080是負責Http協議,8009負責接收ajp協議;
提問1:AJP協議和HTTP協議有什么區別嗎?
HTTP協議:負責接收建立HTTP數據包,成為一個web服務器,處理HTTP協議的同時還額外可處理Servlet和jsp
AJP協議: 負責和其他的HTTP服務器建立連接, 通過AJP協議和另一個web容器進行交互
Web用戶訪問Tomcat服務器的兩種方式

而一個Tomcat就是一個server,其中包含多個service;而每個service由Connector、Container、Jsp引擎、日志等組件構成,造成漏洞的關鍵地方是Connector、Container
Connector上面已經說過分別是AJP Connector和HTTP Connector ,是用來接受客戶端的請求,請求中的數據包在被Connector解析后就會由Container處理。這個過程大致如下圖:

一次請求的處理可以劃分為Connector及Container進行處理,經歷的過程大致如下:
- 一個TCP/IP數據包發送到目標服務器,被監聽此端口的Tomcat獲取到。
- 處理這個Socket網絡連接,使用Processor解析及包裝成request和response對象,并傳遞給下一步處理。
- Engine來處理接下來的動作,匹配虛擬主機Host、上下文Context、MApping Table中的servlet。
- Servlet調用相應的方法(service/doGet/doPost…)進行處理,并將結果逐級返回。小結
對于使用HTTP協議或AJP協議進行訪問的請求來講,在解析包裝成為request和response對象之后的流程都是一樣的,主要的區別就是對 socket流量的處理以及使用Processor進行解析的過程的不同

也就是第二步的地方出現問題
0x04.源碼分析
通過第三步中,我們知道是Processor的解析過程不同,而提供這部分功能的接口,在
org.Apache.coyote.Processor,主要負責請求的預處理。

而此處AjpProcessor則是處理ajp協議的請求,并通過它將請求轉發給Adapter,針對不用的協議則具有不同的實現類。
我們從上面wirshark抓包可以看出

可以看出這邊是設置了三個莫名其妙的東西

通過exp源碼可以看到這邊是設置了三個域對象的值


可以看出,我們這邊是執行成功了,由于wirshark抓包沒有去截圖,又關閉了,所以就不截圖了
這邊可以假設:請求參數時是寫死,也就是xxx.jsp文件,而jsp后綴等等原因,然后成功進行了文件包含
那么我們的test.txt是怎么識別的?
我們繼續往下看,來解決種種疑惑

知道是這個prepareRequest()問題,我們f7跟進去看看

進入了該方法的內部,我們繼續跟進查看,這邊進行判斷,獲取到了請求參數為GET

首先是一些解析數據包讀取字節的操作

while循環獲取,switch判斷


當attributeCode=10時,則進入第一條分支,繼續f8進去



是不是有了有種眼熟的感覺~~~ 其實就是往域對象中存值

由于if都不滿足,直接進入了最后這個比進的else分支

最后進入第二個步驟的最后一小步,f8繼續下一步走,在預處理完了request headers之后,在adapter里面處理request,然后調用Adapter將請求交給Container處理


進入service方法,然后f8一直跟進

直到跟進此處,請求會發送到對應的servlet,我們請求的是一個jsp文件,根據tomcat的默認web.xml文件

通過上面假設,tomcat默認將jsp/jspx結尾的請求交給
org.apache.jasper.servlet.JspServlet處理,它的service()方法如下:

而jspUri等于null,滿足條件,則進入該if條件分支

由于
JAVAx.servlet.include.servlet_path可控制,通過getAttribute去域對象中獲取屬性名為
javax.servlet.include.servlet_path的值,得到值為 test.txt

此時,jspUri的值為/test.txt

pathInfo的值此時為空

最后一直到下面,傳入serviceJspFile方法中

繼續跟進,會先判斷文件是否存在,如果存在,隨后才會初始化wrapper,最后調用JspServletWrapper的service方法來解析,從而導致本地文件包含

參考
https://gitee.com/wdragondragon/javasec/blob/master/tomcat%20ajp%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.md
https://www.cnblogs.com/r00tuser/p/12343153.html
https://xz.aliyun.com/t/7325#toc-6
https://zhishihezi.net/b/5d644b6f81cbc9e40460fe7eea3c7925#