VOUS AVEZ OBTENU UN TROPHÉE - PS4 JAILBREAKÉ EXPLOITATION D'UNE VULNÉRABILITÉ WEBKIT SUR LA PLAYSTATION 4 - SSTIC

La page est créée Jacqueline Martins
 
CONTINUER À LIRE
VOUS AVEZ OBTENU UN TROPHÉE - PS4 JAILBREAKÉ EXPLOITATION D'UNE VULNÉRABILITÉ WEBKIT SUR LA PLAYSTATION 4 - SSTIC
Vous avez obtenu un trophée - PS4 jailbreaké
            Exploitation d’une vulnérabilité WebKit sur la PlayStation 4

2 Juin 2021

Synacktiv

Quentin Meffre   Mehdi Talbi
VOUS AVEZ OBTENU UN TROPHÉE - PS4 JAILBREAKÉ EXPLOITATION D'UNE VULNÉRABILITÉ WEBKIT SUR LA PLAYSTATION 4 - SSTIC
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Qui sommes-nous ?

               Mehdi Talbi
              @abu_y0ussef                          Quentin Meffre
                                                     @0xdagger
     Chercheur en sécurité @Synacktiv
     Recherche académique (dans une vie   Chercheur en sécurité @Synacktiv
     antérieure)                          Recherche de vulnérabilités &
     Recherche de vulnérabilités &        exploitation
     exploitation

                                                                             3/48
Introduction

   Motivation
        Communauté active sur le hacking de consoles de jeux
        … Mais très peu d’exploits publics
        À quel point est difficile l’exploitation de vulnérabilités sur la PS4 ?

   Objectif
        Exploitation pas-à-pas d’une vulnérabilité 0-day dans WebKit sur la PS4

                                                                                   4/48
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Surface d’attaque

                                 Browser    Gamesaves

                                                Userland

                    USB

                    WIFI   BLUETOOTH
                                           FreeBSD Kernel

                                                            6/48
Chaine d’exploitation

                                             Webkit
                                             Exploit

                                             Kernel
                                             Exploit

   Attaque du navigateur
        Navigateur basé sur WebKit
        Sandbox
        Pas de JIT
        Absence de certaines protections
             Gigacage
             Randomisation des StructureID
        ASLR : partiel ? Faible ?
        Absence de capacité de débogage

                                                       7/48
Exploits WebKit

   CVE-2018-4386
       Identifié par Lokihardt (de Projet Zero)
       Exploité par @Fire30_
       Dernier exploit public en date (“bad-hoist”)
       Primitive de lecture/écriture arbitraire
       Firmwares 6.00-6.72

   CVE-2018-4441
       Également identifié par Lokihardt
       Exploité par @SpecterDev
       Primitive de lecture/écriture arbitraire
       Firmwares 6.00-6.20

   Autres exploits …
       Pour les firmwares plus anciens (< 6.xx)
       Exploits de @qwertyoruiopz, @SpecterDev, @CTurt, …

                                                            8/48
Exploits Kernel

   CVE-2020-9892
        Identifié par @theflow0
        Double Free dans la pile IPv6
        Firmwares
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Allocateurs WebKit

   Plusieurs allocateurs
        FastMalloc : allocateur standard
        IsoHeap : utilisé par le moteur DOM
             Tri des allocations en fonction du type
        GC (Garbage Collector) : utilisé par le moteur JavaScript
        IsoSubspace : utilisé par le moteur JavaScript
             Trie des allocations en fonction de leur taille
        GigaCage : protections contre les lectures/écritures OOB sur certains objets

                                                                                       11/48
Allocateur standard

   Présentation
       Heap constitué de chunks
       Chunk divisé en pages (4 kB)
       Page subdivisée en lignes (256 octets)
       Ligne : dessert des allocations d’objets de mêmes tailles

                                                                   Obj N

                                                       Line N

                                                                   Obj 2
                                     Page N                        Obj 1

                  Chunk N                              Line 2

                                                       Line 1

                    ...

                                     Page 2

                  Chunk 1
                                     Page 1

                                                                           12/48
Allocation (1/2)

   Allocations via le chemin rapide (fast path)
        Allocateur de type “bump-pointer”

   --m_remaining;
   char* result = m_ptr;
   m_ptr += m_size;
   return result;

   Allocations via le chemin lent (slow path)
        Réapprovisionnement de l’allocateur
          1 À partir du cache BumpRangeCache (fast path)
           2   À partir de l’allocation d’une nouvelle page (slow path)

                                                                          13/48
