Alle Sicherheitshinweise

Orthanc DICOM Server

Out-of-Bounds-Lesezugriff im DICOM-Bilddecoder (DecodeLookupTable)

Der PALETTE-COLOR-Bilddecoder von Orthanc validiert, dass die LUT-Arrays zur deklarierten Palettengröße passen, prüft aber nicht, dass die als LUT-Indizes verwendeten Pixelwerte innerhalb dieses Bereichs bleiben. Werte außerhalb des Bereichs lesen über die LUT hinaus in angrenzenden Heap-Speicher; die ausgelesenen Bytes werden zu RGB-Werten im Vorschaubild und an den Aufrufer zurückgegeben.

Verfasst vonVolker Schönefeld, Simon WeberErstveröffentlichung 2026-04-02Vollständige Offenlegung 2026-04-28
SchweregradKritischCVSS 9.1CVSS-3.1-VektorAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:HCWECWE-125 (Out-of-bounds Read)ProduktOrthanc DICOM ServerBetroffene VersionenOrthanc <= 1.12.10Behoben in1.12.11CVECVE-2026-5445CERT/CCVU#536588.5

Beschreibung

DICOM-PALETTE-COLOR-Bilder enthalten kanalspezifische Color-Lookup-Tables (Rot, Grün, Blau) und Pixeldaten, deren Werte als Indizes in diese LUTs dienen. Orthancs DecodeLookupTable dekodiert diese Bilder, indem es jedes Pixel durchläuft und drei LUT-Einträge (einen pro Kanal) in das Ausgabe-RGB-Bild liest. Das Framework prüft, dass die LUT-Arrays selbst zur deklarierten paletteSize passen, prüft jedoch nie, ob ein einzelner Pixelwert innerhalb von [0, paletteSize) liegt.

OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp:491-502

for (unsigned int y = 0; y < height; y++)
{
uint8_t* p = reinterpret_cast<uint8_t*>(target->GetRow(y));
for (unsigned int x = 0; x < width; x++)
{
// OOB-Lesezugriff falls *source >= paletteSize
p[0] = lutRed[*source] >> offsetBits;
p[1] = lutGreen[*source] >> offsetBits;
p[2] = lutBlue[*source] >> offsetBits;
source++;
p += 3;
}
}

View source →

Bei einer 16-Eintrag-LUT und Pixelwert 200 landet der Lesezugriff 368 Bytes hinter dem LUT-Puffer (jeder LUT-Eintrag ist uint16_t). Die drei OOB-Lesezugriffe pro Pixel zielen auf separate LUT-Allokationen (Rot, Grün, Blau) und liefern jeweils eine eigenständige Heap-Lese-Primitive. Die ausgelesenen Bytes werden in das RGB-Pixeltripel geschrieben und über den Preview-Endpunkt zurückgegeben.

Nur der PixelFormat_RGB24-Pfad ist betroffen. Der PixelFormat_RGB48-Pfad fixiert paletteSize auf 65536 und nutzt uint16_t-Source-Werte, sodass der maximale Index 65535 exakt in die LUT passt.

Im Test wurde ein 8x8-PALETTE-COLOR-DICOM mit paletteSize=16 und Pixelwerten 16-79 verwendet. Die Vorschau lieferte ein 8x8-RGB-Bild zurück, in dem über 50 von 64 Pixeln Werte ungleich Null trugen — ausgelesene Heap-Daten:

Auszug aus der Vorschau (Rot-Kanal, OOB-Lesezugriff aus der lutRed-Heap-Region)

0000: 30 00 00 00 45 00 00 00 30 f9 0f 00 1e 99 bb f3 0...E...0.......
0010: 31 34 31 31 37 03 ff 00 08 18 66 62 70 03 ff 00 14117.....fbp...
0020: 40 00 00 00 45 00 00 00 20 00 00 00 63 5f 74 69 @...E... ...c_ti
0030: 67 00 54 00 21 00 00 00 90 00 ff 00 90 00 ff 00 g.T.!...........

