![]() |
|
Tutorial [C] Using LD_PRELOAD to overwrite Linux syscalls - Printable Version +- Sinisterly (https://sinister.ly) +-- Forum: Coding (https://sinister.ly/Forum-Coding) +--- Forum: C, C++, & Obj-C (https://sinister.ly/Forum-C-C-Obj-C) +--- Thread: Tutorial [C] Using LD_PRELOAD to overwrite Linux syscalls (/Thread-Tutorial-C-Using-LD-PRELOAD-to-overwrite-Linux-syscalls) |
[C] Using LD_PRELOAD to overwrite Linux syscalls - lola - 08-09-2014 I wrote this to share what I was learning, I'm not a fucking expert, criticize me all you want, and since I don't have much to share here, have this. Ugh, luakit crashed so I'm having to rewrite this entire tutorial from scratch, I'm going to try and detail this as much as possible. What is LD_PRELOAD? Exactly what it sounds like, LD_PRELOAD points to a shared library and loads it before any other libraries, allowing you to overwrite predefined libraries or instructions before anything is actually executed. LD_PRELOAD is present in many modern rootkits such as Azazel and Jynx2, I'll leave the github pages for Azazel and Jynx2 at the bottom of this guide. Why LD_PRELOAD? As I said before, LD_PRELOAD loads a target shared library before any other library, thus being somewhat secure and easy to implement. How does this help? I'm hoping that you have a tiny idea of how rootkits operate and how they work and whatnot. Well using LD_PRELOAD you can overwrite syscalls before they're actually defined by the kernel itself, so you can prevent a syscall like open() from opening a specific file. How are these libraries installed? Let's take a look at the install script I made for panther and procedurally break down each step it goes through to make this easy. ![]()
My script is just a bash script replication of Azazel's Makefile, nothing else. Let's take a look at how you overwrite a syscall. First, you need to know what syscall you're wanting to overwrite, in this case, let's make any non-directory file starting with "__" in its name unable to be removed by rm. To do this, we need to find out what calls rm references, to do this, we'll use the tool "ltrace", similar to strace but it traces library calls and not syscalls. Syntax of ltrace is simple, "ltrace /path/to/file optional arguments", and any calls are printed to the screen. Let's find out what calls rm references by using ltrace and removing an empty file. ![]() Fun things start to happen at the faccessat() and unlinkat() calls, if you man unlinkat, you see that it takes 3 arguments, a file descriptor, a pathname to unlink, and flags, and it is this exact call that we need to overwrite to disallow any user from removing our file. To overwrite a syscall, you need to create C source file, defined _GNU_SOURCE, include any includes mentioned on your target call's and copy the construct on the man page too. It's simple, here's an example. ![]() Notice how I kept the argument names the same as that from the man page. Okay, sure, the syscall has been overwritten now, but if you compile and execute this via a shared library + LD_PRELOAD, you won't be able to remove any files, that's not what we want. If you want to overwrite the old syscall with a new one that calls the old syscall (if that makes any sense), we can use dlsym, this was linked earlier by the -l argument in the installation script. dl* are "interfaces to the dynamic linking library". Read more about it here: http://linux.die.net/man/3/dlsym Using dlsym() you can call the original syscall even after you overwrite it. An example as follows. ![]() Using typeof() automatically grabs the data type of target call and then creates it using that said data type. Keep note of me passing the arguments from the new call into the old call too. The RTLD_NEXT flag just reserves the call for future use. Now if you were to compile this and execute it via a shared library + LD_PRELOAD, the new syscall will be overwritten and it will return the old syscall - if you want to make sure that the new syscall is indeed being called, you can use printf to display a significant message when a file is removed. Okay, so you've overwritten a syscall and you're returning the old syscall into the new one, but this isn't very beneficial as to what we want, which is to remove the ability to remove files that start with "__". To do this, we'll use the header include "stdbool", which = standard boolean, simple stuff, and strncmp, which could be your equivalent to string.startsWith() in a higher level language like Java. ![]() What the boolean type isHidden() is doing is checking if the supplied char a starts with MAGIC_STRING, in this case MAGIC_STRING was defined as "__", and if a starts with "__", the boolean returns true and thus the char is hidden, else the boolean returns false and the supplied char is not that of a hidden file. Now if you compile and execute this as a shared library via LD_PRELOAD, all users, root and non-root, will be unable to remove any files starting with "__". Also make sure to keep note that I created a global boolean type to determine if a char starts with the magic string, as large projects such as rootkits often do this check many times. You can do this with literally any syscalls, and remember to use typeof() when recreating a syscall. Azazel github: https://github.com/chokepoint/azazel Jynx2: https://github.com/chokepoint/Jynx2 RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - Edward - 08-09-2014 I hate being honest. This tutorial interests me a lot, but I don't know a whole lot about C. I will have to read up on it more. RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - chronical - 08-09-2014 I pretty much just skimmed through the whole damn thing, but this is a very interesting tutorial. I'm sure this is useful in rootkits. I'll probably read it in full detail another time. RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - Dyme - 08-10-2014 ld_preload kits are the easiest shit to rm... I'm surprised they're still so popular. RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - lola - 08-10-2014 (08-10-2014, 12:28 AM)Dyme Wrote: ld_preload kits are the easiest shit to rm... I'm surprised they're still so popular. How would you rm a ld_preload kit? I'm still learning and I wouldn't mind your input. RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - Dyme - 08-10-2014 (08-10-2014, 12:38 AM)lola Wrote: How would you rm a ld_preload kit? I'm still learning and I wouldn't mind your input. Azazel, for example: https://twitter.com/grsecurity/status/434876038745579520 RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - Oni - 08-10-2014 (08-10-2014, 02:55 AM)Dyme Wrote: Azazel, for example: https://twitter.com/grsecurity/status/434876038745579520 Well, that's quite funny. I'm surprised. RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - lola - 08-10-2014 (08-10-2014, 02:55 AM)Dyme Wrote: Azazel, for example: https://twitter.com/grsecurity/status/434876038745579520 I knew you could rm ld.so.preload but I forgot about rename(), thanks.
RE: [C] Using LD_PRELOAD to overwrite Linux syscalls - phyrrus9 - 08-13-2014 actually, you can also overload the ld preload attack, simply by adding the correct lib into the LD_PREALOD environment variable. OR, you can use dlsym to find the correct functions you use. Very common attack, has its uses, but in most scenarios today it is actually disabled (use of dyld caches, disabling of environment lookup, code signatures, etc). |