Allocation (2/2)

   Réapprovisionnement de l’allocateur

                                                             Free Line

                                                                ...             BumpRangeCache

     Allocation d’une nouvelle page
        1 Depuis le cache CacheLine
                                                             Free Line
        2   Depuis le dernier chunk alloué
     Alimenter l’allocateur avec les
                                                  Line
     lignes libres & contiguës
     Alimenter le cache avec les lignes                      Free Line
     libres restantes                                                              BumpAllocator

                                                             Free Line

                                                                         released obj
                                             allocated obj
                                                                         released obj

                                                              Page

                                                                                                   14/48
Déallocation

   Déallocation
       Les objets libérés ne sont pas immédiatement mis à disposition → placés dans un
       vecteur dédié (m_objectLog).
       Traitement des objets du vecteur m_objectLog :
               Lorsqu’il atteint sa capacité maximale (512)
               Lors du réapprovisionnement de l’allocateur
       Chunks / Pages / Lignes disposent d’un compteur de référence (refcount)
       Chunks / Pages / Lignes libérés SI refcount == 0

                                                                                         15/48
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Présentation

   Vulnérabilité
        Présente dans le moteur DOM de WebKit
        Trouvée via fuzzing
        Impacte tous les firmwares < 8.00 de la PS4
             … et de la PS Vita aussi
        Remontée à Sony via leur programme de Bug Bounty (2500$)
        Corrigée le 11 Sept. 2020

                                                                   17/48
Code vulnérable
   Code vulnérable
         Vulnérabilité présente dans la méthode
         WebCore::ValidationMessage::buildBubbleTree
         La fonction updateLayout met à jour la disposition de la page :
               Exécution de callbacks JS enregistrées par l’utilisateur
               Possibilité de destruction de l’instance ValidationMessage → UAF
         Erreur dans la définition d’un WeakPtr

   void ValidationMessage::buildBubbleTree()
   {
       /* ... */

       auto weakElement = makeWeakPtr(*m_element);

       document.updateLayout(); // [1] call user registered JS events

       if (!weakElement || !m_element->renderer())
           return;

       adjustBubblePosition(m_element->renderer()->absoluteBoundingBoxRect(), m_bubble.get());

       /* ... */
   }

                                                                                                 18/48
Le bon et le mauvais correctif (1/2)

   Le mauvais correctif

   void ValidationMessage::buildBubbleTree()
   {
       /* ... */
   +
   + auto weakElement = makeWeakPtr(*m_element);
   +
       document.updateLayout();

   +   if (!weakElement || !m_element->renderer())
   +       return;

       adjustBubblePosition(m_element->renderer()->absoluteBoundingBoxRect(), m_bubble.get());
       /* ... */
   }

                                                                                                 19/48
Le bon et le mauvais correctif (2/2)
   Le bon correctif
         Ne pas permettre des mises à jour de la disposition de la page dans
         buildBubbleTree

   void ValidationMessage::buildBubbleTree()
   {
       /* ... */
   -
   - auto weakElement = makeWeakPtr(*m_element);
   -
   - document.updateLayout();
   -
   - if (!weakElement || !m_element->renderer())
   -       return;
   -
   - adjustBubblePosition(m_element->renderer()->absoluteBoundingBoxRect(), m_bubble.get());

       /* ... */

   +   if (!document.view())
   +       return;
   +   document.view()->queuePostLayoutCallback([weakThis = makeWeakPtr(*this)] {
   +       if (!weakThis)
   +           return;
   +       weakThis->adjustBubblePosition();
   +   });
   }

                                                                                               20/48
Chemin vulnérable

            onfocus

           html input     reportValidity

                               Instantiate
                               ValidationMessage

                                                        JS Callback
                                            Layout
                                            Update
                 0s     buildBubbleTree                      Free
                                                     ValidationMessage

                            UAF
                            ValidationMessage

                 5s     deleteBubbleTree

                              Destroy
                              ValidationMessage

                                                                         21/48
Tentatives de déclenchement du bug (1/2)

   Tentative initiale
     1     Enregistrer un événement JS (e.g. onfocus) sur un champ de texte HTML
     2     Instancier l’objet ValidationMessage
                → Déclenchement d’un minuteur pour exécuter buildBubbleTree
                → Exécution de la callback JS
     3     Détruire l’instance ValidationMessage dans la callback JS
     4     Pas de crashs !!
                reportValidity positionne le focus sur l’élément HTML cible
                   Exécution prématurée de la callbask JS

                               PS4 exploit

                                         https://pwnme.org/

                         onfocus input                             onload

                                                                  input.setCustomValidity("pwn");
                                                                  input.reportValidity();
   document.body.delete(input) ;                                  input.autocus = true;
                                                                     ValidationMessage Instanciation
         ValidationMessage destruction

                                                                                                       22/48
Tentatives de déclenchement du bug (2/2)

   Solution
     1   Enregistrer un événement JS handler1 sur un champ HTML input1
     2   Instancier l’objet ValidationMessage (sur input1)
              Le focus est positionné sur input1 → handler1 est exécuté
              handler1 positionne le focus ailleurs (input2)
     3   Définir un nouveau handler handler2 sur input1
     4   Détruire l’instance ValidationMessage dans le handler2

                                   PS4 exploit

                                            https://pwnme.org/

                           onfocus (1) input1    onfocus (2)                           onload

                                       input2
                                                                                        input1.setCustomValidity("pwn");
                                                                                        input1.reportValidity();
                                                                                        input1.setAttribute("onfocus","handle2()");
                                                                                        input1.autocus = true;
         function handle1() {                      function handle2() {                         ValidationMessage Instanciation
           input2.focus();                           document.body.delete(input) ;
         }                                         }
                                                       ValidationMessage Destruction

                                                                                                                                      23/48
Crash !

          24/48
Débogage

  Problème
       Absence de capacité de débogage

  Solution 1 - Installation d’un environnement similaire
       Installer un FreeBSD
       Compiler les sources WebKit récupérées depuis doc.dl.playstation.net
       → Utile Mais un exploit fonctionnel sur notre environnement n’implique pas un portage
       assuré sur la PS4

  Solution 2 - Débogage d’une 0-day avec une 1-day
       Utilier l’exploit “bad-hoist”
             (+) Primitives de lecture/écriture
             (+) Primitives addrof/fakeobj
             (-) Fonctionne uniquement sur les firmwares 6.xx
             (-) Peut influencer notre stratégie de shaping de la mémoire
             (-) Peu fiable

                                                                                               25/48
Anatomie de l’objet vulnérable

   Objet ValidationMessage
        Instancié par reportValidity() (via fastMalloc())
        Accédé par buildBubbleTree()
        Détruit par deleteBubbleTree()

                          m_messageBody

                         m_messageHeading

      HTMLElement             m_bubble

                              m_timer

                             m_message
                                                            instantiated after layout update
      HTMLElement            m_element
                                                            accessed after layout update

                         ValidationMessage

                                                                                               26/48
Survivre au crash initial (1/3)

   Situation après destruction de l’objet vulnérable
        Déréférencement d’un pointeur NULL (m_bubble) → crash du navigateur
        Situation : Inconfortable

                               m_messageBody

                              m_messageHeading

                                  m_bubble

                                   m_timer

                                 m_message        Set to NULL

                                 m_element        Deleted. Reference not cleared

                              ValidationMessage

   Exploitabilité
        Nécessite
           1   Un leak Mémoire, ou bien
           2   … un bypass de l’ASLR

                                                                                   27/48
Survivre au crash initial (2/3)
   Bypass de l’ASLR
        Heap Spray → adresses prédictibles
        Nécessite une connaissance préalable du mapping mémoire

   Survivre au crash
        Allocation de plusieurs milliers objets HTMLElement (e.g. HTMLTextAreaElement)
        UAF de l’objet ValidationMessage

                                                  HTMLTextAreaElement

                                                  HTMLTextAreaElement

                             m_messageBody

                            m_messageHeading
                                                          ...
                                m_bubble

                                  m_timer

                               m_message

                               m_element          HTMLTextAreaElement

                            ValidationMessage

                                                                                         28/48
Survivre au crash initial (3/3)

   Épilogue de la fonction vulnérable

   void ValidationMessage::deleteBubbleTree()
   {
       if (m_bubble) {
           m_messageHeading = nullptr;
           m_messageBody = nullptr;
           m_element->userAgentShadowRoot()->removeChild(*m_bubble);
           m_bubble = nullptr;
       }
       m_message = String();
   }

   Ré-évaluation de la situation
         ValidationMessage de nouveau détruit
         Surcharge de l’opérateur “=”
              Affectation de nullptr sur un objet “refcounté” → décrément du compteur de référence
         Décrément d’un compteur de références sur plusieurs objets contrôlés
         UAF → Décrément arbitraire
         Exploitable

                                                                                                     29/48
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Réutiliser l’objet cible (1/3)
    Contrôler le tas
      1   Allouer N/2 d’objets dit O
               sizeof(O) == sizeof(ValidationMessage)
      2   Instancier un objet ValidationMessage
      3   Allouer N/2 d’objets dit O

                                                More Obj. O
                                                    ...

                                                  Obj. O
                                                  Obj. O
                                                  Obj. O
                                                  Obj. O
                                      Line

                                             ValidationMessage
                                                  Obj. O
                                                  Obj. O
                                                  Obj. O
                                                  Obj. O

                                                More Obj. O
                                                    ...

                                                                 31/48