Im Hex-Dump erscheinen klare ASCII-Strings — 14117, fbp, c_tig — die internen Orthanc-Identifiern und DICOM-Tag-Daten in benachbarten Heap-Chunks entsprechen. Über 21 aufeinanderfolgende Läufe gegen ein Standard-1.12.10-Docker-Image lieferte jeder Lauf 41 bis 53 von 64 Pixeln mit Inhalt zurück, mit zwischen den Läufen variierendem Inhalt entsprechend der wechselnden Heap-Layouts. Repräsentative Lecks umfassten DICOM-UID-Fragmente (038485967947477029570663), interne Klassen-/Methodennamen (PrnPtet, PrnSre, RmtAT), DICOM-Tag-Fragmente (mdl-ain, nsif) und wiederkehrende glibc-Chunk-Header-Pointer-Muster.

AddressSanitizer verortet den ersten Out-of-Bounds-Zugriff in DicomImageDecoder.cpp:497, unmittelbar hinter einer 32-Byte-LUT-Region, die durch DcmElement::newValueField() allokiert wurde:

AddressSanitizer-Trace

==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffff95c34bf0
READ of size 2 at 0xffff95c34bf0 thread T17
#0 in DecodeLookupTable DicomImageDecoder.cpp:497
#1 in Orthanc::DicomImageDecoder::DecodeUncompressedImage() DicomImageDecoder.cpp:575
#2 in Orthanc::DicomImageDecoder::Decode() DicomImageDecoder.cpp:827
#3 in Orthanc::ParsedDicomFile::DecodeFrame() ParsedDicomFile.cpp:1823
#4 in Orthanc::ServerContext::DecodeDicomFrame() ServerContext.cpp:1921
0xffff95c34bf0 is located 0 bytes to the right of 32-byte region [0xffff95c34bd0,0xffff95c34bf0)
allocated by thread T17 here:
#0 in operator new[]
#1 in DcmElement::newValueField() dcelem.cc:788

Die Schwachstelle ist über zwei unterschiedliche Pfade erreichbar. Erstens als authentisierter HTTP-Upload: POST /instances gefolgt von GET /instances/{id}/preview. Zweitens als gespeicherter Angriff über DICOM C-STORE auf Port 4242. Die Default-Konfiguration von Orthanc (DicomAlwaysAllowStore: true) akzeptiert C-STORE-Requests ohne Authentifizierung, sodass ein Angreifer im Netzwerk ein manipuliertes PALETTE-COLOR-DICOM unauthentifiziert ablegen kann. Jede nachfolgende Vorschau-Anfrage einer authentisierten Person — einschließlich des Angreifers selbst mit reinen Read-Access-Credentials — löst den Out-of-Bounds-Lesezugriff aus und gibt die ausgelesenen Heap-Daten im gerenderten Bild zurück.

Auswirkung

  • Offenlegung von Informationen aus beliebigem Heap-Speicher (interne Orthanc-Identifier, DICOM-Tag-Daten, glibc-Chunk-Metadaten) über gerenderte Vorschaubilder.
  • Drei eigenständige Heap-Lese-Primitiven pro Pixel (eine pro LUT). Durch Variation der Pixelwerte über manipulierte Dateien hinweg lassen sich unterschiedliche Heap-Offsets abtasten und ein mehrere Bytes umfassender Heap-Dump zusammensetzen.
  • In Orthancs Default-Konfiguration (DicomAlwaysAllowStore: true) ist das Ablegen unauthentifiziert; das Auslösen des Lecks erfordert Read-Level-Authentifizierung.
  • Erreicht der Out-of-Bounds-Lesezugriff eine nicht gemappte Speicherseite, terminiert der Orthanc-Prozess unerwartet. Auf Standard-Builds mit normalem Heap-Layout ist dies selten.

Abhilfe

Aktualisieren Sie Orthanc auf Version 1.12.11 oder höher. Der Patch fügt eine pixelweise Grenzüberprüfung (*source >= paletteSize → throw) innerhalb der Decode-Schleife ein. Als sofortige Defense-in-Depth-Maßnahme setzen Sie DicomAlwaysAllowStore: false in orthanc.json und konfigurieren eine explizite AET-Allowlist, was den unauthentifizierten Ablegevektor schließt.

