目錄

0x00前言0x01觸發原因0x02調試分析0x03補丁分析0x04參考文章

影響版本:

1.1.0-1.1.12

1.2.0-1.2.7

1.3.0

修復方案:升至1.3.1或以上版本

我的測試環境:SpringBoot 1.2.0

0x00前言

這是2016年爆出的一個洞,利用條件是使用了springboot的默認錯誤頁(Whitelabel Error Page),存在漏洞的頁面在:/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration.java

0x01觸發原因

本次漏洞的觸發點在SpringBoot的自定義錯誤頁面,功能是頁面返回錯誤,並提供詳細信息,信息中包括錯誤status("status"->500)、時間戳("timestamp"->"Fri Dec.....")、錯誤信息("error"->"Internal Server Error")、和用戶輸入的參數("message"->"abcd"),這些參數在模板文件中以類似於以下形式存在:”Error 1234 ${status}---${timestamp}---${error}---${message}“。

後端進行渲染視圖時,首先,解析錯誤頁面模板中的參數名(status、timestamp、error、message),即判斷模板中每個${的位置,然後再判斷最近的}的位置,從而將參數名一個個讀取出來,然而這裏使用了遞歸,也就是說如果參數名中還包含${和}的話,這個解析引擎會再次遞歸一次,再次解析這個值,如,模板中有個值爲${${abc}},由於使用了遞歸,解析引擎會對其解析兩次,第一層去掉最外層的{}解析成${abc},然後將其作爲參數進行第二次解析。在第二次解析中將裏層的{}去掉,變成abc。

每次將一個參數名解析出來之後,就將參數名傳入SpEL引擎,解析成context中對應參數名的值(如"status"->500),完成之後返回參數值給第一步中的解析引擎(返回500)。

解析引擎收到SpEL傳回的參數值之後,再次進行遞歸,以防參數值中也存在${和},存在則去之,然後在遞歸過程中再次傳入SpEL引擎進行解析。這裏就是觸發點了。假設用戶的輸入中包含${payload},則SpEL第一次message解析成${payload}之後,解析引擎進行遞歸,去掉${和}後將payload傳入SpEL引擎,SpEL引擎將將直接對payload進行解析,從而觸發了漏洞,觸發點如下圖所示。

SpringBoot SpEL表達式注入漏洞-分析與復現

0x02調試分析

先搭好存在漏洞的SpringBoot版本的環境,使用其自帶的sample搭建一個服務器,然後自己寫一個控制器,拋出異常即可。

SpringBoot SpEL表達式注入漏洞-分析與復現

開啓調試,使用瀏覽器訪問

http://127.0.0.1:8080/?payload=${new%20java.lang.ProcessBuilder(new%20java.lang.String(new%20byte[]{99,97,108,99})).start()}

首先,將context賦值到this.context中,然後以this.template和this.resolver爲參數調用replacePlaceholders方法。

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

this.template="<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>${timestamp}</div><div>There was an unexpected error (type=${error}, status=${status}).</div><div>${message}</div></body></html>"

跟進replacePlaceholders方法,進入了PropertyPlaceholderHelper文件

SpringBoot SpEL表達式注入漏洞-分析與復現

繼續跟進parseStringValue方法(這就是分析中說的存在遞歸的方法),strVal的值爲之前的this.template,將之賦值給result,然後通過判斷result中${和}的位置,開始解析result中的第一個參數名,並賦值給placeholder,本次的值爲"timestamp",然後將placeholder作爲第一個參數,再次調用本方法(遞歸,以防字符串placeholder中包含${})。

SpringBoot SpEL表達式注入漏洞-分析與復現

跟進遞歸,由於placeholder的值爲"timestamp",其中不包含${,導致startIndex爲-1,故不進入while語句,直接到了return,因此可以發現,在遞歸時,如果第一個參數中不包含${,則直接將第一個參數返回。

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

再次回到之前的點,下一步是調用resolvePlaceholder方法,此函數的作用是查找this.context中對應參數的值並返回,跟進看一下

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

首先看一下this.context,發現"timestamp" -> "Sat Dec 15 10:49:02 CST 2018"

SpringBoot SpEL表達式注入漏洞-分析與復現

繼續跟進,發現value被賦值成SpEL解析後的值,然後return

SpringBoot SpEL表達式注入漏洞-分析與復現

回到parseStringValue方法,將經過SpEL解析後return的值賦值給propVal,由於propVal != null,故跳過第一個if語句,進入第二個語句,將propVal作爲第一個參數再次遞歸。通過上一次遞歸我們發現,如果第一個參數中沒有${,則直接返回第一個參數的值,因此這次就不再跟進了。

SpringBoot SpEL表達式注入漏洞-分析與復現

遞歸回來後propVal的值沒變,使用replace將propVal替換到result中的對應的參數位。接着尋找template中的下一個參數位,賦值給startIndex,用於下一次while條件判斷。

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

進入第二次循環,這次的參數是error,和之前的timestamp過程一樣,就不具體分析了

SpringBoot SpEL表達式注入漏洞-分析與復現

第三次while循環,參數是status,同上,不具體分析

SpringBoot SpEL表達式注入漏洞-分析與復現

進入第四次循環,重頭戲來啦,這次的參數是message,其值是用戶輸入的值。

SpringBoot SpEL表達式注入漏洞-分析與復現

跟進到第一次遞歸,防止參數名中含有${},由於參數名士message,故略過這一步。然後到了resolvePlaceholder方法,用於使用SpEL表達式引擎解析message的值,再跟進一下。

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

發現value的值爲用戶傳入的payload

SpringBoot SpEL表達式注入漏洞-分析與復現

其中包含${},是一個SpEL表達式。繼續跟進,返回到parseStringValue方法。

SpringBoot SpEL表達式注入漏洞-分析與復現

可以發現,爲了防止propVal中包含${},再次進行一次遞歸。下面就是漏洞關鍵點了,跟進這次遞歸。

SpringBoot SpEL表達式注入漏洞-分析與復現

此時placeholder的值爲去掉${}的payload,即:"new java.lang.ProcessBuilder(new java.lang.String(new byte[]{99,97,108,99})).start()"。將placeholder作爲第一個參數傳入SpEL解析函數(147行)

SpringBoot SpEL表達式注入漏洞-分析與復現

可以發現,這裏直接使用parseExpression(name),而name的值就是我們的payload。接着使用getValue解析payload:

Expression expression = this.parser.parseExpression("new java.lang.ProcessBuilder(new java.lang.String(new byte[]{99,97,108,99})).start()");Object value = expression.getValue(this.context);

然後觸發payload,漏洞利用完成。

SpringBoot SpEL表達式注入漏洞-分析與復現

0x03補丁分析

補丁創建了一個新的NonRecursivePropertyPlaceholderHelper類,用於防止parseStringValue進行遞歸解析。

SpringBoot SpEL表達式注入漏洞-分析與復現

SpringBoot SpEL表達式注入漏洞-分析與復現

0x04參考文章

Spring Boot框架Whitelabel Error Page SpEL注入漏洞分析

原文:https://www.cnblogs.com/litlife/p/10183137.html

查看原文 >>
相關文章