
Zwei Kernel-Schwachstellen in Razer Lycosa.sys (CWE-125 Speicherofflegung + CWE-121 Stack-Überlauf), verkettet zu lokaler Rechteausweitung. Materialien zur koordinierten Offenlegung, verifiziert unter Windows 11.
Entdeckt durch https://github.com/416rehman/DeepZero
Hersteller: Razer Inc.
Komponente: Lycosa.sys, der Razer-Lycosa-Tastaturfiltertreiber, x64
SHA-256: a120a6184ab16864e8a5f1dfd0cd178fca541de463b5cef946e18c34b9b6f716
Referenz des Melders: a120a6184ab16864
Status: noch nicht an den Hersteller gemeldet.
Dieses Verzeichnis meldet zwei verschiedene Defekte in derselben Routine desselben Treibers. Sie haben getrennte Ursachen und getrennte Korrekturen, daher hat jeder einen eigenen in sich geschlossenen Ordner und kann verfolgt und mit einer eigenen Kennung versehen werden:
| CVE | Defekt | Typ | Folge |
|---|---|---|---|
| CVE-01 | Die Ausgabelänge wird nicht gegen den Puffer geprüft, sodass der Treiber Kernel-Stack-Speicher zurückgibt | CWE-125 Out-of-Bounds-Read | Offenlegung von Kernel-Speicher, untergräbt die Adressraum-Layout-Randomisierung |
| CVE-02 | Die Eingabelänge wird nicht gegen den Puffer geprüft, sodass der Treiber seine eigene Rücksprungadresse überschreibt | CWE-121 Stack-Buffer-Overflow | Ausführung beliebigen Kernel-Codes |
Beide sind von jedem Konto aus erreichbar, das sich anmelden und ein Programm ausführen kann. Keine Administratorrechte, keine Erhöhung, kein besonderes Privileg. Beide wurden auf Windows 11 25H2 (Build 26200.8875) mit erzwungener Codeintegrität und deaktiviertem Testsigning bestätigt.
Abschnitt 3 beschreibt, was die beiden zusammen bewirken, was der Grund dafür ist, dass sie gleichzeitig gemeldet werden und warum der verkettete Proof of Concept in diesem Stammverzeichnis liegt.
Beide befinden sich im IRP_MJ_DEVICE_CONTROL-Handler bei RVA 0x1270, und beide wirken
auf denselben 0x400-Byte-Puffer auf dem Kernel-Stack. Der Prolog, gelesen aus dem
ausgelieferten Binary, legt die Geometrie für beide fest:
Lycosa+0x1270 48 89 54 24 10 mov [rsp+10h], rdx ; Irp
Lycosa+0x1275 48 89 4c 24 08 mov [rsp+8], rcx ; DeviceObject
Lycosa+0x127a 48 81 ec 98 04 00 00 sub rsp, 498h ; the frame
Lycosa+0x1291 ba 00 04 00 00 mov edx, 400h ; the buffer size
Lycosa+0x1296 48 8d 8c 24 80 00 00 00 lea rcx, [rsp+80h] ; the buffer
Ein 0x400-Byte-Puffer bei rsp+0x80, innerhalb eines 0x498-Byte-Frames, ohne gesicherte
nichtflüchtige Register. Vom Anfang des Puffers an gezählt:
0x000 .. 0x3FF the buffer, which both defects are supposed to stay inside
0x418 the return address of the dispatch routine
0x420 the saved DeviceObject argument
0x428 the saved Irp argument
0x418 ist 0x498 - 0x80. Die Offenlegung (CVE-01) liest über 0x3FF hinaus und gibt
zurück, was sie findet; der Overflow (CVE-02) schreibt über 0x3FF hinaus und ersetzt es.
DriverEntry erstellt das Gerät mit keinem Sicherheitsdeskriptor und veröffentlicht einen
symbolischen Link dafür, sodass es unter \\.\Lycosa erreichbar ist:
IoCreateDevice(param_1, 0x20, L"\\Device\\Lycosa", 0x22, 0, 0, &device);
IoCreateSymbolicLink(L"\\DosDevices\\Lycosa", L"\\Device\\Lycosa");
Jeder betroffene Steuercode dekodiert als FILE_DEVICE_UNKNOWN, METHOD_BUFFERED,
FILE_ANY_ACCESS. FILE_ANY_ACCESS bedeutet, dass kein bestimmtes Zugriffsrecht am
Handle gehalten werden muss, sodass der Sicherheitsdeskriptor des Geräteobjekts das einzige Tor ist, und
er gewährt allen Zugriff.
Alle Ergebnisse in diesen Berichten wurden von einem Standardbenutzerkonto erzeugt, dessen
einzige Gruppenmitgliedschaft die integrierte Gruppe Users ist. Das Konto hatte keine
Administratorrechte, war nicht erhöht und besaß keine über die
Standardwerte hinausgehenden Privilegien.
Der Treiber lädt auch auf Maschinen, an denen nie Razer-Hardware angeschlossen war, weil das Paket gültig katalog-signiert ist. Das ist das Muster, das bei Bring-Your-Own-Vulnerable-Driver-Angriffen verwendet wird.
Getrennt gemeldet, weil es getrennte Defekte sind, aber ein Hersteller, der sie triagiert, sollte wissen, dass jeder den anderen verschlimmert.
Modernes Windows lädt den Kernel an einer randomisierten Adresse. Ein Angreifer, der eine Rücksprungadresse überschreiben kann, muss immer noch wissen, womit er sie überschreiben soll, und das ist normalerweise das Hindernis. Dieser Treiber beantwortet beide Fragen von selbst:
CVE-01 beseitigt die Randomisierung. Die Offenlegung gibt die eigene Rücksprungadresse der
Dispatch-Routine zurück, eine Codeadresse innerhalb von ntoskrnl.exe. Subtrahiert man
ihren bekannten Offset innerhalb des Images, erhält man die Basis, an der der Kernel geladen ist,
und von dort ist jede Adresse innerhalb des Kernels bekannt. Das kostet nichts und
stört nichts.
CVE-01 liefert außerdem den Wert, den CVE-02 benötigt, um keinen Fehler auszulösen. Wie
in CVE-02 Abschnitt 4.4 beschrieben,
lädt der Treiber den Irp aus Offset 0x428 auf seinem Weg nach draußen neu und schreibt
durch ihn hindurch. Ein naiver Overflow, der die Rücksprungadresse erreicht, zerstört auch diesen
Zeiger und löst einen Fehler aus, bevor die Routine zurückkehrt. Der zuverlässige Exploit stoppt
stattdessen die Kopie genau bei 0x428 und lässt den aktiven Irp der aktuellen
Anfrage an Ort und Stelle, sodass der Treiber normal abschließt.
CVE-02 leitet dann die Ausführung um, wobei die Kernel-Basis bereits bekannt ist.
Von einem unprivilegierten Konto aus liest der verkettete Proof of Concept den Frame, berechnet die Kernel-Basis und die eigene Kernel-Adresse des Puffers und sendet eine Return-Oriented-Chain:
step 1, read what is above the buffer on the kernel stack:
+0x418 return address 0xFFFFF807D565CABB
+0x498 frame pointer 0xFFFFFD042D313750 (read twice, must match)
step 2, turn those into the two addresses the payload needs:
kernel base = 0xFFFFF807D565CABB - 0x25CABB = 0xFFFFF807D5400000
buffer on stack = 0xFFFFFD042D313750 - 0x500 = 0xFFFFFD042D313250
step 4, overflow with a chain that:
pivots the stack onto the buffer, calls nt!ZwCreateFile, and
resumes nt!IopfCallDriver+0x5b
sending 0x428 bytes
call returned: accepted=true error=0
PROOF: C:\Windows\System32\dz_lycosa_kernel_exec.txt now exists.
Dies ist die vollständige Kette, Ende-zu-Ende verifiziert. Das unprivilegierte Konto erstellte
eine Datei unter C:\Windows\System32, einem Verzeichnis, auf das ihm sonst der Schreibzugriff
verweigert wird, indem es nt!ZwCreateFile im Kernel-Modus ausführte. accepted=true bedeutet,
dass der Systemaufruf normal zurückkehrte: Die Kette setzt an der exakten Adresse fort, an die der Treiber
zurückkehren wollte (nt!IopfCallDriver+0x5b, was add rsp,0x38 ; ret ist),
sodass der Thread beendet wird und die Maschine weiterläuft. Die erstellte Datei wurde
unabhängig von einer Administrator-Shell aus bestätigt. Das vollständige Transkript ist in
logs/exec_create_file.log, und die Methode ist in
METHODOLOGY.md.
Die praktische Lesart ist, dass dieser eine Treiber jedem Benutzer der Maschine beide Hälften dessen liefert, was normalerweise benötigt wird, um einen Speichersicherheitsdefekt in Kernel-Codeausführung zu verwandeln: die Adressoffenlegung, die die Randomisierung beseitigt, und die Control-Flow-Übernahme, die sie nutzt. Zusammen wurde gezeigt, dass sie eine konkrete privilegierte Aktion ergeben, wobei die Maschine weiterläuft.
Die beiden Korrekturen sind unabhängig und beide klein, vollständig in jedem Bericht angegeben:
OutputBufferLength begrenzen und IoStatus.Information auf das setzen, was tatsächlich
erzeugt wurde.InputBufferLength begrenzen.Beide Berichte empfehlen außerdem, das Steuergerät mit
IoCreateDeviceSecure und einer SDDL-Zeichenfolge zu erstellen, die es auf Administratoren und das
System beschränkt. Das allein würde keinen der beiden Defekte beheben, aber es würde die
unprivilegierte Erreichbarkeit beseitigen, die beiden ihre Schwere verleiht.
Vor dem Verfassen geprüft, weil ein doppelter Bericht die Zeit eines Herstellers verschwendet:
https://aka.ms/VulnerableDriverBlockList und durchsucht über ihre 1.713 Deny-
Regeln. Diese Datei erscheint nicht. Der einzige Razer-Treiber auf dieser Liste ist
Rzpnk.sys, eine andere Komponente.Wir glauben, dass beide Defekte bisher ungemeldet sind, und würden eine Korrektur begrüßen.
Mehrere andere Treiber, die im selben Paketverzeichnis ausgeliefert werden, teilen die allgemeine Form dieses Treibers und werden separat untersucht. Nichts hier ist eine Aussage über sie.
pnputil /add-driver Flter2K.inf /install
sc create lycosa_test type= kernel binPath= C:\path\to\Lycosa.sys start= demand
sc start lycosa_test
Jeder Defekt hat seinen eigenen zweckgebundenen Proof of Concept in seinem Ordner, und dieser Stamm enthält den verketteten, der sie kombiniert:
# CVE-01, reads only, safe to run anywhere, quickest confirmation of the report
rustc -O CVE-01-kernel-memory-disclosure/poc/lycosa_disclosure.rs -o disc.exe
disc.exe
# CVE-02, stops the machine by design
rustc -O CVE-02-kernel-stack-overflow/poc/lycosa_overflow.rs -o ovf.exe
ovf.exe --yes-crash-this-machine
# the chain: CVE-01 + CVE-02 into a file created in System32, machine left running
rustc -O poc/lycosa_chain.rs -o chain.exe
chain.exe --exec # default target under System32
chain.exe --exec C:\Users\Public\proof.txt # or any path you choose
Führen Sie alles von einem Standardbenutzerkonto aus. Der verkettete PoC nennt die beiden
Treiberkonstanten, von denen er abhängt (FRAME und BUF_AT), am Anfang seines Quellcodes,
sodass er durch Ändern dieser beiden Zahlen auf einen anderen Treiber-Build gerichtet werden kann.
Die Kernel-Offsets, die sein --exec-Modus verwendet, sind spezifisch für einen Windows-Build; das
Programm prüft die abgeleitete Kernel-Basis zur Laufzeit und sein --calibrate-Modus
meldet den einen Wert, der sich zwischen Builds ändert.
README.md this overview and the chaining analysis
METHODOLOGY.md how both were found and confirmed, in order
poc/lycosa_chain.rs the CHAINED proof of concept (both defects)
evidence/ the binary, its package, decompiled sources, dumps
logs/exec_create_file.log transcript of the chained run in section 3
CVE-01-kernel-memory-disclosure/ standalone disclosure for the out-of-bounds read
README.md, poc/lycosa_disclosure.rs, evidence/, logs/
CVE-02-kernel-stack-overflow/ standalone disclosure for the stack overflow
README.md, poc/lycosa_overflow.rs, evidence/, logs/