Alle Sicherheitshinweise

Orthanc DICOM Server

Out-of-Bounds-Lesezugriff im DICOM-Bilddecoder (PMSCT_RLE1-Dekomprimierung)

Orthanc dekodiert das proprietäre Philips-PMSCT_RLE1-Bildformat in zwei Durchgängen (RLE und anschließend Delta). Beide Durchgänge lesen zwei Bytes voraus, wenn sie auf einen Escape-Marker (0xa5 / 0x5a) treffen, prüfen jedoch nicht, dass diese Bytes innerhalb des Eingabepuffers liegen. Marker nahe dem Pufferende lösen Out-of-Bounds-Lesezugriffe aus, deren Bytes in die gerenderte Vorschau einfließen.

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

Beschreibung

PMSCT_RLE1 ist ein proprietäres RLE-und-Delta-Kompressionsformat, das von bestimmten Philips-Bildgebungsmodalitäten verwendet wird. Orthanc erreicht den Decoder, wenn eine DICOM-Datei das Standard-Tag PixelData (7FE0,0010) weglässt, jedoch die Philips-Private-Tags (0x07a1,0x1011) = "PMSCT_RLE1" und (0x07a1,0x100a) mit dem komprimierten Payload mitliefert — ImageSource::Setup fällt dann auf DecodePsmctRle1() zurück.

Der erste Durchgang implementiert die Run-Length-Expansion. Trifft er auf das Escape-Byte 0xa5, liest er zwei Folge-Bytes — einen Wiederholungszähler (i+1) und einen zu wiederholenden Wert (i+2) — ohne zu prüfen, ob diese Offsets innerhalb des Eingabepuffers liegen:

OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp:191-206 (RLE-Pass)

for (size_t i = 0; i < length; i++)
{
if (inbuffer[i] == 0xa5)
{
temp.push_back(inbuffer[i+2]); // OOB-Lesezugriff falls i >= length-2
for (uint8_t repeat = inbuffer[i + 1]; repeat != 0; repeat--)
{
temp.push_back(inbuffer[i+2]); // OOB-Lesezugriff bis zu 255-mal wiederholt
}
i += 2;
}
// ...
}

View source →

Der zweite Durchgang implementiert die Delta-Wert-Rekonstruktion. Trifft er auf 0x5a, liest er zwei Folge-Bytes (i+1, i+2) und kombiniert sie zu einem 16-Bit-Wert, ohne die Grenzen zu prüfen:

OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp:212-231 (Delta-Pass)

for (size_t i = 0; i < temp.size(); i++)
{
if (temp[i] == 0x5a)
{
uint16_t v1 = temp[i + 1]; // OOB-Lesezugriff falls i >= temp.size()-1
uint16_t v2 = temp[i + 2]; // OOB-Lesezugriff falls i >= temp.size()-2
value = (v2 << 8) + v1;
i += 2;
}
// ...
}

View source →

Der RLE-Durchgang ist die nutzbarere Primitive: Ein einzelnes 0xa5 nahe dem Pufferende mit einem Wiederholungszähler von 255 liest dasselbe Out-of-Bounds-Byte 256-mal in den Ausgabestrom und erzeugt eine kontrollierte Verstärkung eines einzelnen Heap-Bytes über hunderte Pixel im Vorschaubild.

Im Test wurde ein 24 Byte großer Payload (\x00*22 + \xa5\xff) verwendet, der einen glibc-32-Byte-Chunk füllt. Das 0xa5-Escape an Position 22 liest inbuffer[24] — die Metadaten des nächsten Heap-Chunks — und wiederholt es 256-mal. Der Delta-Durchgang akkumuliert diese Bytes anschließend zu aufsteigenden Pixel-Intensitäten:

Vorschau-Ausgabe (8x8, mode=L)

row 0: [ 0, 0, 0, 0, 0, 0, 0, 0]
row 1: [ 0, 0, 0, 0, 0, 0, 0, 0]
row 2: [ 0, 0, 0, 0, 0, 0, 6, 12]
row 3: [ 18, 24, 30, 36, 43, 49, 55, 61]
row 4: [ 67, 73, 79, 85, 91, 97, 103, 109]
row 5: [115, 121, 128, 134, 140, 146, 152, 158]
row 6: [164, 170, 176, 182, 188, 194, 200, 206]
row 7: [213, 219, 225, 231, 237, 243, 249, 255]

AddressSanitizer verortet den ersten Out-of-Bounds-Zugriff in DicomImageDecoder.cpp:195, unmittelbar hinter einer 24-Byte-Heap-Region:

AddressSanitizer-Trace

