作者:iswin@ThreatHunter

Spring 嚴重的漏洞歷來都不算多,之前比較嚴重的那個問題是 Spring 的 JavaBean 的自動綁定功能,導致可以控制 class ,從而導致可以利用某些特性執行任意代碼,但是那個漏洞比較雞肋,不是每次都能觸發。

由于 Spring 的框架越來越多,而且后面引入了 SpringEl 作為默認的表達式解析方式,所以一旦引入了類似于 OGNL 的表達式,很可能會帶來一些安全問題,本次漏洞就是由于 Spring Web Flow 的數據綁定問題帶來的表達式注入,從而導致任意代碼執行。

一. 漏洞簡介

這個漏洞在今年6月初剛被提交(傳送門), 官方并沒有詳細的信息,通過官方描述和補丁的對比,我們可以大致推斷應該是 Spring Web Flow 在 Model 的數據綁定上面,由于沒有明確指定相關 model 的具體屬性導致從表單可以提交惡意的表達式從而被執行,導致任意代碼執行的漏洞,這個漏洞利用除了版本的限制之外還有兩個前置條件,這兩個前置條件中有一個是默認配置,另外一個就是編碼規范了,漏洞能不能利用成功主要就取決于后面的條件。

整體來說這個漏洞危害應該還是有一些的,如果滿足2個前置條件,那么直接 RCE 是沒什么問題的。在分析這個漏洞之前需要一些 Spring Web flow 的基礎知識,給大家推薦這篇文章

二. 漏洞分析

一開始我也不清楚這個漏洞到底是怎么觸發,對于這個漏洞的理解,最好去看下 Spring Web Flow 的教程,搞明白里面的 view-state 是啥,這里不過多對 Spring Web Flow 的基礎知識過多解釋,那么我們直接看補丁,如下圖:

我們發現這里對 addEmptyValueMapping(DefaultMapper mapper, String field, Object model) 這個方法里面表達式解析的實現類進行了替換,直接使用了 BeanWrapperExpressionParser 來解析,關于這個類我們后面再詳細說,那么知道觸發漏洞的函數后,我們就可以用 Eclipse 或者 Spring Tools 來跟蹤下函數調用棧,具體如下:

通過調用關系我們可以發現一共有一下兩個函數調用了 addEmptyValueMapping 方法

  • addDefaultMappings(DefaultMapper mapper, Set parameterNames, Object model)
  • addModelBindings(DefaultMapper mapper, Set parameterNames, Object model)

這里通過調用關系我們可以大概的搞明白 Spring Web Flow 的執行順序和流程,由 flowcontroller 決定將請求交給那個 handler 去執行具體的流程,這里我們需要知道當用戶請求有視圖狀態處理時,會決定當前事件下一個執行的流程,同時對于配置文件中我們配置的 view-state 元素,如果我們指定了數據的 model ,那么它會自動進行數據綁定,xml 結構如下(這里以官方的example中的 book 項目為例子)

言歸正傳,本次漏洞出現的原因就是在 view-state 節點中數據綁定上,我們繼續跟蹤 addEmptyValueMapping 方法的調用過程,這里通過 eclipse 我們可以發現 bind 方法間接的調用了 addEmptyValueMapping 函數,

到這里我們知道了addEmptyValueMapping 函數存在表達式執行的點,我們現在來詳細看下這個 addEmptyValueMapping 函數,如下圖

這里我們可以看見,只有控制了 field 參數才能出發漏洞,所以我們重點是找到有沒有點我們可以控制從而控制 field 參數來進行任意代碼執行,這里明確目標后,我們回過頭來看 addDefaultMappings 和 addModelBindings 這兩個函數,既然這兩個函數都調用了存在缺陷的函數,那么我們看看這兩個函數的區別是什么,而且那個函數能能能控制 field 參數,兩個函數的區別如下:

