
Dies ist ein Exploit für CVE-2017-7047, funktioniert auf 10.3.2 und darunter.
triple_fetch - ianbeer [https://bugs.chromium.org/p/project-zero/issues/detail?id=1247]
Dies ist ein Exploit für CVE-2017-7047, einen Logikfehler in libxpc, der es bösartigen Nachrichtensendern erlaubte, xpc_data-Objekte zu senden, die von Shared Memory unterstützt wurden. Konsumenten von XPC-Nachrichten schienen nicht zu erwarten, dass die zugrunde liegenden Puffer von xpc_data-Objekten vom Sender modifiziert werden konnten, während sie vom Empfänger verarbeitet wurden.
Dieses Projekt nutzt CVE-2017-7047 aus, um einen Remote-lldb-Debugserver-Stub als Proof of Concept zu bauen, der in der Lage ist, sich an alle Userspace-Prozesse auf iOS anzuhängen und deren Remote-Debugging zu ermöglichen.
Dies ist ein allgemeiner Überblick über den Exploit; eine ausführliche Dokumentation könnte zu einem späteren Zeitpunkt folgen. Weitere Details findest du vorerst im Code :)
Teil I
Der Exploit zielt auf NSXPC, eine Objective-C-Implementierung von Remote Procedure Calls, die von vielen iOS-Diensten verwendet wird (1). Eine NSXPC-Nachricht besteht aus einem bplist16-serialisierten Objekt innerhalb eines xpc-serialisierten xpc_data-Objekts innerhalb einer Mach-Nachricht.
Unter anderem enthält das bplist16-Objekt einen Objective-C-Typcodierungs-String (2), der von der Funktion ___NSMS1 in CoreFoundation geparst wird. Diese Funktion erwartet nicht, dass sich der Inhalt des von ihr geparsten Strings ändert, und dieser Exploit nutzt das aus, um eine Heap-Overflow-Primitive zu konstruieren, indem er ausnutzt, dass ein bestimmter Teil des Strings dreimal aus dem Speicher abgerufen wird. Durch Umschalten zwischen drei verschiedenen, sorgfältig gewählten Werten können wir aus einer gewählten Heap-Allokationsgröße mit beliebigen Bytes überlaufen.
minibplist16.c enthält eine minimale Implementierung der bplist-Serialisierung und eine Diskussion darüber, wie sie funktioniert.
Die äußere XPC-Nachricht enthält das Heap-Grooming. Sie verwendet eine benutzerdefinierte Implementierung des XPC-Serialisierungsprotokolls, um den Heap zu groomen, indem XPC-Wörterbücher mit kollidierenden Schlüsseln erstellt werden, um Allokations- und Free-Primitives aufzubauen. Die äußere XPC-Nachricht enthält außerdem ein Heap-Spray (unter Verwendung mehrerer Kopien eines Shared-Memory-Objekts, um den Speicherverbrauch niedrig zu halten) und ein Mach-Port-Send-Right-Name-Spray.
Der Overflow zeigt den isa-Klassenzeiger eines Objective-C-Objekts auf ein heap-gespraytes Fake-Objekt, sodass bei einem Methodenaufruf auf dieses Fake-Objekt der Stack auf einen kleinen ROP-Stack umgelenkt wird. Der ROP probiert die gesprayten Mach-Port-Send-Right-Namen per Brute-Force durch, indem er versucht, das Send Right des Ziels auf seinen eigenen Task-Port an jeden der Kandidaten-Send-Right-Namen zu senden. Der Exploit lauscht auf allen gesprayten Ports, und wenn der Exploit erfolgreich ist, empfängt er ein Send Right auf den Task-Port des Ziels, woraufhin er die volle Kontrolle über den Ziel-Task hat.
Zwischenspiel
Der Exploit zielt auf den Dienst com.apple.CoreAuthentication.daemon, der vom coreauthd-Daemon gehostet wird und als Root läuft. Dieser Dienst ist aus der App-Sandbox erreichbar. Ein wenig Experimentieren, nachdem ich den Exploit zunächst zum Laufen gebracht hatte, zeigte, dass die processor_set_tasks-API aus dem Kontext von coreauthd in der Lage ist, Send Rights auf die Task-Ports aller auf dem Gerät laufenden Userspace-Prozesse zu erhalten. Dies ist seit mindestens 2012 allgemein bekannt, und die Geschichte wird von dem prominenten iOS-Internals-Forscher Jonathan Levin auf seiner Website ausführlich behandelt (3). Der Code, den Levin 2015 hochgeladen hat, funktioniert heute noch – er benötigt kein gejailbreaktes Gerät, sondern nur Root auf einem Stock-Gerät.
Teil II
Das Hauptziel des Debuggers, den ich mit diesem Exploit bauen wollte, war es, sich an einen beliebigen Prozess anhängen, Breakpoints setzen und bei deren Auslösung den Register- und Speicherzustand inspizieren und verändern zu können. Anstatt das gdb- oder lldb-Remote-Protokoll von Grund auf neu zu implementieren, entschied ich mich, die erforderlichen Änderungen am lldb-Debugserver-Projekt vorzunehmen und dann den Exploit zu verwenden, um es auszuführen.
Anstatt Software-Breakpoints zu verwenden, die entweder das Deaktivieren oder Umgehen der Codesignierung erfordern, wird der Debugserver so gepatcht, dass er ausschließlich Hardware-Breakpoints verwendet. ARM64 verfügt über 16 Hardware-Breakpoint-Register, was bedeutet, dass maximal 16 aktive Breakpoints möglich sind.
Prototyp-Unterstützung für ARM-Hardware-Breakpoints existierte zwar im lldb-Debugserver-Code, aber es bedurfte einiger Bastelei, um sie zum Laufen zu bringen. Beispielsweise musste ich Code hinzufügen, der den pthread_introspection_hook-Funktionszeiger im Debugee so patcht, dass er immer abstürzt, damit ich die Erstellung neuer Threads erkennen, den Hardware-Breakpoint-Zustand in neu erstellte Threads propagieren und so fortfahren kann, als wäre es nie abgestürzt.
Ich habe außerdem den Attach- und Continue-Code gepatcht, um den Task direkt über den Task-Port zu suspendieren und fortzusetzen, anstatt ptrace und Signale zu verwenden.
Build-Tipps
Alles sollte auf allen iOS-Geräten mit 10.0 bis einschließlich 10.3.2 funktionieren. Getestet habe ich auf:
iPhone 7 + 10.3.2 iPod Touch + 10.1.1 iPad Mini 2 + 10.2
Ich habe ein vorgebautes Debugserver-Binary beigelegt, dessen Verwendung ich empfehle, aber der Patch für den lldb-Debugserver ist auch in debugserver.diff enthalten.
Das Bauen des Debugservers ist nicht allzu schwierig. Ich bin von den folgenden Git-Revisionen ausgegangen: lldb: 0db640c4cd1ec4e4c2580336fa5f53be029c5bc7 llvm: ec48fd127774a4b67c72ea7c3057b5c964375e77 clang: b6e778e0bfa2fc32f8821c6b33762f5cb6724659
Wende den mitgelieferten debugserver.diff an.
Für den Build benötigst du (aktuelles) CMake und Ninja; du bekommst sie aus dem Quellcode oder als Binaries von deinem bevorzugten mac-Paketmanager.
(4) enthält eine Anleitung zum Einrichten eines normalen LLVM-Builds unter macOS, die hilfreich sein könnte.
Du musst eine Reihe von Header-Dateien in dein iOS-SDK verlinken, mindestens:
xpc/ launchd.h libproc.h sys/proc_info.h sys/kern_control.h net/route.h mach/mach_vm.h mach/shared_region.h sys/ptrace.h crt_externs.h
Die folgende CMake-Beschwörung sollte dir alle Hinweise geben, die du brauchst:
cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64" -DCMAKE_TOOLCHAIN_FILE=../cmake/platforms/iOS.cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off ../
ninja debugserver
Danach musst du das Debugserver-Binary signieren oder fakesignen und das im mitgelieferten xcode-Projekt ersetzen.
Codesigning
Das Exploit-Projekt installiert standardmäßig eine verbesserte Version des mach_portal-amfid-Hooks (diesmal mit funktionierender Unterstützung für Fat Files und ohne fest verdrahtete Offsets :) )
Wenn du nur Sachen debuggen willst, solltest du das Debugserver-Binary mit deinem eigenen Zertifikat signieren und den amfid-Hook deaktivieren können.
Wenn du den amfid-Hook verwendest, beachte, dass die App, in der er läuft, weiterhin den Limits für die Codeausführung im Hintergrund unterliegt. Die App fordert zwar über beginBackgroundTaskWithName mehr Zeit an.
Verwendung:
Verbinde deinen Host und das Ziel-iDevice mit demselben WLAN-Netzwerk und notiere die IP-Adresse des iDevices.
Baue und starte die Exploit-App. Ich empfehle, dies in xcode zu tun, aber sie funktioniert auch eigenständig.
Warte ein wenig. Wenn es nach ein paar Minuten nicht funktioniert, starte das Gerät hart neu, warte ein wenig und versuche es erneut.
Wenn es funktioniert, sollte es „patched debugserver listening on port 1234“ ausgeben.
Wenn du auf die Schaltfläche „get process listing“ klickst, solltest du die Ausgabe von ps sehen.
(Die Ausgabe ist leichter zu sehen, wenn du xcode verwendest, aber der Exploit zeigt die Ausgabe ebenfalls.)
Suche den Zielprozess, den du debuggen möchtest, und notiere seine PID.
Starte auf dem Host lldb von der Kommandozeile aus: $ lldb (lldb)
Setze die Plattform auf ios remote: (lldb) platform select remote-ios
Verbinde dich mit dem Debugserver-Stub: (lldb) process connect connect://192.168.0.172:1234
(wobei 192.168.0.172 die IP-Adresse des iDevices ist)
Hänge dich an den Prozess an, der dich interessiert: (lldb) attach 55
... warte ein wenig, der Debugserver läuft im Verbose-Modus ...
Process 55 stopped
Executable module set to "/usr/libexec/backboardd".
Du bist angehängt :)
Setze einen Breakpoint: (lldb) break set --name malloc Breakpoint 1: 4 locations.
Weiter:
(lldb) c Process 55 resuming Process 55 stopped
malloc libsystem_malloc.dylibmalloc:
-> 0x1936161e0 <+0>: stp x20, x19, [sp, #-0x20]!
0x1936161e4 <+4>: stp x29, x30, [sp, #0x10]
0x1936161e8 <+8>: add x29, sp, #0x10 ; =0x10Rufe einen Backtrace ab:
(lldb) bt
malloc frame #1: 0x0000000100099648 backboardd_mh_execute_header + 71240
frame #2: 0x00000001945bf218 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56 frame #3: 0x00000001945be9cc CoreFoundation__CFRunLoopDoSource1 + 436
frame #4: 0x00000001945bc4b0 CoreFoundation__CFRunLoopRun + 1840 frame #5: 0x00000001944ea2b8 CoreFoundationCFRunLoopRunSpecific + 444
frame #6: 0x0000000194537b44 CoreFoundationCFRunLoopRun + 112 frame #7: 0x00000001000a5ba8 backboardd_mh_execute_header + 121768
frame #8: 0x00000001000a5bec backboardd_mh_execute_header + 121836 frame #9: 0x00000001936a5850 libsystem_pthread.dylib_pthread_body + 240
frame #10: 0x00000001936a5760 libsystem_pthread.dylib_pthread_start + 284 frame #11: 0x00000001936a2d94 libsystem_pthread.dylibthread_start + 4Fehlerbehebung:
Installiere die neueste Version von XCode (entwickelt und getestet mit 8.3.3). Wenn die lldb-Verbindung fehlschlägt, stelle sicher, dass das SDK für die Ziel-iOS-Version installiert ist.
Einschränkungen:
Ich hoffe, das zu beheben, bin aber im Moment sehr beschäftigt, sorry!
Ausführen anderer PoCs:
Wenn du ein Binary in den pocs-Ordner dieses Projekts legst, kannst du den Exploit dazu bringen, es auszuführen, indem du es in der UI auf dem Gerät auswählst und auf „exec bundle binary“ klickst.
Es läuft weiterhin in der App-Sandbox, aber wenn die App ein Symbol namens privileged_task_port hat, erhält es ein Send Right auf den Task-Port von launchd. Der Ordner triple_fetch_sdk enthält ein Beispielprojekt, das zeigt, wie du dies nutzen kannst, um PoCs zu bauen, zum Beispiel um Verhalten in interessanten Prozessen auszulösen, die du dann mit dem Debugserver debuggen kannst.
Er enthält außerdem die Remote-Call/Ports/Files/Memory-APIs, mit denen du einfach Funktionen in anderen Prozessen aufrufen und Dateideskriptoren, Mach-Ports und Speicher herumverschieben kannst.
(1) [https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html] (2) [https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html] (3) [http://newosxbook.com/articles/PST2.html] (4) [https://gist.github.com/thlorenz/a068c202f2487ec13809]
Dieses Projekt enthält Code (debugserver.diff) und ein Binary (debugserver), die auf lldb basieren und der folgenden Lizenz unterliegen:
University of Illinois/NCSA Open Source License
Copyright (c) 2010 Apple Inc. All rights reserved.
Developed by:
LLDB Team
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
Neither the names of the LLDB Team, copyright holders, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.