Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2022-42864 — Prueba de concepto para el CVE-2022-42864 de condición de carrera en IOHIDFamily | Kitploit
Herramientas/GitHubGitHub/muirey03/cve-2022-42864
Análisis de VulnerabilidadesExplotaciónExplotación de Binarios
GitHubmuirey03/cve-2022-42864

CVE-2022-42864

Prueba de concepto para el CVE-2022-42864 de condición de carrera en IOHIDFamily

Ver Repositorio
6873hace 3 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2022-42864: Cookies Diabólicas

¿Qué es este repositorio?

Esta es mi prueba de concepto (incompleta) del exploit para CVE-2022-42864, una vulnerabilidad de tiempo-de-verificación a tiempo-de-uso en IOHIDFamily que fue corregida en iOS 16.2 / macOS Ventura 13.1.

¿Cuál es el estado de la prueba de concepto?

El exploit actualmente logra la misma primitiva "kfree arbitrario" utilizada en el exploit multicast_bytecopy. Sin embargo, el flujo posterior de exploit de multicast_bytecopy ha sido fuertemente mitigado, por lo que esto no es un exploit completo, solo demuestra la severidad del problema.

¿Debería ejecutar esto?

Si tienes que preguntarlo, no. Esto no hace nada útil, solo provoca un pánico del kernel. No me hago responsable por cualquier pérdida de datos o inestabilidad que este código pueda causar.

El error

El comentario de Apple del código fuente cuando se corrigió este problema lo resume muy bien:

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

Echemos un vistazo a la función antes del parche (he intentado etiquetar las líneas relevantes):

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;
}
  • El bucle en [1] cuenta el número de IOHIDElementValues en el buffer y almacena esta cuenta en cookieCount.
  • La comprobación en [2] (combinada con la condición del bucle while) se asegura de que el campo length de cada cabecera no se extienda más allá de los límites del buffer elementData (ni que quede corto respecto al final del buffer, aunque esto es menos relevante).
  • Una vez que todos los elementos han sido contados y verificados por este bucle, se asigna un buffer cookies al heap en [3] con un tamaño de cookieCount * 4 (o se usa un buffer de pila si cookieCount es suficientemente pequeño).
  • Un segundo bucle en [4] realiza una segunda pasada por el buffer, analizando nuevamente los IOHIDElementValues.
  • Se crean objetos OSData para almacenar el valor de cada elemento en [5], utilizando el campo length que fue validado en el primer bucle.
  • En [6], el cookie de cada elemento se escribe en el array cookies asignado en [3].

Entonces, ¿cuál es el problema? Esta función se comporta correctamente cuando elementData no es volátil, el problema surge cuando el método se llama con memoria compartida. Aquí entra el método IOHIDInterface::SetElementValues_Impl de DriverKit:

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

Aquí, postElementTransaction se llama con md->getBytesNoCopy(), memoria compartida con el espacio de usuario, violando la suposición de que elementData es no volátil. El contenido del buffer elementData puede cambiar después del bucle en [1], pero antes del bucle en [4], entonces, ¿qué significa esto para un atacante?

Hay dos formas en que un atacante puede abusar de esto:

  • La primera es intercambiar el length de un IOHIDElementValueHeader pequeño al final del buffer por un valor mucho más grande. Esto significa que cuando se crea el OSData en [5], se extenderá mucho más allá de los límites del buffer elementData, permitiendo a un atacante leer datos fuera de los límites usando IOHIDInterface::GetElementValues_Impl.
  • La segunda es intercambiar el length de un IOHIDElementValueHeader grande al principio del buffer por un valor mucho más pequeño. Esto hará que el bucle en [4] analice muchos más encabezados de los que fueron contados originalmente en el bucle en [1], por lo que cuando se escriban las cookies en el array cookies en [6], desbordarán el array ya que index nunca se valida contra cookieCount.

En la práctica, esto permite a un atacante leer datos del heap del kernel fuera de los límites de un tamaño arbitrario, y escribir datos arbitrarios (también de tamaño arbitrario) fuera de los límites en el heap del kernel. Estas son dos primitivas poderosas.

Descargar herramienta