Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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é.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2022-42864 — Preuve de concept pour la condition de concurrence IOHIDFamily CVE-2022-42864 | Kitploit
Outils/GitHubGitHub/muirey03/cve-2022-42864
Analyse des VulnérabilitésExploitationExploitation de Binaires
GitHubmuirey03/cve-2022-42864

CVE-2022-42864

Preuve de concept pour la condition de concurrence IOHIDFamily CVE-2022-42864

Voir le dépôt
6873il y a 3 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

CVE-2022-42864 : Cookies diaboliques

Qu'est-ce que ce dépôt ?

Ceci est mon exploit proof-of-concept (incomplet) pour CVE-2022-42864, une vulnérabilité de type temps de vérification/temps d'utilisation (TOCTOU) dans IOHIDFamily qui a été corrigée dans iOS 16.2 / macOS Ventura 13.1.

Quel est l'état du proof-of-concept ?

L'exploit atteint actuellement la même primitive « arbitrary kfree » (libération arbitraire) que celle utilisée dans l'exploit multicast_bytecopy. Cependant, le déroulement ultérieur de l'exploit de multicast_bytecopy a été fortement atténué, donc il ne s'agit pas d'un exploit complet, mais simplement d'une démonstration de la gravité du problème.

Devrais-je exécuter ceci ?

Si vous devez poser la question, non. Cela ne fait rien d'utile, cela provoque simplement un kernel panic. Je ne peux être tenu responsable d'aucune perte de données ni instabilité que ce code pourrait causer.

Le bug

Le commentaire d'Apple dans le code source lors de la correction de ce problème résume bien la situation :

// Find the number of cookies in the data. The data from elementData is shared with user space and may change at any time.

Examinons la fonction avant le patch (j'ai essayé d'annoter les lignes pertinentes) :

