Llamar a un script desde un programa setuid root C: el script no se ejecuta como root

6 minutos de lectura

Necesito ejecutar un script bash como root (sudo sin contraseña o su no viable) y dado que no se puede configurar un script en Linux, pensé en llamarlo desde un ejecutable y hacer eso setuido:

$ cat wrapper.c
int main(void)
{
        system("/bin/bash ./should_run_as_root.sh");
}
$ gcc -o wrapper wrapper.c
$ sudo chown root wrapper
$ sudo chmod ug+s wrapper
$ ll wrapper
-rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper
$

Esto funciona, ya que ejecuta el script correctamente, pero el script se ejecuta como el usuario que ejecuta “./wrapper”.

¿Por qué? ¿Y cómo implementar esto correctamente?

¡Gracias!

  • Para el razonamiento detrás de las respuestas a continuación, consulte man system y stackoverflow.com/questions/1051370/…

    – Stefan Lasiewski

    14/03/2011 a las 21:57

avatar de usuario
tom alsberg

Desde el suid bit en ejecutables solo cambia el UID efectivo (EUID) con el que se ejecutará el ejecutable, y no el UID real (RUID) que getuid() devoluciones, y además de la restricción de suid scripts interpretados (cualquier ejecutable que comience con “#!“), algunas conchas como bash como medida de seguridad adicional, el EUID volverá a ser el RUID; en este caso, deberá usar la llamada setuid(0) en el código C antes de ejecutar el script.

Ver el man paginas de la setuid, seteuid, getuidy geteuid para aprender la semántica exacta de los UID reales y efectivos.

(ADVERTENCIA) Por supuesto, este es un punto apropiado para mencionar que la restricción a suid Las secuencias de comandos en muchos sistemas Unix, shells e intérpretes están ahí por una razón, y es que si la secuencia de comandos no es muy cuidadosa al desinfectar su entrada y el estado del entorno cuando se ejecuta, son peligrosas y pueden ser explotadas para aumentar la seguridad. . Así que ten mucho cuidado al hacer esto. Establezca el acceso a su secuencia de comandos y envoltorio lo más estricto posible, solo permita esta secuencia de comandos muy específica que pretende ejecutar y borre el entorno dentro de su programa C antes de iniciar la secuencia de comandos, configurando variables de entorno como PATH para contener exactamente lo que es necesario en el orden correcto y sin directorios en los que otros puedan escribir.

  • ¿Es más seguro guardar el UID original y restablecerlo al final del programa?

    – skinp

    17 de febrero de 2009 a las 14:49

  • Si su programa hace otras cosas después de que finaliza el script, que no necesitan esto, entonces sí. Si todo lo que haces es regresar, entonces realmente no importa. En el caso típico, un contenedor de secuencias de comandos usará exec y no sistema (…), por lo que, de todos modos, el contenedor no se ejecutará después de que finalice la secuencia de comandos.

    –Tom Alsberg

    17 de febrero de 2009 a las 21:50

  • @TomAlsberg ¿Conoce el código fuente/documentación para confirmar el comportamiento de Bash para este ‘uid de reinicio automático’?

    – steveyang

    18 mayo 2013 a las 17:11

avatar de usuario
pelar

Otra cosa a tener en cuenta aquí es que la limitación aquí es de bash y no del sistema *nix en sí. Bash realmente realiza verificaciones en los scripts SUID para ejecutarlos solo con la raíz EUID. Si toma carcasas más antiguas, a menudo obtendrá lo que quería de la caja. Por ejemplo, sh no hace este tipo de verificaciones:

$ cat wrapper.c
int main(void)
{
            system("/bin/sh -c whoami");
}

$ ls -l wrapper
-rwsr-sr-x 1 root users 8887 Feb 17 14:15 wrapper
$ ./wrapper
root

con golpe:

$ cat wrapper.c
int main(void)
{
            system("/bin/bash -c whoami");
}

$ ls -l wrapper
-rwsr-sr-x 1 root users 8887 Feb 17 14:18 wrapper
$ ./wrapper
skinp

Aún así, la respuesta de Tom es generalmente el camino a seguir para hacer un contenedor para los programas raíz SUID

  • Estas en lo correcto, por su puesto. Linux maneja la restricción de los scripts suid al verificar el modo del ejecutable en la llamada exec, y esta restricción es una medida de seguridad adicional de algunos intérpretes. No estoy seguro de por qué tuve esta confusión cuando escribí esto. Corregí mi respuesta. ¡Gracias!

    –Tom Alsberg

    17 de febrero de 2009 a las 21:44

  • ¡Y, por supuesto, me perdí que en el código del OP no está ejecutando un script con un #! especificación del intérprete en absoluto, pero llamando a bash directamente, por lo que la restricción del kernel no se aplicaría en este caso de todos modos, ¡pero el kernel tiene esta restricción para #! scripts con el modo de archivo suid.

    –Tom Alsberg

    17 de febrero de 2009 a las 21:49

  • No funciona (más). Por un lado, man system dice Do not use system() from a program with set-user-ID or set-group-ID privileges, because .... Por otro lado, esto funciona en Ubuntu 14.04 pero no en Ubuntu 16.04.

    – anumi

    19/10/2016 a las 15:23

  • @anumi como mencioné, esto dependerá de Shell. /bin/bash en ubuntu en realidad está vinculado a dash. Parece que esto se solucionó entre el 14.04 y el 16.04, probablemente en bugs.launchpad.net/ubuntu/+source/dash/+bug/1215660. Otros shells en otras distribuciones/versiones tendrán comportamientos diferentes.

    – skinp

    20 oct 2016 a las 15:15

Agregue el setuid(0) en el script y complételo. Debería funcionar después de esto.

$ cat wrapper.c 
int main(void) 
{ 
        setuid(0);
        system("/bin/bash ./should_run_as_root.sh"); 
} 
$ gcc -o wrapper wrapper.c 
$ sudo chown root wrapper 
$ sudo chmod ug+s wrapper 
$ ll wrapper 
-rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper 
$ 

  • No use system() desde un programa con privilegios set-user-ID o set-group-ID, porque se pueden usar valores extraños para algunas variables de entorno para subvertir la integridad del sistema. Utilice la familia de funciones exec(3) en su lugar, pero no execlp(3) o execvp(3). system(), de hecho, no funcionará correctamente desde programas con privilegios set-user-ID o set-group-ID en sistemas en los que /bin/sh es bash versión 2, ya que bash 2 elimina los privilegios al iniciarse. (Debian usa un bash modificado que no hace esto cuando se invoca como sh).

    – categoría de

    7 de junio de 2011 a las 16:48

Los ejemplos son terriblemente inseguros y permiten que cualquier persona con dos bits de conocimiento ejecute cualquier programa que desee como usuario setuid.

Nunca pase por un shell a menos que primero desinfecte el entorno, la mayoría de los ejemplos que se muestran aquí son vulnerables a tener IFS y PATH configurados antes de ejecutarlo.

¿Por qué sudo no es viable? Evita agujeros de seguridad furiosos como:

bash-3.2$ cat test
#!/bin/bash
echo ima shell script durp durp
bash-3.2$ chmod +x test
bash-3.2$ ./test
heh heh
bash-3.2$ 

Por no estar debidamente higienizado el ambiente, por ejemplo en este caso:

export echo='() { builtin echo heh heh; }'

sudo desinfecta este caso, y quizás otros casos extremos y errores que sería bueno no escribir en un envoltorio suid personalizado.

  • man sudo: “Ejecutar scripts de shell a través de sudo puede exponer los mismos errores del kernel que hacen que los scripts de shell setuid no sean seguros en algunos sistemas operativos…” Probablemente lo mejor sea un contenedor estándar para hacer scripts suid, pero ¿conoce uno? ¡Sudo no es seguro aquí, porque depende del kernel para pasar el script a través de /dev/fd/…!

    – Roberto Siemer

    9 de febrero de 2012 a las 7:56

  • man sudo: “Ejecutar scripts de shell a través de sudo puede exponer los mismos errores del kernel que hacen que los scripts de shell setuid no sean seguros en algunos sistemas operativos…” Probablemente lo mejor sea un contenedor estándar para hacer scripts suid, pero ¿conoce uno? ¡Sudo no es seguro aquí, porque depende del kernel para pasar el script a través de /dev/fd/…!

    – Roberto Siemer

    9 de febrero de 2012 a las 7:56

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad