Bypass FS protections: read-only / no-exec / Distroless
Si estás interesado en una carrera de hacking y hackear lo imposible - ¡estamos contratando! (se requiere dominio del polaco escrito y hablado).
Videos
En los siguientes videos puedes encontrar las técnicas mencionadas en esta página explicadas más a fondo:
Escenario de solo lectura / sin ejecución
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 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 sin 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 (como puertas traseras o enumeradores como kubectl
).
Salto más fácil: Scripts
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.
Saltos de Memoria
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í.
Salto de llamada al sistema FD + exec
Si tienes 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 llamada al sistema exec
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 decodificarlo y descomprimirlo en un fd creado llamando a la llamada al sistema create_memfd
y una llamada al sistema exec para ejecutarlo.
Esto no funciona en otros lenguajes de script como PHP o Node porque no tienen una forma predeterminada de llamar a llamadas de sistema crudas desde un script, por lo que no es posible llamar a create_memfd
para crear el fd de memoria 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 debido a que se aplicará la protección sin ejecución.
DDexec / EverythingExec
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 de ensamblaje que está siendo ejecutado por 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 la memoria.
Para obtener más información sobre esta técnica, consulta el Github o:
pageDDexec / EverythingExecMemExec
Memexec es el siguiente paso natural de DDexec. Es un shellcode demonizado de DDexec, por lo que cada vez que desees ejecutar un binario diferente no necesitas volver a lanzar DDexec, simplemente 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 shell inverso de PHP en https://github.com/arget13/memexec/blob/main/a.php.
Memdlopen
Con un propósito similar a DDexec, la técnica memdlopen permite una forma más fácil de cargar binarios en memoria para luego ejecutarlos. Incluso podría permitir cargar binarios con dependencias.
Bypass de Distroless
¿Qué es Distroless?
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 la cantidad de vulnerabilidades que pueden ser explotadas.
Shell Inverso
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 sueles ejecutar en un sistema.
Por lo tanto, no podrás obtener un shell inverso o enumerar el sistema como sueles hacerlo.
Sin embargo, si el contenedor comprometido está ejecutando, por ejemplo, una aplicación web flask, entonces Python está instalado, y por lo tanto puedes obtener un shell inverso de Python. Si está ejecutando node, puedes obtener un shell inverso de Node, y lo mismo con la mayoría de los lenguajes de script.
Usando el lenguaje de script podrías enumerar el sistema utilizando las capacidades del lenguaje.
Si no hay protecciones de solo lectura/sin ejecución
podrías abusar de tu shell inverso 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 de memoria anteriores para evadirlas.
Puedes encontrar ejemplos de cómo explotar algunas vulnerabilidades de RCE para obtener shells inversos de lenguajes de script y ejecutar binarios desde la memoria en https://github.com/carlospolop/DistrolessRCE.
Si estás interesado en una carrera de hacking y hackear lo imposible - ¡estamos contratando! (se requiere dominio del polaco escrito y hablado).
Última actualización