IOReturn IOHIDDevice::postElementTransaction(const void* elementData, UInt32 dataSize, UInt32 completionTimeout, IOHIDCompletion * completion)
{
    IOReturn ret = kIOReturnError;
    uint32_t   cookies_[kMaxLocalCookieArrayLength];
    uint32_t   *cookies = cookies_;
    uint32_t   cookieCount = 0;
    uint32_t   cookieSize = 0;
    uint32_t   dataOffset = 0;
    uint8_t    *data = (uint8_t*)elementData;
    IOMemoryDescriptor *elementDesc = getMemoryWithCurrentElementValues();
    require(_elementArray && elementDesc, fail);

    WORKLOOP_LOCK;

    // Find the number of cookies in the data. Check that all cookies are valid elements.                   [1]
    while (dataOffset < dataSize) {
        const IOHIDElementValueHeader *headerPtr = (const IOHIDElementValueHeader *)(data + dataOffset);
        IOHIDElementPrivate *element = GetElement(headerPtr->cookie);
        if (!element) {
            HIDDeviceLogError("Could not find element for cookie: %d", headerPtr->cookie);
            ret = kIOReturnAborted;
            goto fail;
        }
        cookieCount++;

        require_noerr_action(os_add3_overflow(dataOffset, headerPtr->length, sizeof(IOHIDElementValueHeader), &dataOffset), fail, HIDDeviceLogError("Overflow iterating cookie data buffer %u %u", dataOffset, headerPtr->length));
    }
    // Data isn't as large as expected, don't overrun, just abort
    if (dataOffset != dataSize) {   //                                                                      [2]
        HIDDeviceLogError("Cookie data buffer is smaller than expected. %u vs. %u",
                        (unsigned int)dataSize, (unsigned int)dataOffset);
        ret = kIOReturnAborted;
        goto fail;
    }
    dataOffset = 0;

    require_noerr_action(os_mul_overflow(cookieCount, sizeof(uint32_t), &cookieSize),
                        fail,
                        HIDDeviceLogError("Overflow calculating cookieSize"));

    cookies = (cookieCount <= kMaxLocalCookieArrayLength) ? cookies : (uint32_t*)IOMallocData(cookieSize); // [3]

    if (cookies == NULL) {
        ret = kIOReturnNoMemory;
        goto fail;
    }

    // Update the elements, this replaced the shared kernel-user shared memory.
    for (size_t index = 0; dataOffset < dataSize; ++index) {    //                                          [4]
        const IOHIDElementValueHeader *headerPtr;
        IOHIDElementPrivate *element;
        OSData *elementVal;

        headerPtr = (const IOHIDElementValueHeader *)(data + dataOffset);
        element = GetElement(headerPtr->cookie);
        dataOffset += headerPtr->length + sizeof(IOHIDElementValueHeader);

        elementVal = OSData::withBytesNoCopy((void*)headerPtr->value,
                                            headerPtr->length); //                                          [5]
        require_action(elementVal, fail, ret = kIOReturnNoMemory);
        element->setDataBits(elementVal);
        elementVal->release();

        cookies[index] = headerPtr->cookie; //                                                              [6]
    }

    // Actually post elements
    ret = postElementValues((IOHIDElementCookie *)cookies, (UInt32)cookieCount, 0, completionTimeout, completion);

fail:
    WORKLOOP_UNLOCK;
    if (cookies != &cookies_[0]) {
        IOFreeData(cookies, cookieSize);
    }

    return ret;
}
  • La boucle [1] compte le nombre de IOHIDElementValues dans le tampon et stocke ce compte dans cookieCount.
  • La vérification [2] (combinée à la condition de la boucle while) garantit que le champ length de chaque en-tête ne dépasse pas les limites du tampon elementData (et ne s'arrête pas non plus avant la fin du tampon, bien que cela soit moins pertinent).
  • Une fois que tous les éléments ont été comptés et validés par cette boucle, un tampon cookies est alloué sur le tas en [3] avec une taille de cookieCount * 4 (ou un tampon sur la pile est utilisé si cookieCount est suffisamment petit).
  • Une seconde boucle en [4] effectue ensuite un deuxième passage dans le tampon, analysant à nouveau les IOHIDElementValues.
  • Des objets OSData sont créés pour contenir la valeur de chaque élément en [5], utilisant le champ length validé dans la première boucle.
  • En [6], le cookie de chaque élément est écrit dans le tableau cookies alloué en [3].

Quel est donc le problème ? Cette fonction se comporte parfaitement correctement lorsque elementData n'est pas volatil ; le problème survient lorsque la méthode est appelée avec de la mémoire partagée. Voici la méthode DriverKit IOHIDInterface::SetElementValues_Impl :

kern_return_t
IMPL(IOHIDInterface, SetElementValues)
{
    IOReturn ret = kIOReturnError;
    UInt8 *values = NULL;
    IOBufferMemoryDescriptor *md = NULL;
    
    md = OSDynamicCast(IOBufferMemoryDescriptor, elementValues);
    require_action(md && count, exit, ret = kIOReturnBadArgument);

    values = (UInt8 *)md->getBytesNoCopy();
    
    // Post the data to the device
    ret = _owner->postElementTransaction(values, (UInt32)md->getLength());
    require_noerr_action(ret, exit, HIDServiceLogError("postElementValues failed: 0x%x", ret));

exit:
    return ret;
}

Ici, postElementTransaction est appelée avec md->getBytesNoCopy(), une mémoire partagée avec l'espace utilisateur, ce qui viole l'hypothèse selon laquelle elementData n'est pas volatil. Le contenu du tampon elementData peut changer après la boucle [1], mais avant la boucle [4]. Qu'est-ce que cela signifie pour un attaquant ?

Un attaquant peut abuser de cela de deux manières :

  • La première consiste à remplacer le length d'un petit IOHIDElementValueHeader à la fin du tampon par une valeur beaucoup plus grande. Cela signifie que lorsque OSData est créé en [5], il s'étendra bien au-delà des limites du tampon elementData, permettant à un attaquant de lire des données hors limites à l'aide de IOHIDInterface::GetElementValues_Impl.
  • La seconde consiste à remplacer le length d'un grand IOHIDElementValueHeader au début du tampon par une valeur beaucoup plus petite. Cela fera analyser par la boucle [4] beaucoup plus d'en-têtes que ceux comptés initialement dans la boucle [1], de sorte que lorsque les cookies sont écrits dans le tableau cookies en [6], ils déborderont du tableau car index n'est jamais validé par rapport à cookieCount.
Télécharger l’outil