Show HN: dlinject.py – Inject a .so into a running Linux process, without ptrace

  • The tl;dr of the technique is to use /proc/$pid/mem to overwrite the stack. (Since you don't have direct control of the instruction pointer this way, there's some complexity in loading shellcode somewhere and having the process return to it to get it to usefully execute your code, much like an actual stack-corruption exploit.)

    On a normal Linux system, /proc/$pid/mem is protected by the same kernel permission check as ptrace, and a Linux security module like Yama, the thing that disables ptracing unrelated processes on Ubuntu etc., will also block this tool (which the README mentions). It seems like it's mostly useful for cases where people are blocking the ptrace syscall (like Docker's default syscall filter, maybe?) and not loading an LSM.

    Cool demonstration that blocking the ptrace syscall isn't sufficient. By the way, blocking /proc too isn't sufficient either: there's the process_vm_writev and process_vm_readv syscalls that work like writing/reading /proc/$pid/mem. I think it's harder to write a robust tool using only those syscalls, but I wouldn't bet on it being impossible.

    If you really want to do syscall filtering to confine an untrusted process (as opposed to reducing attack surface from potential bugs in otherwise-permissible syscalls, which is I think Docker's goal), you need to start from empty and allow syscalls instead of starting from full and blocking them. Alternatively, maybe just run the untrusted code as another user account or something.

  • I'm new to the cyber world and have a few questions about how this works under the hood since my exposure to memory management is really minimal. Why did we have to mess with this shellcode within the injector (dlinject.py) rather than just somehow identifying the PID of the target and loading the injected code directly? Is it not possible via some simply python call to perform the injection, and is that why we're playing with the x86?

    Also, would this work on systems with ASLR?

    Could malicious code be obfuscated, transformed, and then subsequently injected into a process like explorer with this dlinject.py? What are our limitations here?

  • If you want to avoid the side effects of SIGSTOP, you can put the target process in a freezer cgroup instead.

  • What are the circumstances in which someone would be doing something like this?