Réutiliser l’objet cible (2/3)
   Contrôler le tas
      1   Libérer les objets dit O se trouvant autour de l’objet alloué ValidationMessage
      2   Libérer l’objet ValidationMessage
               La ligne associée est libérée
               La page associée peut être ajoutée dans le cache

                                                       ...

                                            Line

                                                     Target

                                                       ...

                                                                                            32/48
Réutiliser l’objet cible (3/3)
   Contrôler le tas
        Allouer de nouveaux objets pour réutiliser l’objet ValidationMessage libéré
        La taille de l’objet alloué doit être égale à celle de l’objet ValidationMessage
        Le tampon de données d’un objet ArrayBuffer est un bon candidat

                                                                  More
                                                               ArrayBuffer'
                                                                Contents
                                                                    ...

                                                               ArrayBuffer'
                                                                Contents

                                                             m_messageBody
                                        ValidationMessage
                                                            m_messageHeading

                                                                               ArrayBuffer'
                                                                                Contents
                                                                m_bubble
                                                                 m_timer
                                                               m_message
                                                               m_element

                                                               ArrayBuffer'
                                                                Contents

                                                                  More
                                                               ArrayBuffer
                                                                Contents
                                                                   ...

                                                                                              33/48
Fuite de données initiale

   Fuite de données
        m_messageBody, m_messageHeading et m_timer sont alloués après avoir réutilisé
        l’objet ValidationMessage
        m_timer est alloué par FastMalloc
            Permet d’inférer l’adresse d’objets alloués dans ce tas

                                           m_messageBody

                                         m_messageHeading

                                               m_bubble

                                                m_timer

                                             m_message

                                              m_element

                                         ValidationMessage

                                                                                        34/48
Primitive de décrément arbitraire

   Exploitation
        Corrompre le pointeur m_messageHeading
        Cibler les attributs length des objets permettant de manipuler des données
        Confondre la taille d’un objet avec le compteur de références de l’objet
        m_messageHeading
        Aligner l’objet visé de manière à élargir son attribut length et non le réduire
        L’objectif est d’obtenir une primitive de lecture et écriture relative

                         m_messageBody

                        m_messageHeading

                            m_bubble

                             m_timer                           Data

                           m_message
                                                Length   00   00      00   XX
                            m_element

                        ValidationMessage
                                                                   refcount field

                                                                                          35/48
Stratégie d’exploitation

                                           ASLR Bypass

                                            Obj. Reuse

                           Relative Read                  Relative R/W
                             Primitive                     Primitive

                                                          Arbitrary R/W
                                                            Primitive

                                                         Code Execution

                                                                          36/48
Primitive de lecture relative (1/3)

   Objectif
          Obtenir l’adresse d’un objet JSArrayBufferView alloué par le Garbage Collector

   Comment ?
                                                                           More
                                                                        StringImpl
                                                                             ...
   1   Allouer beaucoup d’objets StringImpl sur
                                                                           data
       le tas

                                                                                       StringImpl
              Avant/après l’allocation de Timer                            flags
              sizeof(Timer) ==                                            data ptr
              sizeof(StringImpl)                                          length
                                                                         refcount
   2   Utiliser le décrément arbitraire sur l’attribut
       length d’un objet StringImpl                                       Timer
   3   Il est possible de lire au-delà des limites
       fixées par l’objet StringImpl                                       More
                                                                        StringImpl
                                                                             ...

                                                                                                    37/48
Primitive de lecture relative (2/3)
   Fuiter l’adresse d’un objet JSArrayBufferView (1/2)
         Les objets du DOM et les objets JavaScript utilisent deux allocateurs différents
              On ne peut pas atteindre un JSObject à partir de notre primitive de lecture relative
         La méthode JavaScript native Object.defineProperties alloue deux objets qui
         permettent de stocker des références vers des JSObject
              Les objets Vector et MarkedArgumentBuffer sont nos cibles

   static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
   {

       Vector descriptors;
       MarkedArgumentBuffer markBuffer;

       /* ... */
       JSValue prop = properties->get(exec, propertyNames[i]);
       /* ... */
       PropertyDescriptor descriptor;
       toPropertyDescriptor(exec, prop, descriptor);
       /* ... */
       descriptors.append(descriptor); // [1] Stocke une JSValue sur le tas de FastMalloc
       /* ... */
       markBuffer.append(descriptor.value()); // [2] Stocke une seconde fois une JSValue sur le tas de
              FastMalloc
   }

                                                                                                         38/48
