¿Por qué el bit setuid funciona de manera inconsistente?

8

Escribí el código:

// a.c
#include <stdlib.h>
int main () {
  system("/bin/sh");
  return 0;
}

compilado con el comando:

gcc a.c -o a.out

bit setuid agregado en él:

sudo chown root.root a.out
sudo chmod 4755 a.out

En Ubuntu 14.04, cuando ejecuto como usuario general, obtuve el privilegio de root.

pero en Ubuntu 16.04, todavía tengo el shell del usuario actual.

¿Por qué es diferente?

usuario10883182
fuente

Respuestas:

9

Lo que cambió es que se /bin/shconvirtió basho se quedó, lo dashque obtuvo una bandera adicional que -pimita el comportamiento de bash.

Bash requiere que la -pbandera no suelte el privilegio setuid como se explica en su página de manual :

Si el shell se inicia con el id. De usuario (grupo) efectivo no es igual al id. De usuario real (grupo), y no se proporciona la opción -p, no se leen archivos de inicio, las funciones de shell no se heredan del entorno, los SHELLOPTS , BASHOPTS, CDPATH y GLOBIGNORE, si aparecen en el entorno, se ignoran y la identificación de usuario efectiva se establece en la identificación de usuario real . Si se proporciona la opción -p en la invocación, el comportamiento de inicio es el mismo, pero el ID de usuario efectivo no se restablece.

Antes dashno me importaba esto y permitía la ejecución de setuid (al no hacer nada para evitarlo) Pero Ubuntu 16.04 de dashpágina de manual 's ha descrito una opción adicional, similar a bash:

-p priv
No intente restablecer uid efectivo si no coincide con uid. Esto no está configurado de manera predeterminada para ayudar a evitar el uso incorrecto de los programas raíz setuid a través del sistema (3) o popen (3).

Esta opción no existía en upstream (que podría no haber sido reactivo a un parche propuesto * ) ni en Debian 9, pero está presente en Debian Buster, que recibió el parche desde 2018.

NOTA: como se explica por Stéphane Chazelas, ya es demasiado tarde para invocar "/bin/sh -p"en system()porque system()se ejecuta nada dada a través de /bin/shlo que el setuid ya se deja caer. La respuesta de derobert explica cómo manejar esto, en el código anterior system().

* Más detalles sobre la historia aquí y allá .

AB
fuente
system("bash -p")se ejecuta, por sh -c "bash -p"lo que los privilegios ya se han eliminado cuando bashse ejecuta.
Stéphane Chazelas
oh bueno ok Eliminaré la parte de "solución" mejor manejada por la respuesta de derobert de todos modos.
AB
Ver también bugs.debian.org/cgi-bin/bugreport.cgi?bug=734869
Stéphane Chazelas
Parece un guión fijo de Ubuntu en astuta (15.10). bugs.launchpad.net/ubuntu/+source/dash/+bug/1215660
Mark Plotnick
1
Tenga en cuenta que Debian solía ser al revés. Solía ​​parchear bash para no perder privilegios. Si es una mejora es discutible. Ahora, las personas que quieren hacer un system()con privilegios elevados (que, por supuesto, no deberían hacerlo) terminan haciendo un setresuid()antes que es mucho peor ya que el shell no sabe que es suid, así que no active el modo donde no confía en su entorno.
Stéphane Chazelas
8

Probablemente, el shell está cambiando su ID de usuario efectiva de nuevo a la ID de usuario real como parte de su inicio por alguna razón u otra. Puede verificar esto agregando:

/* needs _GNU_SOURCE; non-Linux users see setregid/setreuid instead */
uid_t euid = geteuid(), egid = getegid();
setresgid(egid, egid, egid);
setresuid(euid, euid, euid);

antes de tu system(). (En realidad, incluso en Linux, probablemente solo necesite configurar los reales; los guardados deberían estar bien para dejarlos solos. Esto es solo fuerza bruta para depurar. Dependiendo de por qué está configurado id, es posible que necesite para guardar las ID reales en algún lugar también).

[Además, si esto no es solo un ejercicio para aprender cómo funciona setid, entonces hay muchos problemas de seguridad de los que preocuparse, especialmente cuando se llama a un shell. Hay muchas variables de entorno, por ejemplo, que afectan el comportamiento del shell. Prefiere un enfoque ya existente como sudosi fuera posible.]

derobert
fuente
Me concentré en por qué cambió, mientras que usted proporcionó la forma de evitar el problema. +1
AB
Por supuesto, si realmente necesita un lugar para guardar las ID reales, la ID guardada es un lugar muy conveniente para hacerlo. Especialmente si los ID efectivos no son root: root.
Kevin