以struts2 s2-21為例,分析跟蹤請求從tomcat容器到struts2框架的代碼處理流程。
tomcat部分:
tomcat 調(diào)用JIoEndpoint.java 的run()創(chuàng)建socket
然后調(diào)用processor.process(socket)負(fù)責(zé)解析http 協(xié)議并返回結(jié)果內(nèi)容。
其中processor 是HttpProcessor 的一個實例,事實上tomcat 對HTTP 請求的解析都是通過
HttpProcessor 這個類中的process()這個方法實現(xiàn)的。跟入process()這個函數(shù),主要功能有以下幾個:
parseRequestLine()和parseHeaders()分別解析消息頭第一行、請求頭其他字段等。
prepareRequest()
通過prepareRequest 方法組裝request filter,用于處理http 消息體
adapter.service(request, response)
將request 交給tomcat 處理,返回response
inputBuffer.endRequest()
將response 返回給客戶端
其中,adapter.service(request, response)將請求交給容器處理。tomcat從connector 到servlet 處理HTTP 請求。http 請求會依次進(jìn)入engine、host、wrapper,一直到servlet,這里開始關(guān)聯(lián)struts2。

其中filter是struts2的FilterDispatcher實例。執(zhí)行這個doFilter 方法才開始進(jìn)入struts2 的代碼邏輯,在
這之后程序的控制權(quán)由容器轉(zhuǎn)交給struts2。
struts2處理http請求
其實Struts2 的核心就是一個Filter,它的作用只是處理HTTP 請求(request)然后返回給客戶端(response),其doFilter方法是struts2 處理HTTP 請求的入口。后面struts2 將HTTP 請求經(jīng)過一系列處理之后,交給了參數(shù)攔截器(ParametersInterceptor),用來設(shè)置參數(shù)屬性。當(dāng)提交a=b參數(shù)時,struts2會自動執(zhí)行對應(yīng)的set a方法去設(shè)置屬性值,具體實現(xiàn)依靠OGNL完成。
參數(shù)攔截器(ParametersInterceptor)中的doIntercept 方法:

首先參數(shù)攔截器會獲取action 實例
Object action = invocation.getAction();
然后生成OGNL 上下文
ActionContext ac = invocation.getInvocationContext();
這里的ac 便是OGNL 上下文了。包括_root、_memberAccess等屬性。
通過retriveParamerers,即參數(shù)攔截器,獲取http請求參數(shù)。


調(diào)用ActionContext.getParameters() 實現(xiàn),獲得Map 型的參數(shù)集parameters。遍歷HttpServletRequest、HttpSession、ServletContext 中的數(shù)據(jù),并將其復(fù)制到Webwork 的Map 中實現(xiàn),至此之后,所有數(shù)據(jù)操作均在此Map 結(jié)構(gòu)中進(jìn)行,從而將內(nèi)部結(jié)構(gòu)與Servlet API 相分離。
這里newStack 是從OGNL 上下文中取出的ValueStack,保存的是action 的實例。
這里 newStack.setParameter(name, value); 便是將HTTP 請求的參數(shù)設(shè)置到action 實例當(dāng)中。此過程中會調(diào)用set 方法設(shè)置屬性。這里newStack.setParameter(name, value); 的執(zhí)行邏輯都是通過OGNL 實現(xiàn)的,實際上就是遍歷上下文去找對應(yīng)的set 方法。這也是為何利用ognl實現(xiàn)漏洞的原因。
在ParametersInterceptor.java的參數(shù)攔截器函數(shù)doIntercept()中,其中newStack.setParameter(name, value);函數(shù)中,判斷參數(shù)是否符合要求。


這個 this. excludeParams 便是 struts2-core.jar 中 struts-default.xml 中配置的正則了。因此在s2-021漏洞中可以繞過官方修復(fù)。
s2-021 poc:Class['ClassLoader'].resources.dirContext.docBase=xxxx
因為每個action 必然繼承容器的 classLoader ,所以每個action 中肯定有對應(yīng) classLoader 中的屬性。這里請求參數(shù)是 Class['ClassLoader'].resources.dirContext.docBase ,跟蹤代碼最終找到
調(diào)用的是tomcat 源碼中BaseDirContext 類中的 setDocBase() 方法.