En los sistemas Linux, para ejecutar un programa es necesario que el archivo correspondiente esté disponible en algún punto del sistema de archivos. Esto permite que el sistema detecte y controle fácilmente qué se está ejecutando, ya que cualquier programa necesita tener un path o ruta específica accesible, ya sea en disco o en memoria (como en tmpfs
o memfd
). Esta configuración facilita la tarea de monitorización y restricción de actividades sospechosas, ya que, por ejemplo, es posible bloquear a usuarios no privilegiados de crear archivos ejecutables en lugares no autorizados del sistema.
Pero, ¿qué pasa si podemos iniciar un proceso sin necesidad de un archivo específico? Aquí es donde entra en juego DDexec, una herramienta que permite secuestrar procesos existentes para reemplazarlos con otros programas, burlando así varias protecciones comunes.
DDexec es una herramienta que permite ejecutar programas mediante la manipulación directa de la memoria de un proceso. Esta técnica permite evitar las limitaciones habituales de permisos de ejecución, listados de control de nombres de archivos y whitelisting de hashes, entre otros. La clave de DDexec radica en la capacidad de sobreescribir procesos ya existentes en memoria y hacer que estos ejecuten otros programas.
Para que la técnica funcione, es necesario que ciertas herramientas básicas estén disponibles en el sistema objetivo, aunque la mayoría de estos comandos suelen encontrarse en cualquier distribución de Linux:
dd
bash
, zsh
, ash
(en busybox)
head
, tail
, cut
, grep
, od
, readlink
, wc
, tr
, base64
Estas herramientas son fundamentales para manejar la memoria del sistema y realizar las modificaciones necesarias en los procesos activos.
La técnica de DDexec se basa en la modificación directa de la memoria de un proceso activo. Esto se puede realizar de dos formas:
1. Syscall ptrace(): Utiliza el sistema de llamadas ptrace()
(también usado por gdb
) para controlar y modificar el comportamiento de un proceso. Este método requiere que el atacante tenga acceso para ejecutar syscalls o que gdb
esté disponible en el sistema.
2. Escritura en /proc/$pid/mem: Este método es más interesante, ya que permite modificar directamente el espacio de direcciones de un proceso a través del archivo /proc/$pid/mem
. Este archivo mapea todo el espacio de direcciones de un proceso, lo que permite leer o escribir en cualquier posición de memoria accesible.
Para ejecutar esta técnica, es necesario superar varios obstáculos:
Para superar estos problemas, existen soluciones que permiten que esta técnica funcione de manera relativamente sencilla:
/proc
para obtener información sobre la disposición de las direcciones del proceso.
dd
, que permite realizar movimientos precisos en el archivo /proc/$pid/mem
.
A continuación, se presentan los pasos principales para ejecutar un proceso mediante la técnica de DDexec:
1. Análisis del Binario y el Loader: Primero se debe analizar el binario que se quiere ejecutar para identificar los mapeos necesarios. Después, se crea un shellcode que replica los pasos que el sistema realiza con cada llamada execve()
.
2. Creación de Mapeos y Lectura del Binario: Se crean los mapeos de memoria necesarios, se cargan los binarios en ellos y se configuran los permisos correspondientes.
3. Inicialización de la Pila y el Vector Auxiliar: Se configura la pila con los argumentos necesarios y se coloca el vector auxiliar requerido por el cargador.
4. Sobreescritura de Memoria con Shellcode: Finalmente, se obtiene del archivo syscall la dirección a la que regresará el proceso después de la syscall y se sobreescribe ese lugar con el shellcode. Desde aquí, se pasa el programa deseado al stdin
del proceso, permitiendo que el cargador ejecute el programa.
EverythingExec introduce una serie de alternativas al uso de dd
para la manipulación de memoria. Por ejemplo, tail
es una opción popular para realizar lseek()
a través del archivo de memoria /proc/$pid/mem
. Las herramientas alternativas incluyen:
tail
hexdump
cmp
xxd
Esto permite que el usuario elija entre diferentes herramientas para navegar en la memoria del proceso. Además, se puede configurar la variable SEEKER
para seleccionar el buscador preferido, y SEEKER_ARGS
para definir argumentos específicos según el programa que se quiera utilizar.
SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
En este ejemplo, se configura xxd
como el buscador, especificando los argumentos necesarios para desplazarse a la posición correcta en memoria.
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
La técnica de DDexec y sus variantes, como EverythingExec, representan un avance notable en las capacidades de evasión en sistemas Linux, permitiendo a los atacantes reemplazar procesos en memoria sin necesidad de crear nuevos archivos ejecutables. Esto evade muchas de las técnicas de protección convencionales como los permisos de ejecución y los controles de integridad. Aunque es una técnica avanzada y compleja, conocer su funcionamiento y limitaciones es fundamental para aquellos en el campo de la seguridad que desean proteger sistemas críticos.
Jorge García
Fullstack developer