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
suidperl
material ha sido desaprobado y marcado para su eliminación durante años (pero persiste de todossuidperl
se ha eliminado a partir de perl 5.11 (5.12 estable): perl5110delta:> "suidperl" se ha eliminado. Solía proporcionar un mecanismo para emular bits de permisos setuid en sistemas que no lo admiten correctamente. perl5120delta:> "suidperl" ya no es parte de Perl. Solía proporcionar un mecanismo para emular bits de permisos setuid en sistemas que no lo admiten correctamente.Una forma de resolver este problema es llamar al script de shell desde un programa que puede usar el bit setuid.
Es algo así como sudo. Por ejemplo, así es como lograrías esto en un programa en C:
Guárdelo como setuid-test2.c.
compilar
Ahora haga el setuid en este programa binario:
Ahora, debería poder ejecutarlo, y verá que su script se ejecuta sin permisos de nadie.
Pero aquí también debe codificar la ruta del script o pasarla como argumento de línea de comando al exe anterior.
fuente
PATH
yLD_LIBRARY_PATH
son vectores obvios. Algunas conchas ejecutar$ENV
o$BASHENV
, o~/.zshenv
incluso antes de que comience a ejecutar el guión adecuado, por lo que no puede protegerse de estos en todo desde el guión. La única forma segura de invocar un script de shell con privilegios es limpiar el entorno . Sudo sabe cómo hacerlo de manera segura. Así que no escriba su propio contenedor, use sudo .LD_LIBRARY_PATH
entre otras cosas cuando encuentra el bit setuid.system
, puede encontrar más simple (y más eficiente) usar uno de laexec
familia, lo más probableexecve
. De esa manera, no crea un nuevo proceso ni inicia un shell, y puede reenviar argumentos (suponiendo que su script privilegiado pueda manejar argumentos de manera segura).Prefiero algunos scripts que están en este barco así:
Tenga en cuenta que esto no se usa
setuid
sino que simplemente ejecuta el archivo actual consudo
.fuente
sudo
aviso. (Para mí, el objetivo de setuid es permitir que las cosas se ejecuten como root sin necesidad de sudo.)Si desea evitar llamar
sudo some_script
, simplemente puede hacer:Los programas SETUID deben diseñarse con extremo cuidado, ya que se ejecutan con privilegios de root y los usuarios tienen un gran control sobre ellos. Necesitan comprobar la cordura de todo. No puede hacerlo con scripts porque:
sed
,awk
etc. también necesitarían ser verificadosTenga en cuenta que
sudo
proporciona algunas comprobaciones de cordura, pero no es suficiente: verifique cada línea en su propio código.Como última nota: considere usar capacidades. Le permiten otorgar a un proceso que se ejecuta como usuario privilegios especiales que normalmente requerirían privilegios de root. Sin embargo, por ejemplo, aunque
ping
necesita manipular la red, no necesita tener acceso a los archivos. Sin embargo, no estoy seguro si se heredan.fuente
/ust/bin/env
debería ser/usr/bin/env
.Puede crear un alias para sudo + el nombre del script. Por supuesto, eso es aún más trabajo para configurar, ya que también debe configurar un alias, pero le ahorra tener que escribir sudo.
Pero si no le importan los horribles riesgos de seguridad, use un shell setuid como intérprete para el script de shell. No sé si eso funcionará para ti, pero supongo que podría funcionar.
Sin embargo, permítanme decir que les aconsejo no hacerlo. Solo lo menciono con fines educativos ;-)
fuente
rm -rf /
(y otros comandos de la serie NO LO HAGAS EN CASA ).comando super [-r reqpath] [args]
Super permite que usuarios específicos ejecuten scripts (u otros comandos) como si fueran root; o puede establecer los grupos uid, gid y / o suplementarios por comando antes de ejecutar el comando. Se pretende que sea una alternativa segura a la creación de scripts de raíz setuid. Super también permite a los usuarios comunes proporcionar comandos para que otros los ejecuten; estos se ejecutan con el uid, gid y grupos del usuario que ofrece el comando.
Super consulta un archivo `` super.tab '' para ver si el usuario puede ejecutar el comando solicitado. Si se otorga el permiso, super ejecutará pgm [args], donde pgm es el programa asociado con este comando. (La ejecución de raíz está permitida de manera predeterminada, pero aún se puede denegar si una regla excluye la raíz. Los usuarios ordinarios no pueden ejecutar de manera predeterminada).
Si el comando es un enlace simbólico (o también un enlace duro) al superprograma, escribir% command args es equivalente a escribir% super command args (El comando no debe ser super o super no reconocerá que se invoca a través de un enlazar.)
http://www.ucolick.org/~will/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
fuente
Si por alguna razón
sudo
no está disponible, puede escribir un script de envoltura delgada en C:Y una vez que lo compila, configúrelo como
setuid
conchmod 4511 wrapper_script
.Esto es similar a otra respuesta publicada, pero ejecuta el script con un entorno limpio y usa explícitamente en
/bin/bash
lugar del shell llamado porsystem()
, y cierra algunos posibles agujeros de seguridad.Tenga en cuenta que esto descarta el entorno por completo. Si desea usar algunas variables ambientales sin abrir vulnerabilidades, realmente solo necesita usarlas
sudo
.Obviamente, desea asegurarse de que el script solo se pueda escribir de raíz.
fuente
Primero encontré esta pregunta, no convencido por todas las respuestas, aquí hay una mucho mejor, que también le permite ofuscar completamente su script de bash, si está tan inclinado.
Debería explicarse por sí mismo.
Entonces corres
fuente