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:
It's more and more common to find linux machines mounted with read-only (ro) file system protection, specially in containers. This is because to run a container with ro file system is as easy as setting readOnlyRootFilesystem: true
in the securitycontext
:
However, even if the file system is mounted as ro, /dev/shm
will still be writable, so it's fake we cannot write anything in the disk. However, this folder will be mounted with no-exec protection, so if you download a binary here you won't be able to execute it.
From a red team perspective, this makes complicated to download and execute binaries that aren't in the system already (like backdoors o enumerators like kubectl
).
Note that I mentioned binaries, you can execute any script as long as the interpreter is inside the machine, like a shell script if sh
is present or a python script if python
is installed.
However, this isn't just enough to execute your binary backdoor or other binary tools you might need to run.
If you want to execute a binary but the file system isn't allowing that, the best way to do so is by executing it from memory, as the protections doesn't apply in there.
If you have some powerful script engines inside the machine, such as Python, Perl, or Ruby you could download the binary to execute from memory, store it in a memory file descriptor (create_memfd
syscall), which isn't going to be protected by those protections and then call a exec
syscall indicating the fd as the file to execute.
For this you can easily use the project fileless-elf-exec. You can pass it a binary and it will generate a script in the indicated language with the binary compressed and b64 encoded with the instructions to decode and decompress it in a fd created calling create_memfd
syscall and a call to the exec syscall to run it.
This doesn't work in other scripting languages like PHP or Node because they don't have any default way to call raw syscalls from a script, so it's not possible to call create_memfd
to create the memory fd to store the binary.
Moreover, creating a regular fd with a file in /dev/shm
won't work, as you won't be allowed to run it because the no-exec protection will apply.
DDexec / EverythingExec is a technique that allows you to modify the memory your own process by overwriting its /proc/self/mem
.
Therefore, controlling the assembly code that is being executed by the process, you can write a shellcode and "mutate" the process to execute any arbitrary code.
DDexec / EverythingExec will allow you to load and execute your own shellcode or any binary from memory.
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)