LD_PRELOAD vs. /etc/ld.so.preload

Ever wondered what those very first few syscalls where all about when you watched a program starting with strace? For me it was always some kind of static noise the loader generates, so was of no real interest. But then, one day, I looked a little closer and noticed a weird line testing for the existence of a file called /etc/ld.so.preload. I haven’t yet encountered a system that had such a file. The name was promising so I was curios what that file would be all about and started looking at the glibc sources searching for the corresponding code that does this test. Found it, like expected, in the loader code (elf/rtld.c). It is testing for the existence of that file and if it does it’ll load all shared objects listed in there just like setting the environment variable LD_PRELOAD would do. But wait! LD_PRELOAD was evil when combined with suid binaries so it will be ignored by the loader. That’s because otherwise you could abuse those binaries to raise your privileges by preloading some code that spawns a shell — e.g. by hooking __libc_start_main(). However, those restrictions do not apply for this file. The loader will bravely load the shared objects listed in /etc/ld.so.preload even for suid binaries. So if someone manages to create such a file he effectively owns the system. But since only root should be able to create files under /etc it should be safe for most systems. Anyway, good to know, by using this technique, you can hook your suid programs and for example get a root shell when needed by preloading a shared library that hooks setuid() with a wrapper that tests for a trigger (e.g. an environment variable) and execve()’s /bin/sh for you. Otherwise the wrapper just forwards the setuid() syscall. Now you just have to set your trigger, ping localhost and you’re root. 🙂 On the other hand you can do serious things with it like analysing or instrumenting suid binaries you have no source code of. It’s an elegant way to dig into the program without actually touching the binary.


3 Responses to “LD_PRELOAD vs. /etc/ld.so.preload”

  1. 1 xxor December 15, 2009 at 8:02 pm

    try xocopy.c – it`s easyer

    • 2 minipli December 15, 2009 at 10:11 pm

      I guess xocopy is meant for a different kind of problem — when you cannot even read the binary you’re executing. It’s generating a copy of the file by reading it’s memory representation using ptrace(2). By preloading shared objects instead — either via LD_PRELOAD or /etc/ld.so.preload — you can hook any library function the binary is using which is quite a different and much more powerful functionality. For example, you could preload a shared object containing the symbol __libc_start_main and do exactly what xocopy is doing — but without ptrace(2). Because you’re executing code in the context of the process itself, you can make the copy by direct memory access instead of using ptrace(2) to poke it byte by byte.

  1. 1 Snoopy - How to - the command monitor logger Ive been hoping for exists! | kossboss Trackback on February 23, 2014 at 5:33 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: