# tl;dr This is a collection of various Linux evasion primitives, mainly meant to be used in loaders in such. I make no claim of inventing any of them, this is more of a checklist of features to implement in custom loaders. A PoC of some of the techniques is available @ https://github.com/zimnyaa/LEOPARDSEAL This post focuses on usermode techniques and only briefly touches rootkit-like functionality. A lot of this stuff is also covered in an excellent presentation [here](https://youtu.be/sqAA-qBnKTM). # LD_PRELOAD from memory `LD_PRELOAD` is the bread-and-butter of remote code injection in Linux, as it provides a native primitive to sideload dynamic libraries into other processes. During ELF execution, the `LD_PRELOAD` .so library will get loaded into memory before execution starts. In addition, LD_PRELOAD may point to a filesystem location that is only in RAM, such as temporary memfs filesystems or the file descriptior created by the `memfd_create` Linux syscall. This is why the most frequently used approach to process injection in Linux is: ```j memfd_create -> write .so to FD -> EXECVE (env="LD_PRELOAD=/proc/{pid}/fd/{memfd}") ``` ## run-at-load If you want to hijack execution of the process completely, it is possible to ask the loader to execute code when the custom library is loaded, which is before the rest of the process is. The C template for this is: ```c #include <stdlib.h> static void init(int argc, char **argv, char **envp) { unsetenv("LD_PRELOAD"); unsetenv("LD_PARAMS"); somefunction(); } __attribute__((section(".init_array"), used)) static typeof(init) *init_p = init; ``` If you want to use a `sliver` .SO for this, just use `--run-at-load`. ## chaining run-at-load LD_PRELOADS By compiling your custom loader as an .so and preloading it as well, it is possible to spoof entire process trees: ```j root@kali:~# ps -aux --forest ... truncated ... root 3364533 0.0 2.0 92728 81032 ? S May09 0:35 /usr/bin/zsh root 3364536 0.0 0.4 1238444 19940 ? Sl May09 13:01 \_ /bin/ls <-- THIS IS SLIVER root 3364537 0.0 0.4 1238444 20124 ? Sl May09 12:31 \_ /bin/ls <-- THIS IS SLIVER ... truncated ... ``` ## function hooking It is also possible to use LD_PRELOAD for its (almost) intended purpose, which is function hooking. Filtering function output to hide preloaded libraries, files and file descriptors, ports, etc is more rootkit territory, and I suggest you take a look at https://www.intezer.com/blog/research/new-linux-threat-symbiote/ for inspiration. For our execution purposes, though, we can just proxy calls to some libc function while creating a new thread with the payload. # plain old shellcode execution You can also, of course, just do that: ```c (int(*)())code(); ``` # forking Sometimes, several rounds of delayed forks, especially when the payload consists of several stages, may make runtime detection more difficult. I just do this: ```nim forkpid = syscall(FORK) if forkpid != 0: echo forkpid quit(0) sleep(1000) ``` But it is possible to make it a little bit more fancy. What is interesting is that because forking creates a fresh copy of the process, when forking *inside* a preloaded process with run-at-load *LD_PRELOAD*, the payload will be executed in the new process as well. # ddexec / memory overwriting It is also possible to execute code by writing to memory directly, which requires parsing ASLR. There are several great approaches outlined in the [Sektor7](https://blog.sektor7.net/#!res/2018/pure-in-memory-linux.md) post about Linux userland shellcode execution. The technique of using `dd` to overwrite its own process memory has been almost independently implemented in https://github.com/arget13/DDexec Other approaches highlighted in the Sektor7 presentation above are: - GDB [![](https://blog.sektor7.net/res/2018/img/gdb2.png)](https://blog.sektor7.net/res/2018/img/gdb2.png) - Injecting `memfd_create` shellcode into a remote process, writing into it directly, and calling. - Python `ctypes` shellcode execution (more on Python below) # signaling Lots of `run-at-load` .so files are suspicious and easy to sandbox, so it is possible to use Linux IPC mechanisms such as the `signal` syscall to trigger execution after a delay instead. The simple implementation may be: ``` proc NimMain() {.cdecl, importc.} func myexport*() {.exportc, cdecl, dynlib .} = {.cast(noSideEffect).}: NimMain() setControlCHook(loaderfunc) while true: sleep(1000) ``` In addition, other, more complex IPC mechanisms, like sockets or SHM+semaphores could be used, with the added bonus that the shellcode/.so file could be transferred via them to avoid loading them into the process memory outright. # dynamic languages On any stage of the multistage loader, dynamic language runtimes like `Lua` or `Python` could be embedded to do most anything that could be done natively. With the added advantage that dynamic code can be more easily staged, this approach serves well to help with dechaining the execution process.