STRUTS2的getClassLoader漏洞利用
0x00 摘要
2012年,我在《攻擊JAVA WEB》,文中提多關於“classLoader導致特定環境下的DOS漏洞”,當時並沒有更加深入的說明,這幾天struts官方修補了這個漏洞,本文是對這個漏洞的深入研究。
0x01 正文
這一切,得從我們控制了classLoader說起,曾經寫過一篇文章,提到了一個小小的技術細節,非常不起眼的一個雞肋。 引用《Spring framework(cve-2010-1622)漏洞利用指南》:
Struts2其實也本該是個導致遠端程式碼執行漏洞才對,只是因為它的欄位對映問題,只對映基礎型別,預設不負責對映其他型別,所以當攻擊者直接提交URLs[0]=xxx時,直接爆欄位型別轉換錯誤,結果才僥倖逃過一劫罷了。
tomcat8.0出來後,這個問題爆發了,這是一個雞肋漏洞的逆襲。
在struts2任何一個action執行之前,一旦接受到使用者提交引數xx=zzzzz時,就由Ognl負責呼叫對應的當前action的setXxx方法,至於set方法到底是幹什麼的,其實不重要,裡面的邏輯也不重要,我們只關注這個方法呼叫了,引數傳遞了。這種對屬性的改變,有時候是可以很大程度的影響後續複雜邏輯。
普及一點基礎
Object是java的基礎類,所有的class生成的物件,都會繼承Object的所有屬性和方法,因此當前action無論是什麼程式碼,必須有Object自帶的getClass方法,這個方法會返回一個Class物件,Class物件又一定會有getClassLoader方法,最終在每個action都可以
#!java
getClass().getClassLoader()
拿到當前的ClassLoader。
我研究這個問題,在幾年前了,這個東西理解起來不容易,尤其是各個web容器不一致,剛巧當時有個阿里巴巴內部《tomcat等容器的classLoader載入原理》培訓,收穫匪淺。本文篇幅有限,簡單的講一下。
在JRE啟動中,每個Class都會有自己的ClassLoader。web容器,為了方便的管理啟動過程,通常都有實現自定義的ClassLoader。《Spring framework》的漏洞的利用場景真的非常幸運,利用了web容器的特性getURLs方法,所有容器的servlet的ClassLoader都會透過繼承父類UrlClassLoader得到getURLs這個方法,所以這個漏洞可以不受容器影響。事實上,每個容器的ClassLoader都是自己實現的,環境必然會有所不同,那次struts2僥倖逃過一劫,所以我的一個關注點,一都放在幾大web容器的ClassLoader程式碼變化上,哪天看到tomcat8居然把resources放進ClassLoader上,而ServletContext剛巧掛在resources上,頓時知道肉戲來了。
上傳webshell的可能性研究
多次的遠端程式碼執行漏洞洗禮,我一直在腦海裡模擬“ServletContext被控制了,這次能幹什麼”,究竟有哪些路線,可以通往程式碼執行的領域。
比如:Struts2會去servletContext裡取到一個值,然後把它作為Ognl執行掉。這個太簡單了,我自己都不信。
Ognl的Context樹形結構:
servletContext被轉換成Map,變成了圖中的application子項,這個位址很尷尬,如果是上一層Node,從上到下找到value Stack,確實有實現這個思路的可能,但現在看來,這條路斷了,它不支援找到父節點。經過多次找尋後,確認Ognl出局,只能從web容器本身入手。
執行在Tomcat8下的struts,在隨便哪個action程式碼中,插入這段,下斷點,
#!java
this.getClass().getClassLoader();
任何一個Action的classLoader都是org.apache.catalina.loader.WebappClassLoader,這是漏洞的源頭。
我的思路,是給context賦予初始化引數readOnly=false。因為在tomcat上,所有的請求,都會預設由defaultServlet上處理,或者由jspServet處理。只要在context初始化時,readOnly=false,接下來defaultServlet就會真的處理PUT請求DELETE請求等等大威力請求,於是我們可以直接PUT檔案上來。
這個思路的前提,是defaultservlet再被初始化一次。現實很殘酷,這個思路最終沒有得到執行,原因是servlet只會初始化一次,而readOnly屬性只有在servlet初始化時,才會真的給servet的readOnly屬性賦值。這次突破,宣告失敗。
幾個這個漏洞的除錯小技巧:
1. 僅僅從debug上檢視ognl的賦值情況,是不準確的,debug只能看到這個類定義好的變數。
如果有一個程式碼是這樣的:
#!java
public void setName(String name){…}
但是並沒有定義過這個屬性,這時debug無法看到這個東西,但是其實ognl可以直接透過name=zzzzz呼叫,並且能把zzzz傳遞過去。
2. 或者只有一個私有屬性,但是沒有set方法,其實也是ognl不能賦值的。
這個debug,觀察這個漏洞時,僅僅是個參考,要真正深入進去看程式碼才能和ognl的視線保持一致。
3. 一個final的物件,或者只是get方法返回一個物件,看起來像是隻讀的,其實物件的屬性還是可以改的,這個只是物件的引用。
你可以理解為指標指向的地址不能變,但是指向的那個物件的屬性,是可以修改的。
舉例:
#!java
public User getUser()
{
return this.user;
}
public final User user;
這兩處程式碼,其實真正返回給OGNL的都是user物件,物件的屬性只要還有set方法,也都是可以被修改的。依然可以透過
url?user.name=xxx
對user的name賦值。
struts2執行在tomcat8.0.1rc5(2013,11月前)的任意檔案讀取漏洞
在tomcat的環境下,classLoader會掛載一個resources,類名叫做“StandardRoot”,這個恐怖的東西,和tomcat的資原始檔管理有關,debug看到的第一個屬性就是非常危險的屬性“allowLinking”。
這個事情,要從很久很久以前,struts修補的一個任意檔案讀取漏洞說起。
http://struts.apache.org/release/2.3.x/docs/s2-004.html
這是一個目錄列表+檔案讀取漏洞,修補方案非常陰險,沒有采用正規的手段,在框架層解決漏洞,而是利用了web容器的一個公約特性,jsp的web容器都遵守一個規則。
當一個路徑叫做“/var/www/tomcat/webapps/demo/struts/../
”時,呼叫
#!java
getClassLoader().getResource(Path)
返回路徑為:
/var/www/tomcat/webapps/demo/
會把/../去掉,並且直接到達目的目錄。
這個叫做web容器特性,由web容器說了算,哪天web容器生氣了,想變了,struts沒有話語權。事實上,我一直喜歡講框架安全,其中一條準則,就是“框架不要依靠web容器的特性做防禦”,當然,今天不討論這個話題,只是稍微做個鋪墊。
當時修補程式碼為:
使用者提交struts/../
時,pathEnding="struts/../"
。
但是
resourceUrl="/var/www/tomcat/webapps/demo/"
所以並不以pathEnding結尾。這種猥瑣的做法,當時確實有效。
tomcat8這個版本突然抽風了,重寫了這個方法,還真的返回了
/var/www/tomcat/webapps/demo/struts/../
宣告淪陷。但是程式碼實際執行中,有個要求,就是“StandardRoot.allowLinking”必須是true(預設肯定是false)。
機會來了。首先提交:
http://localhost:8080/demo/t1.action?class.classLoader.resources.allowLinking=true
debug可以看到已經是true。
然後按照以前的攻擊方法:
就可以輕易讀取任意檔案,拿到資料庫密碼等等。
這是兩個漏洞結合的成果,非常遺憾的是,在RC5這個版本之後,有人給tomcat提交了一個需求,大概在2013年11月左右,tomcat的一個不重要的需求中(剛好這個需求涉及到資原始檔相關程式碼),tomcat維護人員也許並沒有意識到了這裡存在讀取資原始檔的威脅,僅僅是把讀取資源功能重新抽象規劃了一次,結果順帶修補了這個漏洞,這問題產生的理由非常冤屈,修補的理由非常冤屈,最鬱悶的是我,活生生的,0day沒了。原本沾沾自喜以為可以大殺四方,結果大神打了個噴嚏。
最後順帶說一句,這個漏洞只在windows下正常,linux下未知原因抽風。
tomcat8下黑掉struts2應用的首頁
但是不要緊,tomcat是不可能給struts解決根本問題的,standardroot暴露出來,可以順帶影響很多東西。這個算DDOS麼?其實我可以把“Hacked by kxlzx”寫到你的應用首頁去
成因非常的“正常”,因為這個context屬性代表了tomcat的/conf/context.xml
檔案的配置,我現在把path給你改了,那麼struts去處理result時,會用路徑拼接讀取檔案,現在目錄名被改掉了,自然就讀不到檔案了,可惜這裡不能00截斷,否則又是一個任意檔案讀取漏洞。 下面是被幹掉的網站,訪問任何一個action,都會有如下效果:
看看debug的情況:
當前action叫做T1,會找到T1.jsp,但是現在目錄名已經被修改了,所以報錯。
這個問題可以影響tomcat8所有版本下執行的struts2,對了,你們得自己設計EXP哈,不要亂入。
jetty7關機指令
既然提到了web容器,只有研究tomcat,肯定不能覆蓋大家關心的地方,於是我選擇了另一個開源免費並且使用量大的輕量級web容器:jetty。
現在先看看jetty是否有突破的口子。這次講解路線反過來,先找個影響“不大”,各位“不是”很關心的漏洞。
還是先看看web結構,使用老辦法斷點:
#!java
this.getClass().getClassLoader();
看到一個class:
#!java
org.eclipse.jetty.webapp.WebAppClassLoader
jetty的漏洞,沒有tomcat那麼含蓄,非常直接的,context就掛載在classLoader上。
jetty在執行過程中,會去實時檢視ContextHandler中的shutdown屬性(webappcontext透過幾層繼承關係,繼承了這個類,其實親戚關係有八丈遠),一旦發現true,直接就不工作了,這是典型的,使用一個狀態判斷業務是否同行。基於這個原理,只要如下訪問,以後這個應用,就只剩下404了。
無論是什麼action,都只會返回這個錯誤,後續的執行,jetty都以為真的shutdown了。並且這個過程沒有任何補救措施,只能管理員手工重啟了,各位SA親們,你們準備好了麼?
jetty任意檔案下載
我們讓404為這個漏洞服務到底。
事實上,下面說的這個問題發生在jetty上,tomcat真的是巧合的逃過一劫。
我們看看jetty對於自定義錯誤檔案的配置過程:
這段配置檔案,可以自定義404錯誤檔案,這裡可以指定/WEB-INF/
目錄下的檔案,一旦配置之後,由ErrorPageErrorHandler負責給errorPages(這也是個map)新增一個對應關係。這個類最終會被掛在到context中,那麼依照這個漏洞的原理,我們可以層層呼叫,最終制定一種錯誤,比如404錯誤。
Jetty把errorHandler掛載到context上,errorHander有個errorPages屬性,這其實是個map,代表錯誤頁面,key是一個返回碼數字,value就是錯誤後顯示的檔案。 所以開啟:
訪問圖片中這條URL後,效果如下,任何一個不存在的頁面都會顯示web.xml的內容:
有了這個問題,就可以讀取資料庫檔案,檢視資料庫密碼,讀取程式碼檔案,查詢隱藏的業務邏輯漏洞。注意,是任何人遇到404都可以看到這個頁面,最好等夜深人靜的時候再使用,用完了還得恢復原樣。
0x02 漏洞修補
這漏洞已經被官方修補了,2012年發出來的老問題,只是沒有單獨提交官方而已,居然也能拖到現在,建議各位下定決心換個框架。
from:http://security.alibaba.com/blog/blog_3.htm
相關文章
- struts2最近幾個漏洞分析&穩定利用payload2020-08-19
- struts2架構網站漏洞修復詳情與利用漏洞修復方案2018-12-03架構網站
- ruoyi漏洞利用2024-07-02
- wild copy型漏洞的利用2020-08-19
- BlueKeep 漏洞利用分析2019-09-20
- Struts2 S2-061漏洞復現(CVE-2020-17530)2020-12-12
- 基於 GDI 物件的 Windows 核心漏洞利用2018-05-09物件Windows
- 漏洞利用與卡巴斯基的對抗之路2020-08-19
- CRLF Injection漏洞的利用與例項分析2020-08-19
- 發掘和利用ntpd漏洞2020-08-19
- CVE-2015-5090漏洞利用2020-08-19
- ROP漏洞詳解和利用2022-05-10
- MS17-010漏洞利用2021-11-22
- struts2的使用2018-06-10
- Codeigniter 利用加密Key(金鑰)的物件注入漏洞2020-08-19加密物件
- CVE-2015-1538漏洞利用中的Shellcode分析2020-08-19
- 漏洞利用之資訊洩露2024-04-29
- cve-2014-0569 漏洞利用分析2020-08-19
- Metasploit之漏洞利用( Metasploitable2)2020-09-27
- 微軟:ProxyShell 漏洞“可能被利用”2021-09-03微軟
- WordPress網站漏洞利用及漏洞修復解決方案2019-02-24網站
- 【漏洞利用】2024Hvv漏洞POC283 個合集分享2024-09-02
- RCE(遠端程式碼執行漏洞)原理及漏洞利用2022-03-17
- 【struts2】2020-12-17
- PKAV 發現 Struts2 最新遠端命令執行漏洞(S2-037)2020-08-19
- Zerodium:Android 漏洞的利用價值首次超越了 iOS2019-09-05AndroidiOS
- PHP DOS漏洞的新利用:CVE-2015-4024 Reviewed2020-08-19PHPView
- 利用勒索軟體Locky的漏洞來免疫系統2020-08-19
- struts2總結(三)--官網下載struts2的jar包2018-08-02JAR
- CISA 在其已知利用漏洞目錄中新增15個新漏洞2022-02-15
- Linux堆溢位漏洞利用之unlink2020-08-19Linux
- Google Chrome 開發者工具漏洞利用2020-08-19GoChrome
- muymacho---dyld_root_path漏洞利用解析2020-08-19Mac
- Python2 input函式漏洞利用2024-06-05Python函式
- 棧溢位漏洞利用(繞過ASLR)2021-09-18
- 0x727/SpringBootExploit: 快速利用SpringBoot的JNDI漏洞的工具2021-12-03Spring Boot
- 緩衝區溢位漏洞的原理及其利用實戰2022-03-01
- 2020及2021年常被利用的30個軟體漏洞2022-01-17