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 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.
Brief
- Let say you have a C/C++ application/tool which is highly proprietary and driving most of the business to your company. You have done some licensing or encryption which prevents a hacker(or maybe rivals) from cracking your binary or to use it without your license keys or something.
- This binary can easily be cracked by the use of
RTLD_NEXT
flag if you have not taken enough precautions which we will discuss later in this article.
Library linking & symbol resolution
- 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. AndfuncXYZ()
is called from the main application which is defined in both the libraryC.so
&D.so
with the same prototype. - Then
funcXYZ()
fromC.so
will be called first as it’s ahead ofD.so
in linking order.
Intro to RTLD_NEXT
But what if you want to call funcXYZ() from
D.so? You can achieve this by
RTLD_NEXTflag defined in
<dlfcn.h>. What you have to do is define your
funcXYZ()as below in
C.so`:
- Now, whenever
funcXYZ()
called from main application it will come toC.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
|
|
main.c
Creating a shared library
|
|
Linking & executing the main application
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.
|
|
How it works
- When you compile
main.c
withgcc -o main main.c ./malloc.so -ldl
, you specifymalloc.so
explicitly on first order. We can verify this byldd
command
- 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
.
What RTLD_NEXT used for?
An obvious question would be “Why the hell library designer/developer keep this kind of vulnerability?”
RTLD_NEXT
allows one to provide a wrapper around a function defined in another shared library. At least that is what man page of dlsym describes.
I am still confused! Is this feature or vulnerability?
Vulnerability
- If you not experienced enough then perhaps your question would be “What’s vulnerability in this ?"?♀️ then let me tell you, my friend, you might have stored license string, encryption key or any other proprietary data to validate against user access which usually programmer stores using struct or array kind of data structures.
- Now, we generally use
memcmp() or
strcmp()library functions to compare user access or validate key/data. You can easily generate wrapper around these functions using
RTLD_NEXT` and manipulate it. - Some companies use real-time authentication by an HTTP request which can also be cracked as there might be a particular function returning
true
orfalse
as access check. You can simply create a wrapper of that function to manipulate it. - This may take more time to find out function by hit & trial method. But it’s not impossible. To figure out function name you can use
nm
orreadelf
like utilities which list out symbol names & it’s corresponding addresses/offset as follows
- If you want to learn more about binary file format ELF, then I have written a separate article for it here.
Precautions you should consider
Use stripped binaries for release
Compiled binary usually contain symbol information as we show using nm
utility above. But when you strip binary it just strip symbol table from it which is not necessary for execution as it is only being used in debugging & link resolution at compile time. Stripped binary can produced with the help of the compiler itself, e.g. GNU GCC compilers’ -s
flag, or with a dedicated tool like strip on Unix.
Static linking
Rather than releasing a dynamic linking binary, compile static version & strip it. Although it has some cons which are out of topic for this article.
Do not use library functions for handling proprietary data
While processing proprietary data in your application do not rely on library functions rather design your own with weird names. If you are storing read-only proprietary data in ASCII format within binary then encrypt it or simply add a particular number in every char so that memory dump won’t show any human-readable sentences or words.