
Kernel-Exploit für CVE-2016-6187 (Lokale Privilegienerweiterung)
Kernel-Exploit für CVE-2016-6187 (Lokale Privilegienausweitung) (betroffene Versionen: < 4.6.5)
Der Exploit wurde gegen einen individuell kompilierten 4.6-Kernel + Buildroot entwickelt (kconfig folgt in Kürze)
und besiegt KASLR, SMEP, SMAP (KPTI für 4.6 nicht verfügbar)
Die ausgenutzte Schwachstelle ist ein Heap-basierter Single-Nullbyte-Overflow in einem der AppArmor-LSM-Hooks (setprocattr). Siehe https://nvd.nist.gov/vuln/detail/CVE-2016-6187
Erste Messungen deuten auf eine 94,44%ige Wahrscheinlichkeit hin, eine Root-Shell zu starten. In 1 von 18 Fällen wird der Exploit den Kernel zum Absturz bringen (oops). Weitere Arbeiten sind erforderlich, um den Kernel nach dem Erlangen von Root-Zugriff vollständig zu stabilisieren.
Wir missbrauchen den Nullbyte-Overflow, um das LSB eines Freelist-Zeigers in kmalloc-128 zu korrumpieren, sodass er effektiv auf ein bereits zugewiesenes Objekt zeigt. Danach geben wir dieses zugewiesene Objekt frei, was ein Double-Free-Szenario verursacht.
Jetzt können wir zwei überlappende Strukturen aus dem kmalloc-128-Cache zuweisen. Die erste Struktur ist ein Objekt, dessen Inhalt vom Userspace zurückgelesen werden kann. Dafür habe ich ip6_sf_socklist gewählt. Die zweite Struktur, die über ip6_sf_socklist zugewiesen wird, sollte Kernel-Zeiger enthalten - rfkill_data ist eine gute Wahl. Sie enthält einen Heap-Zeiger (leere rfkill_data.events-Liste) und einen globalen Datenzeiger auf rfkill_fds (rfkill_data.list.prev). Sobald rfkill_data über ip6_sf_socklist zugewiesen ist, können wir die Kernel-Zeiger durch den Aufruf von getsockopt(sock, IPPROTO_IPV6, MCAST_MSFILTER, gsf, &optlen) abrufen. Die Kernel-Textbasis kann dann aus rfkill_fds abgeleitet werden.
Dann verursachen wir ein zweites Double-Free-Szenario, aber diesmal missbrauchen wir den Verlinkungsprozess der Nachrichtenwarteschlange, um den Freelist-Zeiger zu überschreiben und den Allokator dazu zu bringen, uns einen Chunk aus kmalloc-96 zurückzugeben, obwohl wir eigentlich einen Chunk aus kmalloc-128 anfordern.
Dann können wir den Größenkonflikt ausnutzen, um in den Freelist-Zeiger eines kmalloc-96-Chunks überzulaufen, was uns die Möglichkeit gibt, beliebige Adressen zuzuweisen. In unserem Fall zielen wir auf die ptmx_fops-Struktur und überschreiben den Callback ptmx_fops.unlocked_ioctl mit einem Zeiger auf unser Stack-Pivot-Gadget.
Der Aufruf von ioctl auf /dev/ptmx löst das Pivot-Gadget aus und wir verlagern den Stack auf einen Fake-Stack in kmalloc-128, wo wir bereits unsere erste Stufe der ROP-Kette vorbereitet haben.
Da wir auf dem Fake-Stack in kmalloc-128 nur begrenzten Platz haben (wir wissen nicht, ob der nächste Chunk auf demselben slab liegt), besteht die Aufgabe der ersten ROP-Kette darin, die zweite ROP-Kette aus dem Userspace in den Kernel-Dmesg-Log-Puffer (__log_buf) zu kopieren und den Stack auf __log_buf zu verlagern.
Die zweite ROP-Kette versucht dann, den Kernel zu reparieren (Wiederherstellen von ptmx_fops, ...), bevor sie commit_creds(prepare_kernel_cred(NULL)) aufruft, um Privilegien zu erweitern.
Und schließlich verlässt sie den Kernelspace über iretq und wir kehren mit erhöhten Privilegien zu unserer Unterroutine execve("/bin/sh", 0, 0) zurück.
Unprivilegierte Benutzer müssen in der Lage sein, /dev/rfkill zumindest zu öffnen. Manche Distributionen erlauben das möglicherweise nicht. Ich habe Ubuntu und Fedora überprüft; beide erlauben unprivilegierten Benutzern das Öffnen von /dev/rfkill (obwohl Fedora SELinux anstelle von AppArmor verwendet).
Der folgende Abschnitt erklärt, wie die lokale Privilegienausweitung in qemu-x86_64 reproduziert werden kann.
Zuerst müssen Sie einen initrd- und einen bzImage-Kernel besorgen. Es gibt zwei Möglichkeiten:
Der einfachste und schnellste Weg. Sie finden alle erforderlichen Komponenten in prebuilt/.
Oder alternativ können Sie die Komponenten auch selbst bauen. Holen Sie sich einfach den 4.6-Kernel und verwenden Sie die bereitgestellte x86_64_vuln_kern_defconfig in config/, um das bzImage zu kompilieren.
Für den initrd könnten Sie beispielsweise buildroot verwenden. Stellen Sie nur sicher, dass Sie die korrekten Berechtigungen für /dev/rfkill in Ihrem init setzen
chmod 664 /dev/rfkill
Dies ist dasselbe wie in Ubuntu-16.04 und vielen anderen Distributionen. Vergessen Sie auch nicht, den Exploit zu kompilieren und in Ihren initrd zu legen
make
Sobald Sie die Komponenten erworben haben, booten Sie die anfällige Maschine
./boot.sh <path/to/bzImage> <path/to/rootfs.cpio>
und führen Sie den Exploit aus
./exploit
Möglicherweise müssen Sie den Exploit mehrmals ausführen, je nachdem, ob wir ein LSB auf Null gesetzt haben, das bereits Null war. Beachten Sie auch, dass immer noch eine geringe Wahrscheinlichkeit (vielleicht 10%-20%?) besteht, dass es nach dem Erlangen von Root-Zugriff zu einem Absturz kommt - ich arbeite daran.
Viel Spaß.
ptmx_fops reparieren, um die Stabilität zu erhöhenkmalloc-128-Freelist reparieren, um die Stabilität zu erhöhen