linux--function Hijacking--based on Ld_preload

Source: Internet
Author: User
Tags sha1

Recently I am facing a problem, how to differentiate a problem of library-function from application problems.for solving t His problem, we need-know some knowledge about share-library and basics in linux.for dynamic libraries, they is loaded To memory at program running. There is many benefits for this. On the other hand, we had a chance to do something. For Example:replace the function, which'll is loaded,as our function. Usually,this is maybe a very professional problem, at least for me. But thanks for some masters, they has been provide a mature a-to-our-goal.
1). How to replace a function of shared libraries?
The answer is Ld_preload, this is a environment variable for gun-linker.it are used to indicated some pre-load shared Libra Ries. This meaning, functions in

This libraries would get a higher priority than normal libraries.

Normally, we use this technique just want to intercept some functions. So we can does some other thing (evil thing?)
Above the original function. But
1). How can I get the original function?
Some Functions:dlopen (), Dlsym (), Dlclose () and Dlerror (). There has been many articles to explain them.

In the next section, I'll try to translate a nice article. The original article is there

http://fluxius.handgrep.se/2011/10/31/the-magic-of-ld_preload-for-userland-rootkits/

The directory for this article is as follows:
A. Shared library
Two. Simple Ld_preload (relative to the later processed ld_preload)
2.1. Create and use a shared library
2.2. Dlsym ()
2.3. Restrictions on use

Three. Related Stealth techniques

3.1 Jynx-kit

3.2 Inspection Methods

Here is the text:

A. Shared library
As we know, the link to a dynamic library is implemented when the program loads. This feature is implemented by ld-linux-x86-64.so.x on my computer, but it may also be ld-linux.so.x for other models. If you are interested, you can verify this

Fl[email protected]:~$ readelf-l/bin/ls [...]  Interp         0x0000000000000248 0x00000000004purposes00248 0x0000000000400248                  0x000000000000001c 0x000000000000001c  R      1       [Requesting program interpreter:/lib64/ld-linux-x86-64.so.2] [...]

(PS: Readelf Here is a tool for reading elf files, typically specifying a dynamic loading tool for program files that need to be loaded dynamically.) This involves parsing the elf format, which will attempt to perform some simple analysis of the ELF format in the next article. )

Dynamic compilation is much smaller than a large volume that is statically compiled. For some of these library functions, only a pointer to the relevant library is retained, and there is no entity containing the function. If you want to see a program that contains the calls to those libraries, you can check with the "LDD" command, for example:

<a target=_blank href= "Mailto:[email protected]:~$" >[email protected]:~$</a> ldd/bin/ls     Linux-vdso.so.1 =  (0x00007fff0bb9a000)     libselinux.so.1 =/lib/x86_64-linux-gnu/libselinux.so.1 ( 0x00007f7842edc000)     librt.so.1 =/lib/x86_64-linux-gnu/librt.so.1 (0x00007f7842cd4000)     libacl.so.1 = >/lib/x86_64-linux-gnu/libacl.so.1 (0x00007f7842acb000)     libc.so.6 =/lib/x86_64-linux-gnu/libc.so.6 ( 0x00007f7842737000)     libdl.so.2 =/lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7842533000)     /lib64/ Ld-linux-x86-64.so.2 (0x00007f7843121000)     libpthread.so.0 =/lib/x86_64-linux-gnu/libpthread.so.0 ( 0x00007f7842314000)     libattr.so.1 =/lib/x86_64-linux-gnu/libattr.so.1 (0x00007f784210f000)

Let's look at an example (the example procedure is as follows)

#include <stdio.h> main () {         printf ("Huhu la charrue");}

Both dynamic and static are compiled separately

[Email protected]:~$ gcc toto.c-o toto-dyn [email protected]:~$ gcc-static toto.c-o toto-stat [email protected]:~$ ls- l | grep "toto-"-rwxr-xr-x  1 fluxiux fluxiux     8426 2011-10-28 23:21 toto-dyn-rwxr-xr-x  1 fluxiux fluxiux   804327 2011-10-28 23:21 Toto-stat

We see "Toto-stat" is almost 96 times times the "Toto-dyn", why is it?

[Email protected]:~$ ldd Toto-stat is not     a dynamic executable

        (because "Toto-stat" is a static chant)
         Dynamic linking is a great way to give us a lot of benefits, such as:
                 update libraries and still support programs this want to use older, non-backward-compatible versions O F those libraries,
                Override specific libraries or even specific functions in a library when executing a particular program,
  & nbsp;             do all the while programs is running Using existing libraries.
       We have some habits for naming shared libraries. If the name of a library is "Soname", then a prefix "Lib", a suffix ". So", and a version number are usually added.
       PS: Although it is only a convention: But you do not do so, your library is not recognized correctly)
         now we can take a look at Ld_preload,

Two. Simple Ld_preload application

We know that library files are generally stored in the "/lib" directory. So if you want to modify a library, the easiest way is to find the source of the library, modify and then recompile again. But in addition to this scenario, we have another cool way of using Linux to provide us with an external interface: Ld_preload. (Let's take a look at the following)

2.1. Create and use a shared library
If you want to rewrite the "printf" behavior, you can do this by first writing your "printf" function

        #define _gnu_source        #include <stdio.h>        int printf (const char *format, ...)        {              exit (153);        }

It is then compiled to compile it into a shared library. Like this

        [Email protected]:~$ gcc-wall-fpic-c-o my_printf.o my_printf.c         my_printf.c:in function ' printf ':        MY_PRINTF.C  : 6:2: warning:implicit declaration of function ' exit '        my_printf.c:6:2:warning:incompatible Implicit declaration of Built-in function ' exit '        [email protected]:~$ gcc-shared-fpic-wl,-soname-wl,libmy_printf.so-o libmy_printf.so
   my_printf.o

Then we modify an environment variable and then run our own test program.

        [Email protected]:~$ export ld_preload= $PWD/libmy_printf.so        [email protected]:~$./toto-dyn

You will see that the "printf" behavior has been changed, and it does not print "Huhu la charrue". Okay, let's see what "ltrace" means.

        [Email protected]:~$ ltrace/toto-dyn         __libc_start_main (0x4015f4, 1, 0x7fffa88d0908, 0x402530, 0x4025c0 < Unfinished ...>        printf ("Huhu la charrue" <unfinished ...>        + + + exited (status 153) + + + +

Interestingly, our "printf" was called before the system's "printf". So now look at a new question, if our goal is simply to modify the "printf" behavior, but do not break the original function.   What to do, rewrite the whole function?!! That is obviously inappropriate, in order to deal with this problem, you can look at the following several functions.

2.2. Dlsym ()
There are several interesting functions in the library "LIBDL"
Dlopen (): Load a library
Dlsym (): Gets a pointer to a specific symbol
Dlclose (): Unload a library


Here, because the library is loaded when the program loads, we just need to call "Dlsym" directly. We pass the "Rtld_next" parameter to "Dlsym" to get a pointer to the original "printf" function. Just like this.

[...] typeof (printf) *old_printf; [...] Do here SOMETHING VERY evilold_printf = Dlsym (Rtld_next, "printf"); [...]

Then we need to do a bit of special processing of the formatted string (the corresponding general parameters do not need so much trouble), after processing it can be used directly

        #include <stdio.h>        #include <dlfcn.h>        #include <stdlib.h>        #include <stdarg.h>        int printf (const char *format, ...)        {                  va_list list;                  char *parg;                  typeof (printf) *old_printf;                  Format variable arguments                  va_start (list, format);                  vasprintf (&parg, format, list);                  Va_end (list);                  Do this SOMETHING VERY EVIL                  //Get a pointer to the function "printf"                  old_printf = Dlsym (Rtld_next, "printf");                  (*old_printf) ("%s", parg);//And we call the function with previous arguments free                  (PARG);        }

and recompile.

        [Email protected]:~$ gcc-wall-fpic-c-o my_printf.o my_printf.c         my_printf.c:in function ' printf ':        MY_PRINTF.C : 21:1: Warning:control reaches end of non-void function        

Try again

        [Email protected]:~$ export ld_preload= $PWD/libmy_printf.so        [email protected]:~$./toto-dyn         huhu la charrue

In this way, a user who calls "printf" does not want things to happen quietly. But there are some drawbacks to this mechanism.

2.3. Restrictions on use
This approach is cool, but there are some limitations. For example, a statically compiled program is not valid. Because a statically compiled program does not require a function to connect the faces of a dynamic library. Also, if the file's suid or Sgid bit is set to 1, the load will ignore Ld_preload (which is the developer of LD for security reasons).

Three. Related Stealth techniques

3.1 Jynx-kit

About two weeks ago, we introduced a new stealth technique. This thing takes advantage of a shell script that runs automatically, and has never been checked by Rkhunter and Chkrootkit. First let's take a look at the actual code, in "Ld_poison.c", there are 14 of functions are hijacked

[...]    Old_fxstat = Dlsym (Rtld_next, "__fxstat");    Old_fxstat64 = Dlsym (Rtld_next, "__fxstat64");    Old_lxstat = Dlsym (Rtld_next, "__lxstat");    Old_lxstat64 = Dlsym (Rtld_next, "__lxstat64");    Old_open = Dlsym (Rtld_next, "open");    Old_rmdir = Dlsym (Rtld_next, "rmdir");    Old_unlink = Dlsym (Rtld_next, "unlink");     Old_unlinkat = Dlsym (Rtld_next, "Unlinkat");    Old_xstat = Dlsym (Rtld_next, "__xstat");    Old_xstat64 = Dlsym (Rtld_next, "__xstat64");    Old_fdopendir = Dlsym (Rtld_next, "Fdopendir");    Old_opendir = Dlsym (Rtld_next, "Opendir");    Old_readdir = Dlsym (Rtld_next, "Readdir");    Old_readdir64 = Dlsym (Rtld_next, "readdir64"); [...]

Let's take a look at the "open" function and see that "__xstat" is called inside.

[...]    struct stat s_fstat; [...]    Old_xstat (_stat_ver, pathname, &s_fstat); [...]

Next is a check operation that examines the file's group ID, path, and file name. (We want to make sure that this file is not "Ld.so.preload" because we want to hide it). If we want to hide the file, we will not return the result to the user

[...]    if (S_fstat.st_gid = = Magic_gid | | (Strstr (pathname, magic_dir)! = NULL) | | (Strstr (pathname, config_file)! = NULL)) {        errno = ENOENT;        return-1;    } [...]


Following this approach, we can hide some files and behavior from the user (the attacker) after we have processed the above functions over and over again. But is there any way we can check it? Keep looking down.

3.2 Checking for concealment
Whether or not this stealth method is enough to brighten your eyes, it does kill Rkhunter and Chkrootkit. Because the two tools use symbol-based checking, this is not the best approach.

Consider the following example:
First, if we empty the ld_preload variable, a checksum file is generated for a specified program file. It's like this.

        [Email protected]:~$ sha1sum toto-dyn         A659C72EA5D29C9A6406F88F0AD2C1A5729B4CFA  toto-dyn        [email protected]:~$ sha1sum Toto-dyn > TOTO-DYN.SHA1

Then check the checksum of this file after setting the Ld_preload, just like this

        [Email protected]:~$ export ld_preload= $PWD/libmy_printf.so        [email protected]:~$ sha1sum-c TOTO-DYN.SHA1         Toto-dyn:ok

(seems to have passed the authentication of this file)
But is that really the right thing to do?

Obviously not, because we have not actually modified the program files, so any time the file checksum will be the same. If the anti-stealth tool is based on checksum work, then no doubt this is not possible. Other inspection techniques include: Check for suspicious files, symbols, port binding detection, etc., but also failed because this stealth method is too flexible, and in Jynx we have a sort of port knocking to open the REM OTE Shell for our host.


Well, what else can we do with these things? Check all libraries that ld_preload point to, or "/etc/ld.so.preload". We know that "dlsym" is often used to find primitive functions, all of which can

$ strace./bin/ls[...] Open ("/home/fluxiux/blabla/jynx-kit/ld_poison.so", o_rdonly) = 3read (3, "\177elf\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0 \1\0\0\0\240\n\0\0\0\0\0\0 "..., 832) = 832fstat (3, {st_mode=s_ifreg|0755, st_size=17641, ...}) = 0mmap (NULL, 2109656, prot_read| Prot_exec, map_private| Map_denywrite, 3, 0) = 0x7f5e1a586000mprotect (0x7f5e1a589000, 2093056, Prot_none) = 0mmap (0x7f5e1a788000, 8192, PROT_ read| Prot_write, map_private| map_fixed| Map_denywrite, 3, 0x2000) = 0x7f5e1a788000close (3) [...] Open ("/lib/x86_64-linux-gnu/libdl.so.2", o_rdonly) = 3[...]

Parse the "ld_poison.so" file, see a lot of replacements in it, they are possible places of filth. Looking at the string information of these binaries is likely to provide us with some interesting hints. Of course, if they have been skillfully handled, then there is no way. But another way to think about it, the normal program files need to disguise their own string information.

[Email protected]:~/blabla/jynx-kit$ strings ld_poison.so[...] Libdl.so.2[...] Dlsymfstat[...] Lstat Hooked.ld.so.preloadxochi <--sounds familiar[...] /proc/%s <--Hmmm ... strange! [...]

This stealth method, called Jynx-kit, proves that it is unrealistic to want to deal with the hidden methods above by means of symbol-based checks. and the heuristic check effect will be good.

The original is here: http://fluxius.handgrep.se/2011/10/31/the-magic-of-ld_preload-for-userland-rootkits/





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.