28

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

 4 years ago
source link: https://github.com/DavidBuchanan314/dlinject
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

dlinject.py

Inject a shared library (i.e. arbitrary code) into a live linux process, without ptrace. Inspired by Cexigua and linux-inject , among other things.

Usage

Note: currently requires the python3 branch of pwntools . It's a fairly heavyweight dependency that I only use a few features of, so I might be able to remove it in the future.

usage: dlinject.py [-h] [--nostop] pid lib.so

Inject a shared library into a live process.

positional arguments:
  pid         target pid
  lib.so      Path of the shared library to load (note: must be relative to the target process's cwd, or absolute)

optional arguments:
  -h, --help  show this help message and exit
  --nostop    Don't stop the target process prior to injection (race condition-y, but avoids potential side-effects
              of SIGSTOP)

Why?

  • Because I can.

  • There are various anti-ptrace techniques , which this evades by simply not using ptrace.

  • Using LD_PRELOAD can sometimes be fiddly or impossible, if the process you want to inject into is spawned by another process with a clean environment.

How it Works

  • Send the stop signal to the target process. (optional)

  • Locate the _dl_open() symbol.

  • Retreive RIP and RSP via /proc/[pid]/syscall .

  • Make a backup of part of the stack, and the code we're about to overwrite with our shellcode, by reading from /proc/[pid]/mem .

  • Generate primary and secondary shellcode buffers.

  • Insert primary shellcode at RIP , by writing to /proc/[pid]/mem .

  • The primary shellcode:

    mmap()
    
  • The secondary shellcode:

    _dl_open()
    SIGSTOP
    

Limitations:

  • Sending SIGSTOP may cause unwanted side-effects, for example if another thread is waiting on waitpid() . The --nostop option avoids this, but introduces race conditions.

  • I'm not entirely sure how this will interact with complex multi-threaded applications. There's certainly potential for breakage.

  • x86-64 Linux only (for now - 32-bit support could potentially be added).

  • Requires root, or relaxed YAMA configuration ( echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope is useful when testing).

  • If the target process is sandboxed (e.g. seccomp filters), it might not have permission to mmap() the second stage shellcode, or to dlopen() the library.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK