Security

Malicious Work with the modify-function-return-value Hack

By Raman Deep, November 12, 2012

The modify-function-return-value hack is particularly dangerous because it can be used to intercept function calls in code, user libraries, and in runtime libraries. Knowing how it operates is essential to avoiding it.

# Raman Deep: [email protected]
# This script starts the victim application in GDB , apply the modify-function-return-value
# hack on function 'get_remote_token' the first time it is called, and then detach the application from GDB.
# So, there is no execution overhead once hack is applied.
# The trick used is that most of the compilers, in default settings ,
# use EAX register to return the retun value to the caller
file ./victim_client
br get_remote_token
r
finish
printf "\n value of eax = %d \n", $eax
set $eax=0
printf "\n value of eax, after hack = %d ..... HACKED! \n", $eax
detach
q

I loaded the victim_client with the GDB command file. Then a breakpoint is set, with the GDB command br, on target function get_remote_token. Then the application is started with GDB command r. Below is the result of running victim_client directly and then in GDB under the influence modify-function-return-value.gdb:

Hacking recvfrom in the C Runtime Library

Earlier, I noted that the remote server returns different information (STOP versus. SUCCESS) depending on whether the client is invalid or valid. This information can be used to manipulate the application by hacking the recvfrom function provided by the system.

Actually, hacking recvfrom() is slightly different than merely modifying function return value. Why? Because we need to change the string returned via a second parameter, byrecvfrom(). On computer B, recvfrom() returns STOP; if this can be changed to SUCCESS, then the application is compromised. This is a modify-function-argument-value hack, a variant of the modify-function-return-value hack. Here is a small GDB script (modify-function-return-value_2.gdb) to do that.

# Raman Deep: [email protected]
# This script starts the victim application in GDB , apply the modify-function-return-value
# (well, actually, more than that because it changes the argument on return) hack on function 'recvfrom'
# the first time this is called, and then detaches the application from GDB. So, there is no
# execution overhead once hack is applied.
file ./victim_client
br recvfrom
r
# This is the second argument to the recvfrom.
# Lets save it's address, for later use!
set variable $_buffer_address = *(int *) ($esp +8)
finish
printf "\n Value returned by recvfrom(the buffer) = \"%s\" \n", $_buffer_address
printf "\n Changing it...\n"
call strcpy($_buffer_address,"SUCCESS")
printf "\n Value returned by recvfrom changed to \"%s\"...and HACKED!\n",$_buffer_address
detach
q

The output below is the result of running victim_client directly and then in GDB under the influence modify-function-return-value_2.gdb:

Defense Against the Hack

There are many ways to make it more difficult for crackers to pull off this hack. The idea is to make it hard enough that they will be inclined to abandon their efforts or move on to some other hacking activity elsewhere. A truly determined hacker with all the time in the world, however, will get around any and all of these steps.

Obfuscate:1. Source code obfuscation: This is a mechanism for obfuscating the names of the functions and variables in the source code so that it's difficult to guess the functionality by looking at the name of the identifier.2. Binary code obfuscation: This is the mechanism for obfuscating the binary code generated. It's a lot more difficult, but is a very effective countermeasure. For example, developers can insert bogus code around sensitive information to make it harder for the hacker to stumble upon it  but this is a very basic example.

Use a challenge-response mechanism: The problem with victim_client is that it makes a big decision based solely on the return value of a single function. This problem can be eliminated by adding more variables; for example, passing a challenge value  the server will use this challenge and send back a response. Then the client application will verify the response. This increases the number of variable attributes that a hacker needs to manipulate.

Strip the binary: We were able to find the target function easily because the binary (ELF format) contained enough information about the symbols in it. If we strip the binary, then the symbol table of the ELF binary will be unavailable (hence, make things little harder for the hacker).

Write your own version of C runtime functions: Writing your own C runtime functions, like strcmp, combined with stripping and obfuscation can be very helpful. However, writing some of the functions such as sendto, recvfrom (or any function that needs entry into the kernel) is not straightforward. In any case, writing your own versions of C-runtime-equivalent function creates maintenance and portability issues.

Encryption: Developers should encrypt sensitive data whenever possible. Because encryption can be application-specific, it provides a very subtle countermeasure even if some of the functions are hacked, because information obtained (like the data captured through recvfrom) is not of much use until and unless the encryption is broken.

Use tricky C strings: Perhaps the most valuable information a hacker can obtain is through ASCII strings, which are also the means of communication with the user. All the C-style strings, if stored in some intelligent manner, can trick tools like ltrace, suppressing lots of information from being available to a hacker. For example, you can always start your string with a NULL character  tools like ltrace will be fooled and will not display the actual contents of the string. However, you need to devise a mechanism in your application to handle this. Obviously, this technique can't be used while passing strings to functions like strcpy, strlen, strcmp, etc.

Compile your sensitive functions through assembly and then make changes to their prologue and epilogue. For example, the eax processor register, by default, is used to communicate the return value to the caller; we can change this calling semantic for desired functions. This is very low-level, but worth the pain if used cautiously.

Conclusion

The modify-function-return-value hack is simple, but it can be dangerous. The problems it can create for an application increase dramatically because it can be applied to function calls inside the C runtime library as well. The fact that it does not have a big runtime overhead is also something to worry about. We also examined a variant of this hack, wherein even arguments to a function can be changed. Developers must think of these problems well in advance to make sure that safeguarding techniques are implemented in the application code.

Raman Deep is a senior software engineer with SafeNet's Software Rights Management division. He develops UNIX releases for products designed to help software vendors control how their applications are deployed and used. This article represents his views only.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!