Primitive de lecture relative (3/3)

   Fuiter l’adresse d’un objet JSArrayBufferView (2/2) 1
   1     Allouer plusieurs objets
                                                                                      JSArrayBufferView
         JSArrayBufferView
   2     Ajouter des références vers ces objets à
         l’aide de la méthode                                                                 ...

         Object.defineProperties
               Les deux objets stockant les références vers
                                                                                     JSArrayBufferView ptr
               les JSObject sont libérés à la fin de
               Object.defineProperties
               Il ne faut pas réutiliser ces allocations sous
                                                                                              ...
               peine de perdre nos références
   3     Utiliser la primitive de lecture relative pour                                      data

                                                                                                             StringImpl
         chercher ces références                                                             flags
               L’objet JSArrayBufferView doit être alloué                                   data ptr
               après l’objet utilisé par la primitive de lecture                            length

               relative afin de pouvoir lire son contenu                                   refcount

       1. Merci @qwertyoruiopz pour la technique utilisant Object.defineProperties

                                                                                                                          39/48
Primitive de lecture/écriture relative

   Comment ?
      1   Utiliser à nouveau la primitive de décrément arbitraire
      2   Corrompre la taille d’un JSArrayBufferView à l’aide de l’adresse obtenue
          précédemment
      3   L’objet JSArrayBufferView corrompu permet de lire et écrire relativement en
          mémoire

                                                         m_butterfly

                                                  m_mode          m_length

                                                          m_vector

                                                        m_structure

                                                                                        40/48
Primitive de lecture/écriture arbitraire

   Comment ?
          Primitive de lecture et écriture relative depuis un premier objet JSArrayBufferView
               Corrompre le pointeur du tampon de données d’un second JSArrayBufferView
          Primitive de lecture et écriture arbitraire à partir du second JSArrayBufferView

                              m_butterfly                     m_butterfly

                          m_mode         m_length         m_mode      m_length
                                                                                 JSArrayBufferView 1
    JSArrayBufferView 2        m_vector                        m_vector

                              m_structure                     m_structure

                                   ...

                              ArrayBuffer

                                                                                                       41/48
Exécution de code

   Comment ?
       La PS4 ne permet pas de mapper une page RWX dans le contexte du processus de
       rendu HTML
       Nous pouvons contrôler le registre d’instruction RIP
            Nous avons l’adresse d’un objet HTMLElement
            Corrompre la vtable d’un HTMLElement
            Appeler la méthode JavaScript associée afin de faire un appel utilisant la vtable corrompue
       L’étape suivante peut-être implémentée à l’aide d’une chaine de ROP/JOP
            Méthode couramment utilisée dans le jailbreak PS4

                                                                                                          42/48
Démonstration

                                  2

   2. image credit : TheRegisti

                                      43/48
Porter l’exploit sur la version 7 (1/3)

   Problématique
        L’adresse utilisée pour contourner l’ASLR sur la version 6 ne fonctionne pas sur la
        version 7 de la PS4
        Le navigateur crash lors de l’étape de la réutilisation de l’objet libéré
        ValidationMessage
             Des connaissances préalables sur le mapping mémoire sont nécessaires

                                                                                              44/48
Porter l’exploit sur la version 7 (2/3)

   Solution
        Bruteforcer l’ASLR
             Deviner l’adresse de l’un des HTMLElement alloué
        Brancher un Raspberry Pi (détecté comme un clavier)
        Appuyer sur la touche “Entrée” à une fréquence régulière (5s)
              Redémarrer le navigateur après un crash
        Pas de résultats :-(

                                                                        45/48
Porter l’exploit sur la version 7 (3/3)

   … Quelques jours après la publication de l’exploit
        Publication d’adresses valides pour la version 7.02
        Adaptation de l’exploit (modifications mineures)
        Enchainement avec l’exploit kernel
        → Premier Jailbreak de la PS4 en version 7

                                                              46/48
Table des matières

 1   Introduction & motivation

 2   État de l’art

 3   Allocateur standard                6   Conclusion

 4   Présentation de la vulnérabilité

 5   Exploitation de la vulnérabilité
Conclusion
   Conclusion
       Exploitation d’une vulnérabilité 0-day WebKit sur la PS4
             L’exploit est disponible sur le github de Synacktiv
       Contribution au premier jailbreak sur le firmware 7.xx

   Perspectives

                                                                   48/48
AVEZ-VOUS
       DES QUESTIONS ?

MERCI DE VOTRE ATTENTION
Vous pouvez aussi lire