Die Sicherheitsupdates, die Microsoft am 11. April 2023 veröffentlichte, beseitigten über 90 einzelne Sicherheitslücken. Besonders bemerkenswert war CVE-2023-21554, genannt QueueJumper, eine Schwachstelle für die Remote-Codeausführung, die den Microsoft Message Queueing (MSMQ) Dienst betrifft. MSMQ ist eine optionale Windows-Komponente, die es Anwendungen ermöglicht, Nachrichten über Nachrichtenwarteschlangen auszutauschen, die sowohl lokal als auch aus der Ferne erreichbar sind. Diese Analyse wurde in Zusammenarbeit mit den Teams von Randori und X-Force Adversary Services durchgeführt, von Valentina Palmiotti, Fabius Watson und Aaron Portnoy.
Die folgenden Eigenschaften von CVE-2023-21554 erregten zunächst Aufmerksamkeit:
Bleiben Sie mit dem Think-Newsletter über die wichtigsten – und faszinierendsten – Branchentrends in den Bereichen KI, Automatisierung, Daten und mehr auf dem Laufenden. Weitere Informationen finden Sie in der IBM Datenschutzerklärung.
Um zu bestimmen, wie das Vorhandensein von MSMQ erkannt werden kann, wurde ein Testsystem mit der Komponente in einer Laborumgebung konfiguriert. Beim Verbindungsaufbau zum MSMQ-Endgerät auf Port 1801 antwortete der Server nicht mit Daten. Man könnte davon ausgehen, dass der Server nicht antwortet, wenn er keine plausiblen Daten erhält. Um zu verstehen, wie man mit dem Endgerät kommuniziert, war eine genauere Untersuchung des zugrundeliegenden Codes erforderlich.
Aus dem Advisory geht nicht unmittelbar hervor, welche Binärdatei gepatcht wurde. Der erste Schritt zur Identifizierung des geänderten Codes war das Herunterladen der Update-Datei. Das wurde durch die Suche nach KB5025224 im Microsoft Update-Katalog erreicht.
Suchergebnisse im Microsoft Update-Katalog für KB5025224
Insbesondere die kumulative Aktualisierungsdatei
windows10.0-kb5025224-x64_3522b1b562ed44bc949541dd1c7d08e1e967d925.msu
für Windows 11 für x86-basierte Systeme wurde abgerufen.
Der 7-Zip-Extractor wurde verwendet, um den Inhalt der MSU-Datei und der darin enthaltenen CAB-Dateien zu entpacken. Die Suche nach der Zeichenfolge „msmq“ in allen Dateien in den resultierenden Ordnern ergab die Container-Indexdatei,
Windows11.0-KB5025239-x64/express.psf.cix.xml,
wozu auch folgender Eintrag gehörte:
<File id="21296" name="amd64_microsoft-windows-msmq-queuemanager-core_31bf3856ad364e35_10.0.22621.1555_none_5f975f8fdb349517\f\mqqm.dll" length="34811" time="133245266510000000" attr="128">
Dieser Eintrag bezieht sich auf
Um die Änderungen zwischen der gepatchten und der ungepatchten Version der DateiMQQM.dll1.00
BinDiff-Ergebnisse zwischen gepatchten und ungepatchten MQQM.dll-Dateien
Die Analyse dieser Funktionen mit dem Hex-Rays Decompiler ergab Symbole für die gepatchte Version, die ausführliche Funktionsnamen enthalten, welche anscheinend auf Schwachstellenkennungen des Microsoft Security Research Center (MSRC) verweisen:
Funktions-Flag-Symbole in MQQM.dll
Bei näherer Betrachtung entsprechen die Symbole mit MSRC-Fallnummern den Feature Flags für Schwachstellenbehebungen. Feature Flags sind eine Komponente von Windows, mit der verschiedene Funktionen und Experimente aktiviert oder deaktiviert werden können. In diesem Fall handelt es sich bei dem entdeckten „Feature” tatsächlich um einen Patch für eine Schwachstelle. Wenn das Feature aktiviert ist, wird der sichere, gepatchte Codepfad ausgeführt. Andernfalls wird der ursprüngliche, ungepatchte Codepfad ausgeführt.
Dekompilierter Codeausschnitt mit Funktion zur Behebung der Sicherheitslücke
Für jede der Sicherheitslücken, die CVE-2023-21554 umfassten, wurde sowohl in der Benutzer- als auch in der Kernelkomponente eine Funktions-Flag-Überprüfung durchgeführt. Die Analyse der verbleibenden Binärdateien, die im Sicherheitsupdate-Paket enthalten sind, ergab, dass auch Funktions-Flags für die meisten oder alle Sicherheitslücken eingeführt wurden, die am Patch Tuesday im April 2023 behoben wurden.
Durch den Abgleich dieser Flags konnten wir die Stellen im gepatchten Code schnell lokalisieren. Insbesondere die Änderungen innerhalb von , welche sich auf die ixes-Flag MSRC76146_MSMQ_OOBRWF
Die Überprüfung dieses Funktions-Flags erfolgt achtmal innerhalb der Funktion. Eine solche Überprüfung ist unten dargestellt:
Dekompilierter Codeausschnitt, der die Fixes der Sicherheitslücke zeigt
Im oben gezeigten dekompilierten Codeausschnitt erhält der gepatchte Codepfad den Zeiger auf den nächsten Abschnitt der MSMQ-Nachricht durch einen Aufruf von
Dekompilierungsausschnitt der Funktion GetNextSectionPtrSafe
Nach der Untersuchung aller Vorkommnisse dieser Funktion und anderer wurde festgestellt, dass CVE-2023-21554 aus mehreren Fehlern besteht, die die Größe verschiedener MSMQ-Nachrichtenabschnittstypen unzureichend überprüfen. Durch diese Schwachstellen kann der Hinweis auf das Ende der MSMQ-Nachricht um einen beliebigen 32-Bit-Offset außerhalb der Grenzen des ursprünglich zugewiesenen Buffers erhöht werden.
Nach der Paketverarbeitung wird im letzten Schritt von
Überprüfung des Speicherzugriffs außerhalb des Speicherbereichs für Nachrichtenende
Bei der Bewertung der Ausnutzbarkeit der Schwachstellen wurden weitere Kernel-Schwachstellen im entsprechenden Treiber für den MSMQ-Dienst identifiziert, . Die Schwachstellen wurden erneut durch Funktion-Flag-Symbole angezeigt, die ebenfalls auf den MSRC-Fall 76146 verweisen, wie in beobachtet.
Funktions-Flag-Symbole in mqac.sys
Die Analyse der Funktion
Um die zugehörigen Vorgänge auszuführen, analysiert die Kernelkomponente verschiedene Abschnitte des MSMQ-Paketpuffers. Zwei solcher Instanzen sind unten abgebildet:
Dekompilierter Codeausschnitt, der das Funktions-Flag zur Behebung einer Sicherheitslücke im Kernel-Treiber mqac.sys zeigt
Wie im dekompilierten Codeschnipsel oben zu sehen ist, werden, wenn das Feature-Flag aktiviert ist, die „sicheren“ Funktionen
Der Großteil des Codes für das Parsen von Protokollen befindet sich in der Bibliothekmqsvc.exe referenziert wird, muss eine gültige MSMQ-Anfrage vom Client gesendet werden. Die MSMQ-Nachrichtenspezifikation und das Protokoll sind umfangreich und komplex. Anfangs wurde öffentlicher Code für das Scannen von MSMQ-Servern in einem GitHub-Gist gefunden, der die Grundlage für eine tiefere Untersuchung der Paketverarbeitung bildete. Darüber hinaus war die Microsoft-Dokumentation hilfreich, um das MSMQ-Nachrichtenformat zu verstehen.
Der Code innerhalb der DLL akzeptiert Daten über Port 1801 mit einem Aufruf der WSARecc-Funktion, wie in der untenstehenden Debugging-Sitzung zu sehen ist:
0:020> bp ws2_32!wsarecv ; g
Breakpoint 0 erreicht
WS2_32!WSARecv:
00007ffd`651115c0 48895c2408 mov qword ptr [rsp+8],rbx ss:000000aa`f07fef30=0000000000000006
0:019> k
# Child-SP RetAddr Call Site
00 000000aa`f07fef28 00007ffd`57ba9cb0 WS2_32!WSARecv
01 000000aa`f07fef30 00007ffd`57b9683d
MQQM!NoReceivePartialBuffer+0x38
02 000000aa`f07fefb0 00007ffd`57b2078e MQQM!CWinsockConnection::ReceivePartialBuffer+0x7d
03 000000aa`f07ff010 00007ffd`57b25b28
MQQM!CSockTransport::BeginReceive+0xe6
04 000000aa`f07ff060 00007ffd`57b2d40b
MQQM!CSockTransport::NewSession+0x194
05 000000aa`f07ff3f0 00007ffd`57b2d367 MQQM!CSessionMgr::AcceptSockSession+0x6f
06 000000aa`f07ff430 00007ffd`645e26bd MQQM!AcceptIPThread+0x6a7
07 000000aa`f07ff7d0 00007ffd`6650a9f8
KERNEL32!BaseThreadInitThunk+0x1d
08 000000aa`f07ff800 00000000`00000000 ntdll!RtlUserThreadStart+0x28
0:019> r @$t0=@rdx
0:019> pt
WS2_32!WSARecv+0x19f:
00007ffd`6511175f c3 ret
0:019> dc poi(@$t0+8) LC
000001b5`880ff490 62f06110 524f494c 00000070 5a5a5a5a .a.bLIORp…ZZZZ
000001b5`880ff4a0 0073006e 00610074 0063006e 00200065 n.s.t.a.n.c.e. .
000001b5`880ff4b0 00440049 00000000 00000000 00000000 I.D………….
0:019> ba r1 poi(@$t0+8) ; g
Breakpoint 1 erreicht
MQQM!CBaseHeader::SectionIsValid+0x154:
00007ffd`57b53450 7462 je
MQQM!CBaseHeader::SectionIsValid+0x1b8 (00007ffd`57b534b4) [br=1]
Die Funktion ist dafür verantwortlich, den Anfang einer neuen Nachricht zu parsen, die mit einer BaseHeader-Struktur der Form beginnt:
Struktur des BaseHeader-Objekts
Die Felder der eingehenden Nachricht werden durch
Disassemblierungscode für SectionIsValid innerhalb von MQQM.dll
Nach der ersten Validierung findet der Großteil des Protokollparsings innerhalb der Konstruktorfunktion
Dekompilierung zeigt Sicherheitslücke bei der Handhabung von EodHeader
Die obige Dekompilierung zeigt den gepatchten Pfad, der die Funktion
Die Struktur eines
Demontage Berechnung der Gesamtgröße des EodHeader-Abschnitts
In der obigen Disassemblierung wird der Zeiger auf den Anfang von
WinDbg-Sitzung zeigt eine Zugriffsverletzung beim Schreiben an das Ende einer fehlerhaften MSMQ-Nachricht an.
Um die Stärke des durch die Sicherheitslücken erzielten Schreibvorgangs außerhalb des zulässigen Bereichs zu bewerten, haben wir zunächst die Zuweisung und Verwaltung des zugrunde liegenden Speichers untersucht.
Bevor ein Nachrichtenpaket MSMQ zugewiesen wurde. Diese Funktion ruft den Kernel-Treiber überNtDeviceIoControl.
Dekompilierung der Paket-Bufferzuweisungsfunktion
Die Kernel-Komponente gibt einen Puffer zurück, der aus einer gemappten Ansicht einer Datei auf der Festplatte partitioniert ist, gespeichert im Verzeichnis
ProcessHacker-Speicherlayout des MQSVC-Prozesses, das zeigt, dass der Paketpufferspeicher eine Dateizuordnung ist
Die Paketpufferadresse wird zusammen mit einem zufälligen Paket-Handle nach der Zuweisungsanforderung über IOCTL an den Benutzerbereich zurückgegeben. Der Treiber verwendet das Handle, um die Paketpufferadresse bei der Bearbeitung von Anforderungen aus dem Benutzerbereich zu berechnen.
Der zugrundeliegende Speicherplatz für die anfälligen Buffer befindet sich in einer zugeordneten Datei und somit nicht im Heap des Prozesses. Außerdem speichert der betroffene Speicher keine Objekte. Die Dateizuordnung enthält ausschließlich den Inhalt der MSMQ-Nachrichten sowie die darin gespeicherten Metadaten.
Darüber hinaus ist es ohne Vorkenntnisse über den Speicheraufbau nicht möglich, die relative Positionierung der Dateizuordnung zum Heap des Prozesses zu kennen, um Objektzeiger zu überschreiben. Um also die Ausführung von Remote-Code zu ermöglichen, benötigen wir eine Methode, mit der sich der Speicher in eine vorhersagbare Position bringen lässt.
Nach Experimenten mit dem Senden legitimer MSMQ-Nachrichten an das Ziel wurde festgestellt, dass es möglich ist, eine neue Heap-Allokation neben einer Dateizuordnung
Speicherlayout des MQSVC-Prozesses zeigt einen neuen Heap, der direkt an eine MQ-Dateizuordnung angrenzt
Dies setzt jedoch voraus, dass der Angreifer Zugriff auf das Senden von Nachrichten an mindestens eine Warteschlange des Ziels hat. Andernfalls werden die Nachrichten verworfen und überschrieben und belegen daher den Paketspeicher nicht dauerhaft.
In den durchgeführten Forschungsversuchen wurde festgestellt, dass es einem nicht privilegierten Benutzer möglich ist, eine Warteschlange zu erstellen, die standardmäßig für jeden zugänglich ist, um Nachrichten aus der Ferne zu senden. Die Warteschlange bleibt auf dem System auf unbestimmte Zeit bestehen. Obwohl die meisten modernen Anwendungen von MSMQ als optionale Komponenten und Adapter existieren, bieten Anbieter wie Oracle, Veritas und Xerox Unternehmenssoftware an, die MSMQ als zentrale Abhängigkeit nutzt. Daher ist das Angriffsszenario nicht unrealistisch.
Die Sicherheitslücke im Zusammenhang mit ausgehendem Speicherzugriff führt ein Exploit-Primitiv ein, das es einem böswilligen Client ermöglicht, einenOnDiskExtensionHeader
Bei der Bewertung einer Schwachstelle, die das Schreiben von Werten in einen Offset ermöglicht, müssen einige Eigenschaften
berücksichtigt werden:
Im Fall der QueueJumper-Sicherheitslücken ist der Offset des zugewiesenen Puffers zum OOB-Schreiben kontrollierbar, da er anhand von vom Angreifer kontrollierten Daten berechnet wird. Der Inhalt des OOB-Schreibens unterliegt jedoch einer begrenzten Kontrolle.
Hier stelltAddress geschrieben wird. Die Abfolge der Vorgänge ist wie folgt:
0x000000000000000C
wird geschrieben aufAddress0x00000000Address+0x2
0x0000000000000000Address+0x12
0x0000000000000000
wird geschrieben an Address+0x1A
0x00000094
wird geschrieben Address+0xE
0x0000Address+0x220x0000
wird geschrieben an Address+0x62
memcpy(Address+0xA6, Source, Source->AddressLength+0x08)
DerSourcememcpy definiert eine einzelne Transportadresse eines bestimmten Typs (zum Beispiel NetBIOS). Die Definition lautet wie folgt:
typedef struct _TA_ADDRESS {
USHORT AddressLength;;
USHORT AddressType; Info;
UCHAR-Address[1];;
} TA_ADDRESS, *PTA_ADDRESS;
Gibt die Anzahl der Bytes in einer Adresse des angegebenen AddressType an.
Gibt den Typ der Transportadresse an.
Gibt ein Array variabler Größe an, das die Transportadresse enthält.
In der folgenden Debugging-Sitzung enthältTA_ADDRESS
rax=0000014e1d110180 rbx=0000014e1d110180 rcx=0000014e1d110184
rdx=0000014e1ce86b10 rsi=0000014e1d110001 rdi=0000000545d7fa50
rip=00007ff843208074 rsp=0000000545d7f940 rbp=0000000545d7f980
r8=000000000000000c r9=0000000000000002 r10=0000000000000000
r11=0000000545d7f938 r12=0000000000000002 r13=0000000000001000
r14=0000014e1ce86b10 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
MQQM!CQmPacket::CQmPacket+0x89c:
00007ff8`43208074 e8a5780a00 call MQQM!memcpy (00007ff8`432af91e)
0:017> dc rcx
0000014e`1d110184 00010004 00000000 8620a8c0 00000000 ………. …..
Oben hat das ObjektTA_ADDRESS, eine Art von1. Die Umwandlung jedes Bytes in ein IPv4-Oktett ergibt die Adresse , das ist die IPv4-Quelladresse des Clients.
Dieses Szenario erlaubt das Schreiben von angreifergesteuerten Daten über eine Adresse zu einem kontrollierten Offset zur Paketallokation im Speicher. Dies ist zwar sehr restriktiv und möglicherweise unpraktisch, könnte aber theoretisch verwendet werden, um die in den Speicher geschriebenen Werte genau zu kontrollieren, indem mehrere Anfragen von unterschiedlichen Adressen mit abnehmenden Paketoffsets gestellt werden.
Aufgrund der Vielzahl von Einschränkungen bei der blinden Remote-Codeausführung wurden alternative Angriffsszenarien, wie z. B. Datenlecks, untersucht.
Ein Angriff, der in Frage kam, bestand darin, den Hinweis auf einen bestimmten Nachrichtenabschnitt zu beschädigen, um auf einen Speicher außerhalb der Grenzen zu verweisen, und später die Nachricht abzurufen, um den benachbarten Speicher zu lesen.
Allerdings wird zu Beginn jedes Abschnitts-Parsings die Position des aktuellen Abschnitts überprüft, sodass wir die Parsing-Logik nicht dazu bringen können, einen Datenabschnitt zu parsen, der außerhalb der Grenzen liegt.
Ein anderes mögliches Angriffsszenario besteht darin, den OnDiskExtensionHeader einer anderen Nachricht zu überschreiben, um den Empfänger der Nachricht über den Ursprung der empfangenen Nachricht zu täuschen. Ebenso ist es möglich, den Inhalt von Nachrichten zu überschreiben, die für Warteschlangen bestimmt sind, auf die der Angreifer keinen Zugriff hat. Um bestimmte Inhalte einer Nachricht zu überschreiben, müsste der Angreifer Informationen über die Nachricht besitzen, beispielsweise über deren Größe.
Es gibt einen optionalen Abschnitt namens SoapHeader, der anfällig für den Datenzugriff außerhalb des zulässigen Bereichs ist und das folgende Format hat:
SoapHeader-Paketformat
Es wurde festgestellt, dass der Speicher, der zum Speichern von MSMQ-Paketdaten verwendet wird, beim Freigeben des Puffers nicht ordnungsgemäß gelöscht wird. Dadurch führt das Senden eines MSMQ-Pakets, das kleiner ist als ein vorheriges MSMQ-Paket, dazu, dass das Speicherlayout die Daten des aktuellen Pakets gefolgt von Daten aus zuvor verarbeiteten MSMQ-Paketen enthält.
Es wurde entdeckt, dass
Die eingeschränkte Kontrolle über Schreibinhalte, wobei zusätzliche unkontrollierte Schreibvorgänge benachbarte Speicherbereiche beschädigten, sowie begrenzte Kenntnisse über das Nachrichtenlayout erwiesen sich als großes Hindernis bei der Ausbeutung.
Zum Zeitpunkt der Analyse wurden nur die Nutzerraum-Schwachstellen bei der anfänglichen Verarbeitung eines MSMQ-Nachrichtenpakets auf Ausnutzbarkeit geprüft. Die Analyse der Schwachstellen der Kernel-Variante könnte zusätzliche Ausbeutungsmöglichkeiten aufdecken. Zum Beispiel ist es möglich, dass das Einfügen eines fehlgeleiteten Headers ein Schreibprimitiv in der Kernel-Speicherzuordnung der Datei erzeugt. In einigen Fällen verhindern Kontrollen in der Benutzerraumverarbeitung, dass der Kernel einige Nachbearbeitungsoperationen durchführen kann.
Außerdem hat der Angreifer bei den Kernel-Varianten weniger direkte Kontrolle über den Inhalt der Nachrichten und arbeitet mit derselben Dateizuordnung wie der Benutzerbereich und nicht in einem Kernel-Pool (Heap). Auch Schutzmaßnahmen wie KASLR stellen Hindernisse dar, die für die Ausbeutung schwer zu überwinden sind.
Aufgrund der Implementierung des gepatchten Codes kann ein Remote-Client sicher feststellen, ob ein System das Update installiert hat. Dies kann durch das Senden einer MSMQ-Nachricht erfolgen, die eine Sicherheitslücke auslöst, aber keinen ausgehenden Zugriff verursacht, wodurch der Dienstprozess nicht zum Absturz gebracht wird. Wenn das HTTP-Flag im UserHeader der Nachricht gesetzt ist, wird ein SRMPEnvelopeHeader erwartet. Im Patch wird eine Überprüfung auf einen ganzzahligen Überlauf im Feld multipliziert mit 2 durchgeführt. Diese Länge kann so eingestellt werden, dass das Ergebnis der Multiplikation eine kleine Zahl ergibt, die der tatsächlichen Größe der Daten entspricht.
Dekompilierter Codeausschnitt, der die Überprüfung auf Integer-Überlauf bei SRMPEnvelopeHeader DataLength zeigt
Wenn das Ziel gepatcht wird, führt die Schwachstelle dazu, dass eine Ausnahme ausgelöst wird und der Server die Verarbeitung der Nachricht abbricht, sodass keine Antwort an den Client zurückgesendet wird. Wenn das Problem nicht behoben wird, verarbeitet der Server die Nachricht normal und sendet eine Antwort.
Aufgrund des Speicherplatzes der anfälligen Puffer scheint die Remotecodeausführung für einen Angreifer mit der Fähigkeit, Nachrichten an eine beliebige Warteschlange des Ziels zu senden, praktikabler. In diesem Szenario ist es möglich, den Heap so zu pflegen, dass ein angrenzender Heap zugewiesen wird. Die extrem eingeschränkte Kontrolle über Schreibinhalte stellt eine Herausforderung für die Remote-Ausbeutung dar. Aufgrund von Abschwächungen wie ASLR muss auch ein Informationsleck erhalten werden. Es ist möglich, dass ein einzelner Schreibvorgang einer Konstanten (0xC, 0x0
Letztendlich kommen wir zu dem Schluss, dass die Ausbeutung von QueueJumper aus der Ferne zwar nicht unmöglich ist, die zuvor genannten Anforderungen dies jedoch erschweren. Dieser Blogbeitrag zeigt nur die Oberfläche von einer sehr komplexen Nachrichtenspezifikation, einem Dienst und einem Protokoll. Weitere Recherchen zu den Schwachstellen sowohl im Benutzerbereich als auch bei den Kernel-Komponenten sind gerechtfertigt.