Bypass FS protections: read-only / no-exec / Distroless
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
If you are interested in hacking career and hack the unhackable - we are hiring! (se requiere polaco fluido escrito y hablado).
In the following videos you can find the techniques mentioned in this page explained more in depth:
Es cada vez más común encontrar máquinas linux montadas con protección de sistema de archivos de solo lectura (ro), especialmente en contenedores. Esto se debe a que ejecutar un contenedor con un sistema de archivos ro es tan fácil como establecer readOnlyRootFilesystem: true
en el securitycontext
:
Sin embargo, incluso si el sistema de archivos está montado como ro, /dev/shm
seguirá siendo escribible, por lo que es falso que no podamos escribir nada en el disco. Sin embargo, esta carpeta estará montada con protección no-ejecución, por lo que si descargas un binario aquí no podrás ejecutarlo.
Desde la perspectiva de un equipo rojo, esto hace que sea complicado descargar y ejecutar binarios que no están en el sistema ya (como puertas traseras o enumeradores como kubectl
).
Ten en cuenta que mencioné binarios, puedes ejecutar cualquier script siempre que el intérprete esté dentro de la máquina, como un script de shell si sh
está presente o un script de python si python
está instalado.
Sin embargo, esto no es suficiente para ejecutar tu puerta trasera binaria u otras herramientas binarias que puedas necesitar ejecutar.
Si deseas ejecutar un binario pero el sistema de archivos no lo permite, la mejor manera de hacerlo es ejecutándolo desde la memoria, ya que las protecciones no se aplican allí.
Si tienes algunos motores de script potentes dentro de la máquina, como Python, Perl o Ruby, podrías descargar el binario para ejecutarlo desde la memoria, almacenarlo en un descriptor de archivo de memoria (create_memfd
syscall), que no estará protegido por esas protecciones y luego llamar a una exec
syscall indicando el fd como el archivo a ejecutar.
Para esto, puedes usar fácilmente el proyecto fileless-elf-exec. Puedes pasarle un binario y generará un script en el lenguaje indicado con el binario comprimido y codificado en b64 con las instrucciones para decodificar y descomprimirlo en un fd creado llamando a create_memfd
syscall y una llamada a la exec syscall para ejecutarlo.
Esto no funciona en otros lenguajes de scripting como PHP o Node porque no tienen ninguna default way to call raw syscalls desde un script, por lo que no es posible llamar a create_memfd
para crear el memory fd para almacenar el binario.
Además, crear un fd regular con un archivo en /dev/shm
no funcionará, ya que no se te permitirá ejecutarlo porque se aplicará la protección no-ejecución.
DDexec / EverythingExec es una técnica que te permite modificar la memoria de tu propio proceso sobrescribiendo su /proc/self/mem
.
Por lo tanto, controlando el código ensamblador que se está ejecutando en el proceso, puedes escribir un shellcode y "mutar" el proceso para ejecutar cualquier código arbitrario.
DDexec / EverythingExec te permitirá cargar y ejecutar tu propio shellcode o cualquier binario desde memoria.
Para más información sobre esta técnica, consulta el Github o:
DDexec / EverythingExecMemexec es el siguiente paso natural de DDexec. Es un DDexec shellcode demonizado, por lo que cada vez que quieras ejecutar un binario diferente no necesitas relanzar DDexec, solo puedes ejecutar el shellcode de memexec a través de la técnica DDexec y luego comunicarte con este demonio para pasar nuevos binarios para cargar y ejecutar.
Puedes encontrar un ejemplo de cómo usar memexec para ejecutar binarios desde un reverse shell de PHP en https://github.com/arget13/memexec/blob/main/a.php.
Con un propósito similar al de DDexec, la técnica memdlopen permite una manera más fácil de cargar binarios en memoria para ejecutarlos más tarde. Podría incluso permitir cargar binarios con dependencias.
Los contenedores distroless contienen solo los componentes mínimos necesarios para ejecutar una aplicación o servicio específico, como bibliotecas y dependencias de tiempo de ejecución, pero excluyen componentes más grandes como un gestor de paquetes, shell o utilidades del sistema.
El objetivo de los contenedores distroless es reducir la superficie de ataque de los contenedores al eliminar componentes innecesarios y minimizar el número de vulnerabilidades que pueden ser explotadas.
En un contenedor distroless, es posible que ni siquiera encuentres sh
o bash
para obtener un shell regular. Tampoco encontrarás binarios como ls
, whoami
, id
... todo lo que normalmente ejecutas en un sistema.
Por lo tanto, no podrás obtener un reverse shell o enumerar el sistema como lo haces normalmente.
Sin embargo, si el contenedor comprometido está ejecutando, por ejemplo, un flask web, entonces python está instalado, y por lo tanto puedes obtener un reverse shell de Python. Si está ejecutando node, puedes obtener un reverse shell de Node, y lo mismo con casi cualquier lenguaje de scripting.
Usando el lenguaje de scripting podrías enumerar el sistema utilizando las capacidades del lenguaje.
Si no hay protecciones de read-only/no-exec
, podrías abusar de tu reverse shell para escribir en el sistema de archivos tus binarios y ejecutarlos.
Sin embargo, en este tipo de contenedores, estas protecciones generalmente existirán, pero podrías usar las técnicas de ejecución en memoria anteriores para eludirlas.
Puedes encontrar ejemplos sobre cómo explotar algunas vulnerabilidades RCE para obtener reverse shells de lenguajes de scripting y ejecutar binarios desde la memoria en https://github.com/carlospolop/DistrolessRCE.
Si estás interesado en una carrera de hacking y hackear lo inhackeable - ¡estamos contratando! (se requiere polaco fluido escrito y hablado).
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)