mercure
Nicht authentifizierte Remote Code Execution im DICOM-Receiver
Der mercure-DICOM-Receiver baut aus Werten, die in eingehenden DICOM-Daten enthalten sind, einen Betriebssystembefehl zusammen. Ein Host, der DICOM-Daten an den Receiver senden kann, kann dadurch beliebige Befehle auf dem empfangenden Server ausführen, ganz ohne Authentifizierung.
system()-Aufruf wurde entfernt: getdcmtags postet nun über einen Socket mit URL-kodierten Werten an den Bookkeeper, statt ein Shell-Kommando zu bauen.CVEAusstehendGHSAAusstehendBeschreibung
mercure ist eine quelloffene DICOM-Routing- und Verarbeitungsplattform für Workflows in der medizinischen Bildgebung. Wir schätzen die Arbeit der Maintainer daran sowie ihre schnelle, konstruktive Reaktion auf diesen Bericht.
Das getdcmtags-Binary ist Teil der DICOM-Receiver-Pipeline. Nachdem storescp eine eingehende DICOM-Datei geschrieben hat, extrahiert getdcmtags die Tag-Werte und registriert die Datei beim Bookkeeper-Dienst. Diesen Registrierungsaufruf baut es per String-Verkettung als Shell-Kommando zusammen und führt ihn mit system() aus.
Zwei Tag-Werte, SOPInstanceUID und SeriesInstanceUID, werden mit DCMTKs findAndGetOFStringArray() gelesen, das die Rohbytes ohne Prüfung des DICOM-UID-Formats (nur Ziffern und Punkte) zurückgibt. Sie werden direkt in das Kommando verkettet:
getdcmtags/main.cpp:64-87
void sendBookkeeperPost(OFString filename, OFString fileUID, OFString seriesUID){ if (bookkeeperAddress.empty()) { return; }
std::string cmd = "wget -q -T 1 -t 3 --post-data=\"filename="; cmd.append(filename.c_str()); // enthält SeriesInstanceUID cmd.append("&file_uid="); cmd.append(fileUID.c_str()); // SOPInstanceUID, vom Angreifer kontrolliert cmd.append("&series_uid="); cmd.append(seriesUID.c_str()); // SeriesInstanceUID cmd.append("\""); cmd.append(" --header=\"Authorization: Token "); cmd.append(bookkeeperToken); cmd.append("\" http://"); cmd.append(bookkeeperAddress); cmd.append("/register-dicom -O /dev/null");
system(cmd.data()); // Command Injection}Vor der Verkettung führt readTag() eine kleine Zeichenersetzung durch, die unzureichend und in einem Fall sogar schädlich ist: Ein Carriage Return wird zu ; umgeschrieben, was einen Shell-Kommandotrenner einführt. Dollarzeichen, Klammern, Backticks und Pipes bleiben unverändert. Da die Werte im Kommando in doppelten Anführungszeichen stehen, wird $(...)-Kommandosubstitution weiterhin von der Shell ausgewertet:
getdcmtags/main.cpp:172-204
OFCondition result = dataset->findAndGetOFStringArray(tag, out);// ...for (size_t i = 0; i < out.length(); i++){ switch (out[i]) { case 13: // CR -> Semikolon out[i] = ';'; break; case 10: // LF -> Leerzeichen out[i] = ' '; break; case 34: // doppeltes -> einfaches Anführungszeichen out[i] = 39; break; default: break; }}Der Receiver betreibt storescp mit --promiscuous und akzeptiert daher Verbindungen von beliebigen Calling-AE-Titeln ohne Authentifizierung. Ein einziges DICOM-C-STORE an Port 11112 mit einer präparierten SOPInstanceUID genügt: getdcmtags liest den Wert, übergibt ihn an sendBookkeeperPost(), und system() wertet das eingebettete Kommando während der Argumentexpansion aus. Der Bookkeeper muss nicht erreichbar sein; das eingeschleuste Kommando läuft, bevor wget fehlschlägt.
Die Injection zielt gezielt auf SOPInstanceUID. SeriesInstanceUID ist ebenfalls vom Angreifer kontrollierbar, wird aber zuvor für Verzeichniserstellung und Dateiumbenennung verwendet; Shell-Metazeichen lassen diese Dateioperationen fehlschlagen, sodass getdcmtags beendet wird, bevor der verwundbare Aufruf erreicht ist. SOPInstanceUID wird ausschließlich von sendBookkeeperPost() verarbeitet.
Die Befehlsausführung als Benutzer mercure (uid 1000) wird durch die Ausgabe eines eingeschleusten id-Kommandos bestätigt:
Proof-of-Concept-Ausgabe
uid=1000(mercure) gid=1000(mercure) groups=1000(mercure)Auswirkung
- Ein entfernter, anonymer Angreifer, der den DICOM-Receiver erreichen kann, kann Betriebssystembefehle auf dem empfangenden Server ausführen. Der Receiver akzeptiert Verbindungen von beliebigen Calling-AE-Titeln, sodass keine Anmeldedaten erforderlich sind.
- Die eingeschleusten Befehle laufen als Benutzer
mercureinnerhalb des Receiver-Containers, mit Zugriff auf die vom Receiver verarbeiteten Bilddaten sowie auf die eingebundenen Konfigurations- und Datenvolumes. Je nach Deployment verschafft dies einen Ausgangspunkt für weitere Bewegungen im klinischen Netzwerk. - Für ein Krankenhaus oder eine Klinik bedeutet das: Der Server, der Patientenbilder empfängt, kann von jedem übernommen werden, der ihn im Netzwerk erreicht, ganz ohne Anmeldung.
Abhilfe
Aktualisieren Sie auf mercure 0.4.1; dort wurde der system()-Aufruf entfernt: getdcmtags postet nun über einen Socket mit URL-kodierten Werten an den Bookkeeper, statt ein Shell-Kommando zu bauen. Zwei allgemeine Schutzmaßnahmen gelten für jeden Code dieser Art: externe Programme ohne Shell aufrufen (ein Argumentvektor über execvp() oder posix_spawn(), nicht system()) und DICOM-UIDs vor der Verwendung gegen ihr spezifiziertes Format (nur Ziffern und Punkte) prüfen. Bis zum Update sollte der Netzwerkzugriff auf den Receiver-Port auf vertrauenswürdige Bildquellen beschränkt werden.
Checkliste für Betreiber
Auf 0.4.1 oder neuer aktualisieren
Das gepatchte Release ausrollen und sicherstellen, dass das Receiver-Image neu gebaut wurde, da der Fix im
getdcmtags-Binary liegt.Receiver-Port einschränken
Den Netzwerkzugriff auf den DICOM-Port (Standard 11112) auf bekannte Bildgebungsmodalitäten und DICOM-Knoten beschränken; Verbindungen von unerwarteten Hosts als verdächtig behandeln.
Receiver-Logs prüfen
Receiver- und
getdcmtags-Logs auf unerwartete Befehle oderwget-Fehler im Umfeld von Verbindungen unbekannter Quellen prüfen.
Bewertung im Detail
storescp läuft mit --promiscuous und akzeptiert beliebige Calling-AE-Titel, sodass keine Anmeldedaten erforderlich sind.UI:NDie Verarbeitung erfolgt automatisch beim Empfang; keine Benutzerinteraktion erforderlich.S:UDer Code wird im Sicherheitskontext des Receivers selbst ausgeführt.C/I/A:HBeliebige Befehlsausführung als Receiver-Prozess gewährt vollständigen Lese-, Änderungs- und Verweigerungszugriff auf die Daten und Host-Ressourcen, die er kontrolliert.Referenzen
So können wir helfen
Wer wir sind
Die Sicherheitsforscher hinter diesem Sicherheitshinweis.

Dr. rer. nat. Simon Weber
Senior Pentester & MedSec-Forscher
Ich evaluiere Ihr SaMD mit derselben branchenprägenden Sicherheitsexpertise, die ich dem BAK MV für die Überarbeitung des B3S-Standards beigetragen habe.
- Promotion über Krankenhaus-Cybersicherheit
- Kritische Schwachstellen in Krankenhaussystemen gefunden
- Alumni der THB MedSec-Forschungsgruppe
- gematik Security Hero

Dipl.-Inf. Volker Schönefeld
Senior Application Security Expert
Als ehemaliger CTO und Entwickler, der zum Pentester wurde, arbeite ich mit Ihrem Team zusammen, um Schwachstellen aufzudecken und Lösungen zu finden, die zu Ihrer Architektur passen.
- 20+ Jahre als CTO, 50+ Mio. App-Downloads
- Architektur und Absicherung großer IoT-Flotten
- Certified Web Exploitation Specialist
- gematik Security Hero
Penetrationstest gesucht?
Machine Spirits ist spezialisiert auf Sicherheitsbewertungen für Medizinprodukte und Gesundheits-IT. Von MDR-Penetrationstests bis C5-Cloud-Compliance helfen wir MedTech-Unternehmen, regulatorische Anforderungen zu erfüllen.