這里比較明顯的區別就是 addModelBindings 函數中 for (Binding binding : binderConfiguration.getBindings()) 存在這樣一個循環,而且就是這個循環的控制決定了 field 參數的值,經過進一步分析,這里控制 field 的參數的決定性因素就是 binderConfiguration 這個變量所控制的值,這里經過源碼的跟蹤我們可以發現,binderConfiguration 函數的值就是 webflow-*.xml 中 view-state 中 binder 節點的配置,所以這個函數的值來源于配置文件,所以這個函數我們無法控制,從而無法觸發漏洞,所以我們重點來看看 addDefaultMappings 這個函數,我們發現 addDefaultMappings 中我們可以控制 field 參數,所以我們重點來看看如何去觸發這個函數。

現在我們基本上可以確定了 addDefaultMappings 函數是我們觸發漏洞的關鍵點,那么如上圖所示,bing 函數中調用了這兩個函數,那么我們可以看出只有當 binderConfiguration 為空的時候才能觸發我們的漏洞,那么我們剛才也說了 binderConfiguration 這個值是由配置文件中是否有 binder 節點來控制的(這里需要注意的是程序執行到 bind 方法的前置條件是 view-state 節點中是否配置了 model 屬性,即綁定的 javabean 對象是什么),而且 addDefaultMappings 函數中 parameterNames 參數就是我們從表單中傳遞的值,所以到這里漏洞的觸發流程和觸發條件基本上清楚了,觸發條件如下:

  • 在 webflow 配置文件中 view-state 節點中指定了 model 屬性,并且沒有指定綁定的參數,即 view-state 中沒有配置 binder 節點
  • 而且 MvcViewFactoryCreator 類中 useSpringBeanBinding 默認值(false)未修改

這里為什么一定要 useSpringBeanBinding 的值為 false ,我們來看一下 addEmptyValueMapping 函數,這里的 expressionParser 變量的聲明類是 ExpressionParser 接口,那么決定最后 expressionParser.parseExpression(field, parserContext) 這個函數來執行任意表達式是這個變量的賦值,那么在 spring web flow 中這個 expressionParser 的默認值就是 WebFlowELExpressionParser 的實例,這個類表達式默認的解析是有 spel 來執行的,具體可以去跟蹤函數,那么在org.springframework.webflow.mvc.builder.MvcViewFactoryCreator.createViewFactory(Expression, ExpressionParser, ConversionService, BinderConfiguration, Validator, ValidationHintResolver)這個類如下圖:

我們可以看見如果 useSpringBeanBinding 這個屬性為 false 那么久使用默認的解析類,如果這個值為 true 就由 BeanWrapperExpressionParser 這個類來解析,這個類的 parseExpression 函數我們來看看

首先決定了能不能執行的第一個控制變量是 allowDelimitedEvalExpressions ,這個默認值是 false ,所以這里是執行不了表達式的。

所以這里必須滿足 useSpringBeanBinding 這個默認值不被改變。

這里需要注意一點,我們構造的惡意參數名稱必須以_開頭,具體原因看 addDefaultMappings 函數中的 fieldMarkerPrefix 變量。

OK,到這里漏洞的觸發條件和流程已經很明確了,下面說說具體怎么利用。

三. 漏洞利用

這次漏洞測試是以 Spring Web flow 官方的 Example 中的例子來進行,因為這里的某個 flow 滿足我們的條件,具體配置如下:

項目地址,這里在測試時需要注意修改 org.springframework.webflow.samples.booking.config.WebFlowConfig.mvcViewFactoryCreator() 方法中的改成 factoryCreator.setUseSpringBeanBinding(false); 因為這個工程修改了 useSpringBeanBinding 的默認值。

這里直接到訂閱圖書,上圖說了在 reviewBooking flow 中就能出發,如下圖:

點擊 confirm ,然后抓包添加惡意參數變量,如下圖:

OK,大功告成。

參考資料

[1] : https://pivotal.io/security/cve-2017-4971

[2] : https://www.ibm.com/developerworks/cn/education/java/j-spring-webflow/index.html


幫發小廣告:

為了更好的和廣大安全愛好者交流,我們搭建了個交流社區,社區主要聚焦在威脅發現以及安全數據分析等領域,我們希望有更多的朋友能加入,能一起分析知識、共同進步。社區地址:https://threathunter.org/, 感謝大家支持。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/322/