Linux ignora el bit setuid¹ en todos los ejecutables interpretados (es decir, ejecutables que comienzan con una #!
línea). Las preguntas frecuentes de comp.unix.questions explican los problemas de seguridad con los scripts de shell setuid. Estos problemas son de dos tipos: relacionados con shebang y relacionados con shell; Entro en más detalles a continuación.
Si no le importa la seguridad y desea permitir secuencias de comandos setuid, en Linux, deberá parchear el núcleo. A partir de los núcleos 3.x, creo que debe agregar una llamada a install_exec_creds
la load_script
función, antes de la llamada a open_exec
, pero no lo he probado.
Setuid shebang
Hay una condición de carrera inherente a la forma en que #!
se implementa shebang ( ):
- El núcleo abre el ejecutable y descubre que comienza con
#!
.
- El kernel cierra el ejecutable y abre el intérprete en su lugar.
- El kernel inserta la ruta del script a la lista de argumentos (como
argv[1]
) y ejecuta el intérprete.
Si se permiten scripts setuid con esta implementación, un atacante puede invocar un script arbitrario creando un enlace simbólico a un script setuid existente, ejecutándolo y organizando el cambio del enlace después de que el núcleo haya realizado el paso 1 y antes de que el intérprete llegue a abriendo su primer argumento. Por esta razón, la mayoría de los equipos ignoran el bit setuid cuando detectan un shebang.
Una forma de asegurar esta implementación sería que el kernel bloquee el archivo de script hasta que el intérprete lo haya abierto (tenga en cuenta que esto debe evitar no solo desvincular o sobrescribir el archivo, sino también renombrar cualquier directorio en la ruta). Pero los sistemas unix tienden a evitar los bloqueos obligatorios, y los enlaces simbólicos harían que una función de bloqueo correcta sea especialmente difícil e invasiva. No creo que nadie lo haga de esta manera.
Algunos sistemas Unix (principalmente OpenBSD, NetBSD y Mac OS X, todos los cuales requieren que se habilite una configuración del kernel) implementan shebang setuid seguro utilizando una característica adicional: la ruta se refiere al archivo ya abierto en el descriptor de archivo N (por lo que la apertura es aproximadamente equivalente a ). Muchos sistemas unix (incluido Linux) tienen scripts setuid pero no./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- El núcleo abre el ejecutable y descubre que comienza con
#!
. Digamos que el descriptor de archivo para el ejecutable es 3.
- El núcleo abre el intérprete.
- El núcleo inserta
/dev/fd/3
la lista de argumentos (como argv[1]
) y ejecuta el intérprete.
La página de shebang de Sven Mascheck tiene mucha información sobre shebang a través de unidades, incluido el soporte de setuid .
Intérpretes setuid
Supongamos que ha logrado hacer que su programa se ejecute como root, ya sea porque su sistema operativo admite setbanid shebang o porque ha utilizado un contenedor binario nativo (como sudo
). ¿Has abierto un agujero de seguridad? Tal vez . El problema aquí no es sobre programas interpretados o compilados. El problema es si su sistema de tiempo de ejecución se comporta de manera segura si se ejecuta con privilegios.
Cualquier ejecutable binario nativo vinculado dinámicamente es interpretado de alguna manera por el cargador dinámico (por ejemplo /lib/ld.so
), que carga las bibliotecas dinámicas requeridas por el programa. En muchos dispositivos, puede configurar la ruta de búsqueda para bibliotecas dinámicas a través del entorno ( LD_LIBRARY_PATH
es un nombre común para la variable de entorno) e incluso cargar bibliotecas adicionales en todos los archivos binarios ejecutados ( LD_PRELOAD
). El invocador del programa puede ejecutar código arbitrario en el contexto de ese programa colocando un especialmente diseñado libc.so
en $LD_LIBRARY_PATH
(entre otras tácticas). Todos los sistemas sanos ignoran las LD_*
variables en los ejecutables setuid.
En shells como sh, csh y derivados, las variables de entorno se convierten automáticamente en parámetros de shell. A través de parámetros como PATH
, IFS
y muchos más, el invocador del script tiene muchas oportunidades para ejecutar código arbitrario en el contexto de los scripts de shell. Algunos shells establecen estas variables en valores predeterminados razonables si detectan que el script ha sido invocado con privilegios, pero no sé si hay alguna implementación en particular en la que pueda confiar.
La mayoría de los entornos de tiempo de ejecución (ya sean nativos, de bytes o interpretados) tienen características similares. Pocos toman precauciones especiales en los ejecutables setuid, aunque los que ejecutan código nativo a menudo no hacen nada más elegante que el enlace dinámico (que toma precauciones).
Perl es una notable excepción. Es explícitamente compatible con scripts setuid de forma segura. De hecho, su script puede ejecutar setuid incluso si su sistema operativo ignoró el bit setuid en los scripts. Esto se debe a que Perl se envía con un ayudante raíz setuid que realiza las comprobaciones necesarias y revoca al intérprete en los scripts deseados con los privilegios deseados. Esto se explica en el manual de Perlsec . Solía ser que los scripts de perl setuid necesarios en #!/usr/bin/suidperl -wT
lugar de #!/usr/bin/perl -wT
, pero en la mayoría de los sistemas modernos, #!/usr/bin/perl -wT
son suficientes.
Tenga en cuenta que el uso de un contenedor binario nativo no hace nada en sí mismo para evitar estos problemas . De hecho, puede hacer que la situación es peor , ya que podría evitar que el entorno de ejecución de detectar que se invoca con privilegios y sin pasar por su capacidad de configuración de tiempo de ejecución.
Un contenedor binario nativo puede hacer que un script de shell sea seguro si el contenedor desinfecta el entorno . El script debe tener cuidado de no hacer demasiadas suposiciones (por ejemplo, sobre el directorio actual), pero esto continúa. Puede usar sudo para esto siempre que esté configurado para desinfectar el medio ambiente. Las variables de la lista negra son propensas a errores, por lo que siempre debe incluirlas en la lista blanca. Con sudo, asegúrese de que la env_reset
opción está activada, que setenv
es apagado, y que env_file
y env_keep
sólo contienen las variables inocuos.
TL, DR:
- Setuid shebang es inseguro pero generalmente ignorado.
- Si ejecuta un programa con privilegios (ya sea a través de sudo o setuid), escriba código nativo o perl, o inicie el programa con un contenedor que desinfecte el entorno (como sudo con la
env_reset
opción).
¹ Esta discusión se aplica igualmente si sustituye "setgid" por "setuid"; ambos son ignorados por el kernel de Linux en los scripts