Checkliste für Betreiber

  • Version prüfen.

    curl -u <user>:<pass> http://<orthanc>:8042/system | jq .Version — der gepatchte Bereich beginnt bei 1.12.11.

  • Unauthentifizierten C-STORE-Ablegevektor schließen.

    Setzen Sie DicomAlwaysAllowStore: false in orthanc.json und definieren Sie eine explizite DicomModalities-Allowlist legitimer AETs. Andernfalls kann jeder Host, der Port 4242 erreicht, das manipulierte DICOM unauthentifiziert ablegen.

  • Vorschau-Endpunkt einschränken.

    Wenn Ihr Deployment keine Web-Vorschau benötigt, beschränken Sie GET /instances/*/preview an Ihrem Reverse-Proxy. Der Out-of-Bounds-Lesezugriff wird erst beobachtbar, wenn das manipulierte Bild gerendert wird.

  • Read-Access-Konten prüfen.

    Ein Angreifer benötigt nur Read-Level-Credentials, um die ausgelesenen Heap-Daten zu sehen. Prüfen Sie RegisteredUsers in orthanc.json und ein externes Authentifizierungsbackend auf veraltete oder niedrig privilegierte Konten, die keinen Lesezugriff auf beliebige Studien haben sollten.

  • Auf Abstürze nach Vorschau-Anfragen achten.

    Auf Builds mit striktem Heap-Layout kann der Out-of-Bounds-Lesezugriff gelegentlich eine nicht gemappte Seite treffen. Alarmieren Sie auf Orthanc-Prozessneustarts unmittelbar nach GET /instances/*/preview-Logeinträgen.

  • DICOM-Speicher auf auffällige PALETTE-COLOR-Studien prüfen.

    Durchsuchen Sie den Speicher nach Studien mit PhotometricInterpretation = PALETTE COLOR und kleiner Palettengröße (z. B. paletteSize ≤ 16), deren Pixeldaten Werte größer als der Palettenbereich enthalten. Solche bereits vor dem Patch abgelegten Studien wurden möglicherweise bereits zur Speicheroffenlegung genutzt.

Bewertung im Detail

AV:NÜber das Netzwerk per HTTP-REST-API von Orthanc (POST /instances + /preview) sowie per DICOM C-STORE auf Port 4242 erreichbar.AC:LDeterministisches Leck. Im Test trugen 41-53 von 64 Pixeln in jedem von 21 aufeinanderfolgenden Läufen gegen einen Standard-Build Heap-Inhalte.PR:NDer publizierte Vektor spiegelt Deployments wider, in denen die Vorschau-Wiedergabe ohne HTTP-Authentifizierung exponiert ist und der C-STORE-Listener unter dem Default DicomAlwaysAllowStore: true unauthentifizierte Requests akzeptiert. Beide Schranken sind konfigurierbar; siehe die Checkliste für Betreiber unten.UI:NKeine Interaktion durch eine zweite Person erforderlich; Ablegen und Auslösen können von derselben Person durchgeführt werden.S:UNur der Orthanc-Prozess ist betroffen; über diese Primitive sind keine prozessübergreifenden Ressourcen erreichbar.C:HOffenlegung von Heap-Inhalten über mehrere voneinander unabhängige Lesezugriffe pro Pixel. Nachgewiesene Lecks umfassen Orthanc-interne IDs, DICOM-UID-Fragmente und benachbarte Tag-Daten.I:NReine Lese-Primitive; nichts wird modifiziert.A:HAuf Builds mit striktem Heap-Layout kann der Out-of-Bounds-Lesezugriff eine nicht gemappte Speicherseite treffen und den Orthanc-Prozess terminieren.

Referenzen

So können wir helfen

Wer wir sind

Die Sicherheitsforscher hinter diesem Sicherheitshinweis.

Dr. Simon Weber Profile

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
Volker Schönefeld Profile

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.