==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffffa5437348
READ of size 1 at 0xffffa5437348 thread T18
#0 in std::vector<unsigned char>::push_back() stl_vector.h:1192
#1 in Orthanc::DicomImageDecoder::DecodePsmctRle1() DicomImageDecoder.cpp:195
#2 in Orthanc::DicomImageDecoder::ImageSource::Setup() DicomImageDecoder.cpp:275
#3 in Orthanc::DicomImageDecoder::DecodeUncompressedImage() DicomImageDecoder.cpp:558
#4 in Orthanc::DicomImageDecoder::Decode() DicomImageDecoder.cpp:827
#5 in Orthanc::ParsedDicomFile::DecodeFrame() ParsedDicomFile.cpp:1823
#6 in Orthanc::ServerContext::DecodeDicomFrame() ServerContext.cpp:1921
0xffffa5437348 is located 0 bytes to the right of 24-byte region [0xffffa5437330,0xffffa5437348)
allocated by thread T18 here:
#0 in operator new[]
#1 in DcmElement::newValueField() dcelem.cc:788

Die Schwachstelle ist über dieselben zwei Pfade erreichbar wie CVE-2026-5445 (DecodeLookupTable): authentisierter HTTP-Upload + Vorschau, oder unauthentifizierte C-STORE-Ablage auf Port 4242 unter der Default-Konfiguration DicomAlwaysAllowStore: true. Variation der Payload-Größe über mehrere Anfragen hinweg tastet unterschiedliche Heap-Offsets ab und baut so einen mehrere Bytes umfassenden Heap-Dump auf.

Auswirkung

  • Offenlegung von Informationen aus beliebigem Heap-Speicher über gerenderte Vorschaubilder, mit kontrollierter Verstärkung (ein OOB-Byte wird in der Ausgabe bis zu 256-mal wiederholt) durch den RLE-Wiederholungszähler.
  • Durch Variation der Eingabe-Payload-Größe tastet der Angreifer über mehrere manipulierte Dateien hinweg unterschiedliche Heap-Offsets ab und baut einen mehrere Bytes umfassenden Heap-Dump auf.
  • In Orthancs Default-Konfiguration (DicomAlwaysAllowStore: true) ist das Ablegen unauthentifiziert; das Auslösen erfordert Read-Level-Authentifizierung.
  • Auf Builds mit striktem Heap-Layout (z. B. AddressSanitizer oder gehärteter glibc) kann ein Out-of-Bounds-Lesezugriff den Prozess abbrechen lassen; auf Standard-Builds ist das typische Resultat ein stiller Datenabfluss.

Abhilfe

Aktualisieren Sie Orthanc auf Version 1.12.11 oder höher. Der Patch fügt vor jedem i+1/i+2-Zugriff in beiden Durchgängen Grenzüberprüfungen ein und bricht das Decodieren mit BadFileFormat ab, sobald ein Escape-Marker auf zu wenig Folge-Daten trifft. Als sofortige Defense-in-Depth-Maßnahme setzen Sie DicomAlwaysAllowStore: false in orthanc.json und konfigurieren eine 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.

  • DICOM-Speicher auf PMSCT_RLE1-Payloads prüfen.

    Durchsuchen Sie den Speicher nach Studien, die (7FE0,0010) PixelData weglassen, jedoch (0x07a1,0x1011) = "PMSCT_RLE1" enthalten. Studien aus Quellen außerhalb Ihres Modalitäten-Inventars oder mit unerwarteter Payload-Größe sollten vor dem Patch in Quarantäne und zur Prüfung gegeben werden.

Bewertung im Detail

AV:LDer publizierte Vektor behandelt den Pfad als Local-Vector: Ein Akteur lädt eine manipulierte DICOM-Datei hoch oder speichert sie, die ein anderer Agent später rendert. Hinweis: Die Schwachstelle ist auch netzseitig per HTTP-REST und per C-STORE auf Port 4242 erreichbar.AC:LEine einzelne manipulierte DICOM-Datei mit RLE-Escape nahe dem Pufferende; keine Umgebungsvorbedingungen.PR:NDer publizierte Vektor spiegelt Deployments wider, in denen der C-STORE-Listener unter dem Default DicomAlwaysAllowStore: true unauthentifizierte Requests akzeptiert und die Vorschau-Wiedergabe ohne HTTP-Authentifizierung exponiert ist.UI:REin Aufrufer (derselbe oder ein anderer Viewer) muss die Vorschau anfordern, damit das manipulierte DICOM gerendert und der Out-of-Bounds-Lesezugriff ausgelöst wird.S:UNur der Orthanc-Prozess ist betroffen; über diese Primitive sind keine prozessübergreifenden Ressourcen erreichbar.C:HKontrollierte Offenlegung von Heap-Inhalten über viele Ausgabe-Pixel pro Anfrage, mit Payload-Größen-Variation als Sweep über Heap-Offsets.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.