TomcatAJP檔案包含漏洞及線上修復漏洞

men發表於2020-09-12

漏洞概述

2020年2月20日,國家資訊保安漏洞共享平臺(CNVD)釋出關於Apache Tomcat的安全公告,Apache Tomcat檔案包含漏洞(CNVD-2020-10487,對應CVE-2020-1938)。

Tomcat AJP協議由於存在實現缺陷導致相關引數可控,攻擊者利用該漏洞可通過構造特定引數,讀取伺服器webapp下的任意檔案。若伺服器端同時存在檔案上傳功能,攻擊者可進一步實現遠端程式碼的執行。

由於Tomcat在處理AJP請求時,未對請求做任何驗證,通過設定AJP聯結器封裝的request物件的屬性, 導致產生任意檔案讀取漏洞和程式碼執行漏洞

CVE-2020-1938 又名GhostCat, 之前引起了一場風雨,由e長亭科技安全研究員發現的存在於Tomcat中的安全漏洞,由於Tomcat AJP協議設計上存在缺陷,攻擊者通過 Tomcat AJP Connector 可以讀取或包含 Tomcat 上所有 webapp 目錄下的任意檔案,例如可以讀取 webapp 配置檔案或原始碼。此外在目標應用有檔案上傳功能的情況下,配合檔案包含的利用還可以達到遠端程式碼執行的危害。

影響範圍
Apache Tomcat 9.x < 9.0.31
Apache Tomcat 8.x < 8.5.51
Apache Tomcat 7.x < 7.0.100
Apache Tomcat 6.x

本次漏洞與三個include屬性有關

javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path
任意檔案讀取

任意檔案讀取問題出現在org.apache.catalina.servlets.DefaultServlet這個Servlet

構造一個AJP請求,請求會走預設的DefaultServlet並交給DefaultServletdoGet方法處理。
doGet會呼叫ServeResource方法獲取資原始檔,呼叫getRelativePath方法獲取要讀取資源的相對路徑,通過getResources方法就可以獲取到了對應路徑的Web資源物件。
然後再通過控制ajp控制的上述三個include屬性來讀取檔案,通過操控上述三個屬性從而可以讀取到/WEB-INF下面的所有敏感檔案,不限於class、xml、jar等檔案。

任意程式碼執行

任意程式碼執行問題出現在org.apache.jasper.servlet.JspServlet這個servlet

構造一個如下的AJP請求,讓Tomcat執行/docs/test.jsp,但實際上它會將code.txt當成jsp來解析執行。

RequestUri:/docs/test.jsp
javax.servlet.include.request_uri: /
javax.servlet.include.path_info: code.txt
javax.servlet.include.servlet_path: /

code.txt內容如下

<%
	java.util.List<String> commands = new java.util.ArrayList<String>();
	commands.add("/bin/bash");
	commands.add("-c");
	commands.add("/Applications/Calculator.app/Contents/MacOS/Calculator");
	java.lang.ProcessBuilder pb = new java.lang.ProcessBuilder(commands);
	pb.start();
%>

傳送AJP請求,請求的是/docs/test.jsp這個jsp,但是由於那三個include屬性可控,可以將test.jsp對應的伺服器指令碼檔案改為code.txt,導致tomcat把我們的code.txt當jsp檔案編譯執行,導致程式碼執行。

TomcatAJP Connector以及AJP協議

Tomcat Connector 是 Tomcat 與外部連線的通道,它使得 Catalina 能夠接收來自外部的請求,傳遞給對應的 Web 應用程式處理,並返回請求的響應結果。

預設情況下,Tomcat 配置了兩個 Connector,它們分別是 HTTP ConnectorAJP Connector:

// HTTP Connector:用於處理 HTTP 協議的請求(HTTP/1.1),預設監聽地址為 0.0.0.0:8080

// AJP Connector:用於處理 AJP 協議的請求(AJP/1.3),預設監聽地址為 0.0.0.0:8009

