Struts2漏洞分析與研究之Ognl機制探討

轉載請註明出處謝謝:http://blog.csdn.net/u011721501?viewmode=list

0、前言

最近專業實訓上需要添加一個struts2的批量利用程序,倒騰半天,我發現我對struts2系列的漏洞根本就不懂,用是會用,但是對我來說還是不夠,網上也沒有什麼好的分析文章來老老實實分析每一個細節。所以我這裏就結合每天的研究寫一些博客share出來。這是第一篇,也是昨天研究的一部分。

 

1、概述
 
在Struts2中,使用Ognl表達式作爲字符串與對象之間轉換的一種實現,通過Ognl表達式可以輕鬆做到String與Object之間的溝通。
在Struts2工程中,ognl對應的jar包是ognl-2.7.3,附上源碼來看一下Ognl類的實現。
在Ognl.java中,最基本的兩個方法就是getValue與setValue,傳入三個參數(表達式,上下文以及根對象)。其他的實現都是實現相同的功能。
Ognl的API很簡單,無論什麼複雜的功能,都會通過OGNL的三個要素完成。這三個要素分別是:
(1)表達式
表達式(Expression)規定Ognl做些什麼,其本質是一個帶有語法含義的字符串。支持的語法非常強大,從對象屬性、方法的訪問到簡單計算,甚至可以進行對象的創建與lambda。
 
(2)Root對象
這個又稱爲根對象,是用來存放執行Ognl的對象。比如要利用Ognl表達式對User對象的name屬性,這時候User對象就是本次操作的根對象(Root)。
 
(3)上下文環境
Context,這個對有Java開發經驗的人來說並不算新奇,但是對於一般人來說很難理解,Context翻譯爲上下文,也可以理解爲環境變量,是標明整個運行環境中的參數信息,默認值等。OGNL的上下文環境其實就是個Map結構,裏面保存了一些值。
 
 
2、基本操作
 
(1)訪問根對象
訪問根對象的屬性和方法可以不寫對象名前面的"#",使用點號進行訪問即可。
如訪問User根對象的name屬性:
OGNL: user.name
 
(2)對上下文的訪問
由於上下文是一個Map結構,訪問這些參數需要通過#符號加上鍊式表達式進行。
如訪問parameter中的name:
OGNL:#parameter.name
 
(3)靜態方法/屬性調用
通過@[class]@[field/method]訪問,這裏的類名要帶着包名。
如調用User中的靜態方法get
 
(4)方法的調用
使用點號加方法名稱進行調用,而且可以傳遞參數。
如訪問Root對象中的group屬性中的Users的size方法
group.users.size()
 
此外,Ognl還支持簡單計算,如9 mod 2 取模運算;支持對數組和容器的訪問,可以按照數組下標進行訪問,對於Map結構還可以直接使用鍵值來訪問。
還有投影選擇功能,用來篩選數據,這裏不再贅述。
 
 
3、深入研究
(1)Context構成
 
上面是OGNL上下文的結構,在OGNL中使用OgnlContext類進行實現。由上圖可以看到OGNL Context的具體構成。其中的ValueStack叫做值棧,是根對象的實現,在OGNL中則是使用OgnlValueStack實現ValueStack接口來實現這個機制。
那麼如何保存請求中的多個對象呢?Ognl中使用了CompoundRoot root;
來保存。CompoundRoot類繼承了ArrayList類,裏面有pop、push方法,很顯然是被做成了一個棧結構,正好解釋了爲啥叫ValueStack(值棧)。在上下文中,除了ValueStack,其他都是Map結構,訪問時直接#符號跟名稱即可。
以前沒有閱讀源碼,我一直認爲根對象是獨立與上下文環境而存在,知道看了上下文的實現(OgnlContext中的addDefaultContext方法),這個方法返回默認Map結構,作爲Context。方法中還調用了setRoot方法將根對象也給附上去了,也就是說這個根對象(ValueStack)也是上下文的一部分。
 
(2)Context其他重要參數
 
root(_root):作爲根對象的引用。
 
values(_values):如果自己傳入一個Map作爲上下文,那麼也要用OgnlContext進行包裝,這個values就被看做爲真正的容器。
 
ClassResolver(_classResolver):指定類加載機制的處理類,默認使用反射機制動態加載類。
 
TypeConvert(_typeConverter):處理類型轉化的類。處理字符串轉爲java類型。
 
MemeberAccess(_memberAccess):指定了訪問策略的處理方式。
 
 
(3)方法/屬性訪問策略MemberAccess
我們知道,在Struts2漏洞中的s2-005的攻擊代碼中有('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true這麼一句。
這裏就是爲了修改上下文中的_memberAccess爲true,爲啥設置爲true呢?  因爲默認爲false........
源碼如下圖:
 
 
MemberAccess在OGNL中的實現是DefaultMemberAccess,在Struts2中是SecurityMemberAccess。
這裏說一下SecurityMemberAccess:
 
 
Struts2爲了自身機制實現,又把這個memberAccess在OGNL上的實現封裝了一遍,可以其中的allStaticMethodAccess默認是false,也就是說默認不支持靜態方法的執行。
 
(4)方法/屬性訪問機制-------MethodAccessor和PropertyAccessor
這倆規定了OGNL訪問方法和屬性時的實現方式。在Struts2中,MethodAcccessor的實現類是XWorkMethodAccessor。
(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))
這句也是攻擊代碼的一部分,意思是將XWorkMethodAccessor的denyMethodExecution設置爲false。
讀源碼,只有當ReflectionContextState.DENY_INDEXED_ACCESS_EXECUTION爲false,方法纔可以執行。
具體控制在callStaticMethod中,這裏從上下文中獲取這個值xwork.MethodAccessor.denyMethodExecution ,轉化爲Boolean的類型,可以看到,如果沒有設置,默認爲False。如果e爲false,就return null,方法不會成功執行。
 
 
4、總結
OGNL機制是建立在三個基本元素根對象、上下文、表達式的基礎上,其他的實現都是提供一套解析引擎。由於OGNL及其靈活,所以造成了不少的漏洞,想必做安全的大家都會知道,接下來的幾篇我就會從源碼角度探索Struts2的各個漏洞。
 
參考資料
Struts2技術內幕
 
轉載請註明出處謝謝:http://blog.csdn.net/u011721501?viewmode=list
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章