This is a cross-post from my blog
While I was working as a core C library developer with my previous employer. I came across this RTLD_NEXT flag in dynamic linking which has the amazing capability and can be easily exploited or used for the unethical purpose(Here I intend to educate the developer to don’t be victims). In this article, I will show you a simple way to hack C/C++ application using RTLD_NEXT with an easy example.
Intro to RTLD_NEXT
- Library linking & symbol resolution i.e. extracting address(precisely offset here in dynamic linking case) of function is specified at compile time.
- For example, there are four shared libraries linked & loaded dynamically in order as A.so, B.so, C.so & D.so with the main application. And funcXYZ() is called from the main application which is defined in both the library C.so & D.so with the same prototype.
- Then funcXYZ() from C.so will be called first as it’s ahead of D.so in linking order.
- But what if you want to call funcXYZ() from D.so ? You can achieve this by RTLD_NEXT flag defined in . What you have to do is define your funcXYZ() as below in C.so:
void funcXYZ() { void (*fptr)(void) = NULL; if ((fptr = (void (*)(void))dlsym(RTLD_NEXT, "funcXYZ")) == NULL) { (void)printf("dlsym: %s\n", dlerror()); exit(1); } return ((*fptr)()); }
- Now, whenever funcXYZ() called from main application it will come to C.so which simply search for the same symbol from next loaded libraries i.e. D.so .
- dlsym() search for symbol provided in argument from the memory and a returns function pointer to the same. ## Let’s hack C/C++ application using RTLD_NEXT
malloc.c
#include <stdio.h> #include <dlfcn.h> void *malloc(size_t size) { static void *(*fptr)(size_t) = NULL; /* look up of malloc, only the first time we are here */ if (fptr == NULL) { fptr = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc"); if (fptr == NULL) { printf("dlsym: %s\n", dlerror()); return NULL; } } printf("Our Malloc\n"); return (*fptr)(size); // Calling original malloc }
main.c
#include <stdio.h> #include <stdlib.h> int main() { malloc(1); return 0; }
Creating a shared library
$ gcc -o malloc.so -shared -fPIC malloc.c -D_GNU_SOURCE
Linking & executing the main application
$ gcc -o main main.c ./malloc.so -ldl $ ./main Our Malloc
Note: You can also use LD_PRELOAD as below, which loads the specified library first. No need to mention ./malloc.so explicitly in the compilation.
$ LD_PRELOAD=`pwd`/malloc.so ./main
How it works
- When you compile
main.c
withgcc -o main main.c ./malloc.so -ldl
, you specify malloc.so explicitly on first order. We can verify this by ldd command
$ ldd main linux-vdso.so.1 => (0x00007fff37bf4000) malloc.so (0x00007fc5df598000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fc5df37d000) libc.so.6 => /lib64/libc.so.6 (0x00007fc5defbb000) /lib64/ld-linux-x86-64.so.2 (0x00007fc5df79b000)
- So when you call malloc it will refer the first occurrence of the symbol from the loaded library sequence which is in our malloc.so library.
- We now extract original malloc from next loaded shared library which is /lib64/libc.so.6. Vulnerability & precautions you should consider
Top comments (0)