HTTP Connector 就是用來提供我們經常用到的 HTTP Web 服務。而 AJP Connector,它使用的是 AJP 協議(Apache Jserv Protocol),AJP 協議可以理解為 HTTP 協議的二進位制效能優化版本,它能降低 HTTP 請求的處理成本,因此主要在需要叢集、反向代理的場景被使用。

AJP是Apache Tomcat web伺服器用來與servlet容器通訊的一個二進位制協議。主要用於叢集或逆向代理場景,其中web伺服器與應用伺服器或servelet容器進行通訊。

簡單來說,就是HTTP Connector暴露給客戶端了,AJP是webserver (如Apache HTTPD)和Apache Tomcat伺服器之間內部使用的,如下圖所示。AJP在Apache HTTP伺服器中是以模組的形式實現的,表示為mod_jk或mod_proxy_ajp。AJP本身並不會暴露到外部,這也是下一部分要討論的RCE場景的先決條件之一。

漏洞修復

升級版本

將Tomcat立即升級到9.0.31,8.5.51或7.0.100版本進行修復

升級步驟

1.下載要升級的Tomcat版本

wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.51/bin/apache-tomcat-8.5.51.tar.gz

2. 停止舊版本tomcat

cd /home/…/tomcat_8/bin
./shutdown.sh

# 建立新的tomcat路徑,備份舊的tomcat服務
mkdir /home/…/tomcat_8_old
cp -Rf /home/…/tomcat_8/* /home/…/tomcat_8_old/

# 安裝目錄下解壓新的tomcat
tar -zxvf apache-tomcat-8.5.51.tar.gz

# 刪除舊的服務檔案,將新的服務名稱改成之前的
rm -rf tomcat_8
mv apache-tomcat-8.5.51 tomcat_8

# 用備份的server.xml替換新的server.xml
cd /home/…/tomcat_8/conf/
cp /home/…/tomcat_8_old/conf/server.xml ./

# 用備份的webapps替換新的webapps
cd /home/…/tomcat_8/
cp /home/…/tomcat_8_old/webapps ./

# 用備份的catalina.sh替換新的
cd /home/…/tomcat_8/bin/
cp /home/…/tomcat_8_old/bin/catalina. sh ./


# 我這裡的備份路徑下有一些日誌資訊也一併移過來
mv /home/…/tomcat_8_old/logs/* /home/…/tomcat_8/logs/


# 啟動tomcat
cd /home/…/tomcat_8/bin
./startup.sh
隱藏版本

可以的話做一下隱藏版本資訊

cd cd apache-tomcat-8.5.51/lib
unzip catalina.jar
vim ServerInfo.properties 
# 自定義修改 server.number和server.built的配置  
server.info=Apache Tomcat
server.number=sb
server.built=sb


cd  /opt/apache-tomcat-8.5.51/lib
jar uvf catalina.jar org/apache/catalina/util/ServerInfo.properties

# 重啟服務即可

tomcat在8.5.51版本做了如下修復

// 預設不開啟AJP
// 預設只監聽本地ip
// 強制設定認證secret
// 程式碼層面主要在AjpProcessor類的prepareRequest方法封裝requst物件時採用了白名單,只新增已知屬性。這樣三個include屬性不再被客戶端控制,漏洞修復。
禁用AJP協議

編輯/conf/server.xml,找到如下行

<Connector port="8009"protocol="AJP/1.3" redirectPort="8443" />

將此行註釋掉(也可刪掉該行)

<!--<Connectorport="8009" protocol="AJP/1.3"redirectPort="8443" />-->
配置secret來設定AJP協議的認證憑證

例如(注意將您的tomcat_ajp_secret更改為一個安全性高,無法被輕易猜解的值)

<Connector port="8009"protocol="AJP/1.3" redirectPort="8443"address="YOUR_TOMCAT_IP_ADDRESS" secret="YOUR_TOMCAT_AJP_SECRET"/>

相關文章