2009-02-17 29 views
24

Necesito ejecutar un script bash como root (sudo o su no viable sin contraseña) y como no puede establecer un script en Linux, pensé en llamar desde un ejecutable y hacer que setuid:Llamar a un script desde un programa setuid root C - script no se ejecuta como root

$ 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 - al igual que en la secuencia de comandos se ejecuta correctamente - pero el script se ejecuta como el usuario que ejecuta "./wrapper".

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

Gracias!

+2

Por el razonamiento detrás de las respuestas a continuación, consulte 'man system', y http://stackoverflow.com/questions/1051370/why-do-i-need-setuid0-within-a-setuid-root-c- program-that-calls-an-administrati –

Respuesta

38

Desde el bit suid en ejecutables sólo cambia el UID efectivo (EUID) el ejecutable se ejecutará como, y no el verdadero UID (RUID) que getuid() devoluciones, y además de la restricción de suid guiones interpretarse (cualquier principio ejecutable con "#!"), algunos shells como bash como una medida de seguridad adicional volverán a configurar el EUID en el RUID. En este caso, deberá usar la llamada setuid(0) en el código C antes de ejecutar el script.

Ver las páginas del mansetuid, seteuid, getuid, y geteuid para aprender la semántica exacta de los UID real y efectivo.

(ADVERTENCIA) Por supuesto, esto es un punto apropiado mencionar que la restricción de suid scripts en muchos sistemas UNIX, conchas e intérpretes, están ahí por una razón, y es que si el guión no es muy cuidadoso sobre la desinfección de su entrada y el estado del entorno cuando se ejecuta, son peligrosos y pueden ser explotados para la escalada de seguridad. Así que ten mucho cuidado al hacer esto. Establezca el acceso a su secuencia de comandos y envoltorio tan estrictamente como sea posible, solo permita este script muy específico que desea ejecutar, y borre el entorno dentro de su programa C antes de iniciar el script, estableciendo variables de entorno como PATH para contener exactamente lo que es necesario en el orden correcto y no hay directorios que puedan escribirse a otros.

+0

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

+0

Si su programa hace otras cosas después de que termina el guión, eso no necesita esto, entonces sí. Si todo lo que haces es regresar, entonces realmente no importa. En el caso típico, un contenedor de scripts usará el comando exec y no el sistema (...), así que de todos modos el contenedor no se ejecutará después de que el script finalice. –

+0

@TomAlsberg ¿Conoces el código fuente/documentación para confirmar el comportamiento de Bash para este 'auto reset user'? – steveyang

6

Otra cosa a tener en cuenta aquí es que la limitación aquí es de bash y no del propio sistema * nix. Bash realmente realiza verificaciones en los scripts SUID para ejecutarlos solo con la raíz EUID. Si toma conchas más viejas, a menudo obtendrá lo que quería de la caja. Por ejemplo, sh no hace que 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 bash:

$ 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 

Sin embargo, la respuesta de Tom es generalmente el camino a seguir para la fabricación de un contenedor para los programas de root

+0

Tienes razón, por supuesto. Linux maneja la restricción de scripts suid comprobando el modo del ejecutable en la llamada del ejecutivo, 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! –

+0

Y, por supuesto, lo eché de menos en el código del OP, ¡en realidad no está ejecutando un script con un #! la especificación del intérprete, 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. –

+0

No funciona (nunca más). Por un lado, 'man system' dice' No use system() desde un programa con set-user-ID o set-group-ID privilegios, porque ... '. Por otro lado, esto funciona en Ubuntu 14.04 pero no en Ubuntu 16.04. – anumi

3

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 
$ 
+2

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

0

¿Por qué sudo no es viable?Evita que rabia agujeros de seguridad, tales 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$ 

Debido al ambiente no ser desinfectados adecuadamente, por ejemplo, en este caso:

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

sudo desinfecta este caso, y tal vez otros casos extremos y trampas que sería bueno no escribir en un envoltorio suid personalizado.

+0

man sudo: "Ejecutar scripts de shell mediante sudo puede exponer los mismos errores de núcleo que hacen inseguros los scripts de shell setuid en algunos sistemas operativos ..." Un estándar envoltorio para hacer scripts suid es probablemente el mejor, pero ¿conoces uno? ¡Sudo no es seguro aquí, porque depende del kernel para pasar el script a través de/dev/fd/...! –

1

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

Nunca pase por un intérprete de comandos 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.

Cuestiones relacionadas