閱讀349 返回首頁    go 技術社區[雲棲]


CVE-2017-12615/CVE-2017-12616:Tomcat信息泄漏和遠程代碼執行漏洞分析報告

一. 漏洞概述

2017年9月19日,Apache Tomcat官方確認並修複了兩個高危漏洞,漏洞CVE編號:CVE-2017-12615和CVE-2017-12616,該漏洞受影響版本為7.0-7.80之間,官方評級為高危,在一定條件下,攻擊者可以利用這兩個漏洞,獲取用戶服務器上 JSP 文件的源代碼,或是通過精心構造的攻擊請求,向用戶服務器上傳惡意JSP文件,通過上傳的 JSP 文件 ,可在用戶服務器上執行任意代碼,從而導致數據泄露或獲取服務器權限,存在高安全風險。

二. 漏洞基本信息

  • 漏洞編號: CVE-2017-12616 CVE-2017-12615
  • 漏洞名稱: CVE-2017-12615-遠程代碼執行漏洞 CVE-2017-12616-信息泄露漏洞
  • 官方評級: 高危,實際測試漏洞危害較低
  • 漏洞描述: CVE-2017-12616:信息泄露漏洞 當Tomcat中啟用了 VirtualDirContext時,攻擊者將能通過發送精心構造的惡意請求,繞過設置的相關安全限製,或是獲取到由VirtualDirContext提供支持資源服務的JSP源代碼,從而造成代碼信息泄露。

CVE-2017-12615:遠程代碼執行漏洞
當 Tomcat運行在Windows操作係統時,且啟用了HTTP PUT請求方法(例如,將 readonly 初始化參數由默認值設置為 false),攻擊者將有可能可通過精心構造的攻擊請求數據包向服務器上傳包含任意代碼的 JSP 文件,JSP文件中的惡意代碼將能被服務器執行。導致服務器上的數據泄露或獲取服務器權限。
在一定的條件下,通過以上兩個漏洞可在用戶服務器上執行任意代碼,從而導致數據泄露或獲取服務器權限,存在高安全風險。

  • 漏洞利用條件: CVE-2017-12615漏洞利用需要在Windows環境,且需要將 readonly 初始化參數由默認值設置為 false,經過實際測試,Tomcat 7.x版本內web.xml配置文件內默認配置無readonly參數,需要手工添加,默認配置條件下不受此漏洞影響。 CVE-2017-12616漏洞需要在server.xml文件配置VirtualDirContext參數,經過實際測試,Tomcat 7.x版本內默認配置無VirtualDirContext參數,需要手工添加,默認配置條件下不受此漏洞影響。
  • 影響範圍: CVE-2017-12615影響範圍: Apache Tomcat 7.0.0 - 7.0.79 (windows環境) CVE-2017-12616影響範圍:Apache Tomcat 7.0.0 - 7.0.80

三. 漏洞詳細分析信息

3.1.環境搭建

Apache Tomcat默認開啟PUT方法,org.apache.catalina.servlets.DefaultServlet的readonly默認為true,而且默認沒有在conf/web.xml裏寫,需要手工添加並且改為false,才可以測試。

<init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
</init-param>```  

##3.2原理分析
本次Apache Tomcat兩個CVE漏洞涉及到 DefaultServlet和 JspServlet,DefaultServlet的作用是處理靜態文件 ,JspServlet 的作用是處理jsp 與jspx 文件的請求,同時DefaultServlet 可以處理 PUT 或 DELETE請求,以下是默認配置情況:
![1](https://yqfile.alicdn.com/469dbdc7ca182406069ceb36638d845db9e36b3c.png)
除了jsp和jspx默認是由org.apache.jasper.servlet.JspServlet處理,其他默認都是由org.apache.catalina.servlets.DefaultServlet來處理。
可以看出即使設置readonly為false,默認tomcat也不允許PUT上傳jsp和jspx文件的,因為後端都用org.apache.jasper.servlet.JspServlet來處理jsp或是jspx後綴的請求了,而JspServlet中沒有PUT上傳的邏輯,PUT的代碼實現隻存在於DefaultServlet中。
這個漏洞的根本是通過構造特殊後綴名,繞過了tomcat檢測,讓它用DefaultServlet的邏輯去處理請求,從而上傳jsp文件。
目前主要三種方法:
- evil.jsp%20
- evil.jsp::$DATA
- evil.jsp/

利用這兩種姿勢PUT請求tomcat的時候,騙過tomcat而進入DefaultServlet處理的邏輯,如圖:
![2](https://yqfile.alicdn.com/3933d25ffe38ef8b06854c889885e2dcc567c95f.png)
![3](https://yqfile.alicdn.com/82188c5249550d509182704521c57d09ccda1466.png)

 ![4](https://yqfile.alicdn.com/09b3d069423177cf21b771280ceefb713e3c09c7.png)


##3.3.  調試代碼
調試DefaultServlet.java代碼流程,如下:

 ![5](https://yqfile.alicdn.com/0edfdd0ffc5e54d18b546016c7192c44fc0a1f03.png)


設置readOnly為false
先調用棧
![6](https://yqfile.alicdn.com/393768b09a736315a99c17a6ee60bc035de53eda.png)



重點看doPut,這裏tomcat開始處理PUT請求,可以看到這裏如果readonly是true就直接進入error了,所以需要設置成false。

 ![7](https://yqfile.alicdn.com/df664a0c63bdb19651b7fb82248a4f98c05ed822.png)
![8](https://yqfile.alicdn.com/73a6ba0d5b94c696d2480ef56e3ec46ef9e2b485.png)


真正寫入文件在FileDirContext.java的rebind函數裏。






 ####  FileOutputStream特性

上麵遺留了一個問題就是當請求jsp%20或是jsp::$DATA後綴的時候,為什麼最終卻寫入.jsp後綴的文件,這些其實是java.io. FileOutputStream的問題了,具體需要分析jdk的C代碼才能得到解答,如圖

 ![9](https://yqfile.alicdn.com/82a1cb00b687bd20cec23e23947d4cbbcc382c2f.png)
![10](https://yqfile.alicdn.com/fbb73825fca6c19b56790847245bd4f3e45dfc45.png)
![11](https://yqfile.alicdn.com/ace41b17d0376a881c862eee87d66a6ed0b2b2ba.png)
![12](https://yqfile.alicdn.com/222f4ad9d9709c2c355838324912cd288ea932e0.png)

![13](https://yqfile.alicdn.com/ec5f203cbf72e2e1e10446fff4d9889128e6110b.png)



跟到open是native的,已經不是java層麵的問題了,這個open實際上是一個jni接口,然後調用windowsAPI CreateFileW創建文件,這裏下載openjdk6的jdk代碼分析,如圖:
  ![14](https://yqfile.alicdn.com/079a39aaa4f472ae48c84bb9f10bcd1782f7ad92.png)
這裏Java_java_io_FileOutputStream_open便是上邊java代碼裏open函數的C代碼實現,其中參數path對應open函數的name變量,繼續跟蹤,如圖: ![15](https://yqfile.alicdn.com/c9fd79d3695e76c698ca5161d65775c001977005.png)
繼續跟入winFileHandleOpen,這裏最終是調用windows的CreateFileW實現文件創建,如圖:
 ![16](https://yqfile.alicdn.com/090919bb89ecbee8537b020bb46c595a9fa73d8d.png)

而在windows下,創建文件是對後綴名稱有要求的,例如:如果後綴末尾是空格,會被去掉,a.txt::$DATA傳入CreateFileW也會被處理成a.txt


#### java.io.File的特性
前麵沒有說evil.jsp/,這種方法也可以PUT上傳,但是不同於上麵兩種,這種方法是利用了File類的特性,先看代碼,如圖:
![17](https://yqfile.alicdn.com/2cb0e3ffae0a3b4c80c0a202a4bc5949a5fa7311.png)
![18](https://yqfile.alicdn.com/8f54585a35e6897c62082a12ec4e94483898cf16.png)




這裏測試發現java.io.File會過濾掉子文件名末尾的斜杠,寫一個測試用例確實是這樣的,如圖:
 ![19](https://yqfile.alicdn.com/d1ed55636749dfa3748b7493e4c8304ed9905c11.png)

具體跟蹤一下代碼,如圖:
 ![20](https://yqfile.alicdn.com/b67e758696e0aea2c36fdf52396245c9983537dd.png)

繼續跟入,如圖:
 ![21](https://yqfile.alicdn.com/496044177e7aad6c660544f36f4c3246fce61312.png)

在這裏這個normalize(path, n, (prev == slash) ? i - 1 : i)會將文件名末尾的/過濾掉,所以可以導致後麵文件寫入jsp文件。

##3.4.  漏洞複現

Apache Tomcat 7默認值是 true,在默認條件下,無法成功利用這兩個漏洞。為了觸發漏洞,需要在conf/web.xml 中 defaultservlet 的配置中手工添加如下配置:
```javascript

<init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
</init-param>```  

我們通過構造的請求上傳b.jsp,執行該請求請求就會由DefaultServlet 處理,從而PUT操作就會順利執行,成功上傳文件,以下通過構造請求,觸發並複現該漏洞:
![22](https://yqfile.alicdn.com/485d160c70c31dfea07f36babca57c30c713648b.png)



在分析的時候,我們也發現File類存在一個利用點,normalize函數過濾掉了末尾斜杠。我們通過構造請求測試,發現可以被利用,通過對全版本測試,發現Windows、Linux、Unix下的Apache Tomcat 5.X、6.X、7.x、8.x、9.x版本均受到影響,從這點可以看出官方給出的補丁存在繞過,目前該問題已經得到Apache官方的確認。
 ![23](https://yqfile.alicdn.com/4fb3dfa13b520c3ff27b8607c3a03b173b3ac5f5.png)
![24](https://yqfile.alicdn.com/548732b2e1cc318e2ca76d65383c9966f68a328d.png)



#四.   漏洞分析總結
從以上分析可以得出,該漏洞利用的前提條件需要手動開啟readOnly功能,以支持上傳操作,在Apache tomcat 7.X版本默認配置的情況下是無法成功利用漏洞,從實際測試來看,漏洞危害性並沒有那麼高。
但是如果用戶一旦啟用了readOnly功能,黑客可利用漏洞成功入侵。
#五.   如何檢測漏洞?
從以上分析可以得出,該漏洞利用的前提條件需要手動開啟readOnly功能,開發或運維人員可以排查是否啟用了PUT方法並開啟了readOnly功能。
#六.   如何應對漏洞?
1.  根據業務評估配置conf/webxml文件的readOnly值為Ture或注釋參數,禁用PUT方法並重啟tomcat服務,臨時規避安全風險;
注意: 如果禁用PUT方法,對於依賴PUT方法的應用,可能導致業務失效。
2.  目前官方已經發布了7.0.81版本修複了兩個漏洞,建議用戶盡快升級到最新版本;
3.  對於最新版本繞過的問題,建議用戶持續關注官方信息,及時更新到最新版本;
4.  可以選用阿裏雲雲盾WAF產品進行防禦。
- 未使用WAF前:
 ![25](https://yqfile.alicdn.com/d2ca1490de5c24b072216772ac72461ef4093942.png)

<p >成功上傳文件</p>
- 使用WAF後的防禦效果:
 ![26](https://yqfile.alicdn.com/c25f29372e4f2c1011bfcad63fd0b760de7dd400.png)

<p >請求405報錯,上傳文件失敗</p>
#七.   Web安全最佳實踐
##為什麼PUT方法不安全?
除標準常用的GET和POST方法外,HTTP請求還使用其他各種方法,PUT方法是HTTP請求方法中的一種。此方法用於請求服務器把請求中的實體儲存在請求資源下,如果請求資源已經在服務器中存在,那麼將會用此請求中的數據替換原先的數據,作為指定資源的最新修改版。如果請求指定的資源不存在,將會創建這個資源,且數據位請求正文。
在以往的實際安全事件案例中,我們可以看到,由於PUT方法自身不帶驗證機製,有很多利用PUT方法很快捷簡單的成功入侵服務器,上傳Webshell或其他惡意文件,從而獲取敏感數據或服務器權限,從web安全年最佳實踐來看,我們不推薦使用這些不安全的http OPTIONS方法。
從安全最佳實踐來說,我們應該遵循“最小化”原則,不要隨意開啟不必要的服務或方法,僅開啟必要的功能,減小風險暴露麵,從而降低安全風險,保障業務的安全性。
##如何知道自己網站使用了哪些http方法?

![27](https://yqfile.alicdn.com/873e0117fdeaa7262d2dbb6c09785f9f693d2036.png)
 查看響應的 Allow: GET, HEAD, POST, OPTIONS,TRACE
注:該測試僅限於自身業務。
##禁用不必要的http方法
- IIS:
IIS默認拒絕PUT和DELETE請求,如果使用了不安全的方法,建議禁用webDAV模塊。
 ![28](https://yqfile.alicdn.com/222c6c31de7f1f1ba9c263fd4d3d0b1b57ba3c22.png)


- Apache:

```javascript

Location /> 
僅允許GET和POST方法,修改後重啟服務。
<LimitExcept GET POST > 
  Order Allow,Deny 
  Deny from all 
</LimitExcept> 
</Location>```  



- Tomcat:
修改web.xml配置,增加以下內容,並重啟tomcat服務:
&lt;security-constraint>  
   <web-resource-collection>  
      <url-pattern>/*</url-pattern>  
      <http-method>PUT</http-method>  
<http-method>DELETE</http-method>  
<http-method>HEAD</http-method>  
<http-method>OPTIONS</http-method>  
<http-method>TRACE</http-method>  
   </web-resource-collection>  
   <auth-constraint>  
   </auth-constraint>  
 </security-constraint>  
 <login-config>  
   <auth-method>BASIC</auth-method>  
 </login-config>

####安全在於細節,安全無小事。

最後感謝阿裏巴巴集團安全部柏通的技術支持。
##八.  附錄
[1].    https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
[2].    https://stackoverflow.com/questions/630453/put-vs-post-in-rest
[3].    https://tomcat.apache.org/security-7.html
[4].    https://tomcat.apache.org/security-7.html#Fixed_in_Apache_Tomcat_7.0.81

最後更新:2017-09-21 11:32:41

  上一篇:go  《PIC微控製器項目設計:C語言》一2.2 數組
  下一篇:go  專訪新浪微博黃波:千人千麵,機器學習賦能用戶信息流消費