Security Advisory
RaspberryMatic Unauthenticated Remote Code Execution
Durch die Kombination mehrerer Schwachstellen können unauthentifizierte Angreifer eigenen Code auf einer RaspberryMatic Instanz ausführen.
CVE: CVE-2024-24578
CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Kritikalität: critical
Betroffene Versionen: ≤ 3.73.9.20240130
Behoben in: ≥ 3.75.6.20240316
Gefunden von: Hans-Martin Münch
Produktbeschreibung
RaspberryMatic ist ein alternatives Betriebssystem für eine freie, OpenSource-basierte “homematicIP CCU-Zentrale” aus deiner Hand bei Nutzung einer CCU3, ELV-Charly, RaspberryPi, Tinkerboard, ODROID, Intel NUC oder als virtuelle Maschine via Proxmox VE, Home Assistant Add-on, Docker/OCI, LXC, Qemu/KVM, Kubernetes/K8s, Synology VMM, QNAP VS, UNRAID, XCP-ng/XenServer, VirtualBox, vmWare or HyperV.
Details
RasberryMatic nutzt den in Java entwickelten HMIPServer des HomeMatic-Open-Central-Control-Unit-SDK (HM-OCCU-SDK). Die Funktionen dieses Dienstes können über URLs, die mit /pages/jpages
starten aufgerufen werden. Der Code zum Hochladen neuer Firmware-Releases führt keine Prüfung der SessionID durch, daher kann der Controller ohne eine gültige Session aufgerufen werden.
Das folgende Code Beispiel zeigt den Code von de.eq3.ccu.server.internal.FirmwareUploadRouteHandler
. Der Wert des URL-Parameters “sid” wird in Zeile 6 gelesen, jedoch nicht weiter geprüft.
1public void handle(RoutingContext event) {
2 String msgCommandFinishedWithErrors = "Handling of command finished with error.";
3 HttpServerRequest request = event.request();
4 if (logger.isDebugEnabled())
5 logger.debug("Request: " + request.uri());
6 String sid = request.params().get("sid");
7 request.setExpectMultipart(true);
8 request.uploadHandler(upload -> {
9 String tempFile = DeviceFirmwareController.getTempFirmwarePath(upload.filename());
10 upload.exceptionHandler(());
11 boolean isValidFilename = DeviceFirmwareController.isValidFilename(upload.filename());
12 if (isValidFilename) {
13 upload.streamToFileSystem(tempFile, ());
14 } else {
15 request.response().putHeader("Content-Type", "text/html");
16 request.response().end("${addDevFirmwareInvalid}");
17 request.response().close();
18 logger.warn(msgCommandFinishedWithErrors);
19 }
20 });
21 ...
Dieser Code kann über den Pfad /pages/jpages/system/DeviceFirmware/addFirmware
erreicht werden, solange die HTTP Anfrage einen gültigen “multipart/form-data” Body enthält.
Das hochgeladene TGZ Archiv wird mit der Methode extractFileFromArchiveToTmp
entpackt. In dieser Methode werden die im Archiv enthaltenen Dateinamen nicht weiter geprüft, weshalb das Schreiben einer Datei außerhalb des vorgesehenen Verzeichnisses möglich ist. Diese Art von Schwachstellen wird allgemein als ZipSlip bezeichnet.
1private static void extractFileFromArchive2Tmp(TarInputStream is, TarEntry entry) throws IOException {
2 boolean success = false;
3 File tmpFirmware = new File(TMP_DIR);
4 success = tmpFirmware.setWritable(true, false);
5 if (!tmpFirmware.exists()) {
6 success = tmpFirmware.mkdir();
7 } else {
8 success = true;
9 }
10 if (success) {
11 byte[] data = new byte[2048];
12 try(FileOutputStream entryStream = new FileOutputStream(TMP_DIR + FILE_SEP + entry.getName());
13 BufferedOutputStream dest = new BufferedOutputStream(entryStream)) {
14 int count;
15 while ((count = is.read(data)) != -1)
16 dest.write(data, 0, count);
17 dest.flush();
18 File folder = new File(TMP_DIR);
19 File[] listOfFiles = folder.listFiles();
20 for (File file : listOfFiles) {
21 if (file.isFile())
22 file.setReadable(true, false);
23 }
24 }
25 } else {
26 log.error("Not able to create " + TMP_DIR);
27 }
28 }
29 ...
Weitere Details sowie ein Proof of Concept finden sich im offiziellen RaspberyMatic Advisory.
Workarounds
Keine
Indicators of Compromise
- Prüfung der lighttpd Access Logs (
/var/log/lighttpd-access.log
) auf POST Requests für/pages/jpages/system/DeviceFirmware/addFirmware
- RapsberryMatic mountet die meisten Verzeichnisse als read only, daher können Angreifer über diese Schwachstelle nicht einfach eine WebShell auf das System laden. Eine zuverlässige Technik um eigenen Code auszuführen stellt das Überschreiben der Datei
/usr/local/addons/mediola/bin/watchdog
dar. Die SHA1 Checksumme dieser Datei ist659c7b88873dc2065e83ed28f4ceb84bfc50005f
.
Coordinated Disclosure Zeitverlauf
- 30/01/2024 Initialer Konakt mit RaspberryMatic.
- 30/01/2024 Rückmeldung von RaspberryMatic, mit der Bitte um weitere Details.
- 30/01/2024 Senden der detailierten Schwachstellenbeschreibung an RapsberryMatic.
- 31/01/2024 RaspberryMatic nimmt Mitarbeiter von eQ3 in die Kommunikation auf, eröffnet ein GitHub Security issue.
- 31/01/2024 eQ3 liefert ersten Fix für die Schwachstelle.
- 31/01/2024 GitHub weißt de Schwachstelle die CVE-2024-24578 zu.
- 01/02/2024 MOGWAI LABS gibt Feedback zum Security-Update von eQ3.
- 12/02/2024 RaspberryMatic informiert uns, dass die Schwachstelle in in der CCU/OCCU Firmware 3.76.x behoben sein wird, welche im März 2024 veröffentlicht werden soll.
- 13/02/2024 MOGWAI LABS akzeptiert das geplante Release, Nachfrage ob CCU/OCCU eine separate CVE beantragen werden.
- 18/03/2024 RaspberryMatic und CCU/OCCU veröffentlichen Advisories.