hacktricks/linux-hardening/bypass-linux-shell-restrictions/ddexec.md
carlospolop 466ebcbb16 f
2023-06-05 20:30:03 +02:00

7.4 KiB

DDexec

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Contexto

En Linux, para ejecutar un programa, este debe existir como archivo y debe ser accesible de alguna manera a través de la jerarquía del sistema de archivos (esto es simplemente cómo funciona execve()). Este archivo puede residir en el 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, lo que facilita la detección de amenazas y herramientas de atacantes o evitar que intenten ejecutar cualquier cosa de ellos en absoluto (por ejemplo, no permitir que los usuarios sin privilegios 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...

Dependencias

El script final depende de las siguientes herramientas para funcionar, deben ser accesibles en el sistema que estás atacando (por defecto las encontrarás en todas partes):

dd
bash | zsh | ash (busybox)
head
tail
cut
grep
od
readlink
wc
tr
base64

La técnica

Si eres capaz de modificar arbitrariamente la memoria de un proceso, entonces puedes tomar el control de él. Esto se puede utilizar para secuestrar un proceso ya existente y reemplazarlo con otro programa. Podemos lograr esto utilizando la llamada al sistema ptrace() (que requiere que tengas 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 el root y el propietario del programa del archivo pueden modificarlo.
  • ASLR.
  • Si intentamos leer o escribir en una dirección que no está 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... de esta manera, los procesos secundarios que usen ese descriptor de archivo 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 del 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.

Con más detalle

Los pasos son relativamente fáciles y no requieren ningún tipo de experiencia para entenderlos:

  • Analiza el binario que queremos ejecutar y el cargador para averiguar qué mapeos necesitan. Luego crea un "código de shell" que realizará, en términos generales, los mismos pasos que el kernel hace en cada llamada a execve():
    • Crea dichos mapeos.
    • Lee los binarios en ellos.
    • Configura los permisos.
    • Finalmente inicializa la pila con los argumentos para el programa y coloca el vector auxiliar (necesario para el cargador).
    • Salta al cargador y deja que haga el resto (cargar bibliotecas necesarias para el programa).
  • Obtén del archivo syscall la dirección a la que el proceso volverá después de la llamada al sistema que está ejecutando.
  • Sobrescribe ese lugar, que será ejecutable, con nuestro código de shell (a través de mem podemos modificar páginas no escribibles).
  • Pasa 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

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