Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
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
CVE-2022-42864 — Proof-of-Concept für die CVE-2022-42864 IOHIDFamily Race-Condition | Kitploit
Tools/GitHubGitHub/muirey03/cve-2022-42864
SchwachstellenanalyseExploitationBinary-Exploitation
GitHubmuirey03/cve-2022-42864

CVE-2022-42864

Proof-of-Concept für die CVE-2022-42864 IOHIDFamily Race-Condition

Repository anzeigen
6873vor 3 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

CVE-2022-42864: Diabolische Cookies

Was ist dieses Repo?

Dies ist mein (unvollständiger) Proof-of-Concept-Exploit für CVE-2022-42864, eine Time-of-Check-Time-of-Use-Schwachstelle in IOHIDFamily, die mit iOS 16.2 / macOS Ventura 13.1 behoben wurde.

Wie ist der Status des Proof-of-Concept?

Der Exploit erreicht derzeit die gleiche „arbitrary kfree“-Primitive, die auch im multicast_bytecopy-Exploit verwendet wird. Allerdings wurde der darauffolgende Exploit-Ablauf von multicast_bytecopy stark abgesichert, sodass es sich hierbei nicht um einen vollständigen Exploit handelt, sondern lediglich um eine Demonstration des Schweregrads des Problems.

Sollte ich das ausführen?

Wenn Sie fragen müssen, nein. Dies tut nichts Nützliches, es führt lediglich zu einer Kernel-Panik. Ich übernehme keine Verantwortung für Datenverlust oder Instabilität, die durch diesen Code verursacht werden könnte.

Der Bug

Apple's Kommentar aus dem Quellcode, als dieses Problem behoben wurde, fasst es gut zusammen:

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

Schauen wir uns die Funktion vor dem Patch an (ich habe versucht, relevante Zeilen zu kennzeichnen):

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;
}
  • Die Schleife bei [1] zählt die Anzahl der IOHIDElementValues im Puffer und speichert diese Anzahl in cookieCount.
  • Die Überprüfung bei [2] (zusammen mit der Bedingung der while-Schleife) stellt sicher, dass das length-Feld jedes Headers nicht über die Grenzen des elementData-Puffers hinausreicht (noch darf es vor dem Ende des Puffers enden, obwohl dies weniger relevant ist).
  • Sobald alle Elemente durch diese Schleife gezählt und auf Plausibilität geprüft wurden, wird bei [3] ein cookies-Puffer auf dem Heap mit einer Größe von cookieCount * 4 allokiert (oder ein Stack-Puffer, falls cookieCount klein genug ist).
  • Eine zweite Schleife bei [4] durchläuft den Puffer dann ein zweites Mal und parst die IOHIDElementValues erneut.
  • Bei [5] werden OSData-Objekte erstellt, die den Wert jedes Elements halten, unter Verwendung des length-Feldes, das in der ersten Schleife validiert wurde.
  • Bei [6] wird das cookie jedes Elements in das bei [3] allokierte cookies-Array geschrieben.

Was ist also das Problem? Diese Funktion verhält sich vollkommen korrekt, wenn elementData nicht flüchtig ist. Das Problem tritt auf, wenn die Methode mit gemeinsam genutztem Speicher aufgerufen wird. Betreten Sie die IOHIDInterface::SetElementValues_Impl DriverKit-Methode:

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;
}

Hier wird postElementTransaction mit md->getBytesNoCopy() aufgerufen, einem mit dem Userspace geteilten Speicher. Dies verletzt die Annahme, dass elementData nicht flüchtig ist. Der Inhalt des elementData-Puffers kann sich nach der Schleife bei [1], aber vor der Schleife bei [4] ändern. Was bedeutet das für einen Angreifer?

Ein Angreifer kann dies auf zwei Arten ausnutzen:

  • Die erste besteht darin, die length eines kleinen IOHIDElementValueHeader am Ende des Puffers auf einen viel größeren Wert zu ändern. Wenn dann das OSData bei [5] erstellt wird, reicht es weit über die Grenzen des elementData-Puffers hinaus, sodass ein Angreifer mit IOHIDInterface::GetElementValues_Impl Daten außerhalb der Grenzen lesen kann.
  • Die zweite besteht darin, die length eines großen IOHIDElementValueHeader am Anfang des Puffers auf einen viel kleineren Wert zu ändern. Dadurch werden in der Schleife bei [4] viele weitere Header geparst, als ursprünglich in der Schleife bei [1] gezählt wurden. Wenn dann die Cookies in das cookies-Array bei [6] geschrieben werden, kommt es zu einem Überlauf aus dem Array heraus, da index nie gegen cookieCount validiert wird.
Tool herunterladen