DDexec / EverythingExec
Last updated
Last updated
Aprende y practica Hacking en AWS: HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
En Linux, para ejecutar un programa, este debe existir como un archivo y debe ser accesible de alguna manera a través de la jerarquía del sistema de archivos (así es como funciona execve()
). Este archivo puede residir en disco o en la memoria RAM (tmpfs, memfd), pero necesitas una ruta de archivo. Esto ha hecho muy fácil controlar lo que se ejecuta en un sistema Linux, facilita detectar amenazas y herramientas de atacantes o prevenir que intenten ejecutar algo propio en absoluto (por ejemplo, no permitir que usuarios no privilegiados coloquen archivos ejecutables en cualquier lugar).
Pero esta técnica está aquí para cambiar todo esto. Si no puedes iniciar el proceso que deseas... entonces secuestras uno que ya existe.
Esta técnica te permite burlar técnicas de protección comunes como solo lectura, noexec, lista blanca de nombres de archivo, lista blanca de hash...
El script final depende de las siguientes herramientas para funcionar, estas deben ser accesibles en el sistema que estás atacando (por defecto las encontrarás en todas partes):
Si puedes modificar arbitrariamente la memoria de un proceso, entonces puedes tomar el control de él. Esto se puede utilizar para secuestrar un proceso existente y reemplazarlo con otro programa. Podemos lograr esto ya sea usando la llamada al sistema ptrace()
(lo cual requiere tener la capacidad de ejecutar llamadas al sistema o tener gdb disponible en el sistema) o, de manera más interesante, escribiendo en /proc/$pid/mem
.
El archivo /proc/$pid/mem
es un mapeo uno a uno de todo el espacio de direcciones de un proceso (por ejemplo, desde 0x0000000000000000
hasta 0x7ffffffffffff000
en x86-64). Esto significa que leer o escribir en este archivo en un desplazamiento x
es lo mismo que leer o modificar el contenido en la dirección virtual x
.
Ahora, tenemos cuatro problemas básicos a enfrentar:
En general, solo root y el propietario del programa del archivo pueden modificarlo.
ASLR.
Si intentamos leer o escribir en una dirección no mapeada en el espacio de direcciones del programa, obtendremos un error de E/S.
Estos problemas tienen soluciones que, aunque no son perfectas, son buenas:
La mayoría de los intérpretes de shell permiten la creación de descriptores de archivos que luego serán heredados por los procesos secundarios. Podemos crear un descriptor de archivo que apunte al archivo mem
de la shell con permisos de escritura... por lo tanto, los procesos secundarios que utilicen ese descriptor podrán modificar la memoria de la shell.
ASLR ni siquiera es un problema, podemos verificar el archivo maps
de la shell o cualquier otro de procfs para obtener información sobre el espacio de direcciones del proceso.
Entonces necesitamos hacer lseek()
sobre el archivo. Desde la shell esto no se puede hacer a menos que se use el infame dd
.
Los pasos son relativamente fáciles y no requieren ningún tipo de experiencia para entenderlos:
Analizar el binario que queremos ejecutar y el cargador para averiguar qué mapeos necesitan. Luego crear un "código" de "shell" que realizará, en términos generales, los mismos pasos que el kernel hace en cada llamada a execve()
:
Crear dichos mapeos.
Leer los binarios en ellos.
Configurar los permisos.
Finalmente inicializar la pila con los argumentos del programa y colocar el vector auxiliar (necesario por el cargador).
Saltar al cargador y dejar que haga el resto (cargar las bibliotecas necesarias para el programa).
Obtener del archivo syscall
la dirección a la que el proceso regresará después de la llamada al sistema que está ejecutando.
Sobrescribir ese lugar, que será ejecutable, con nuestro código de "shell" (a través de mem
podemos modificar páginas no escribibles).
Pasar el programa que queremos ejecutar a la entrada estándar del proceso (será leído()
por dicho código de "shell").
En este punto, depende del cargador cargar las bibliotecas necesarias para nuestro programa y saltar a él.
Echa un vistazo a la herramienta en https://github.com/arget13/DDexec
Existen varias alternativas a dd
, una de las cuales, tail
, es actualmente el programa predeterminado utilizado para lseek()
a través del archivo mem
(que era el único propósito de usar dd
). Dichas alternativas son:
Al establecer la variable SEEKER
, puedes cambiar el buscador utilizado, por ejemplo:
Si encuentras otro buscador válido que no esté implementado en el script, aún puedes usarlo configurando la variable SEEKER_ARGS
:
Bloquea esto, EDRs.
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)