The first example we will explore involves sniffing encrypted traffic at the application layer. Normally to understand how a client or server application interacts with the network, we would use a traffic analyzer like Wireshark.1 Unfortunately, Wireshark is limited in that it can only see the data post encryption, which obfuscates the true nature of the protocol we are studying. Using a soft hooking technique, we can trap the data before it is encrypted and trap it again after it has been received and decrypted.
Our target application will be the popular open-source web browser Mozilla Firefox.2 For this exercise we are going to pretend that Firefox is closed source (otherwise it wouldn't be much fun now, would it?) and that it is our job to sniff data out of the firefox.exe process before it is encrypted and sent to a server. The most common form of encryption that Firefox performs is Secure Sockets Layer (SSL) encryption, so we'll choose that as the main target for our exercise.
In order to track down the call or calls that are responsible for passing around the unencrypted data, you can use the technique for logging intermodular calls as described at http://forum.immunityinc.com/index.php?topic=35.0. There is no "right" spot to place your hook; it is really just a matter of preference. Just so that we are on the same page, we'll assume that the hook point is on the function PR_Write, which is exported from nspr4.dll. When this function is hit, there is a pointer to an ASCII character array located at [ ESP + 8 ] that contains the data we are submitting before it has been encrypted. That +8 offset from ESP tells us that it is the second parameter passed to the PR_Write function that we are interested in. It is here that we will trap the ASCII data, log it, and continue the process.
First let's verify that we can actually see the data we are interested in. Open the Firefox web browser, and navigate to one of my favorite sites, https://www .openr^ce.org/. Once you have accepted the site's SSL certificate and the page has loaded, attach Immunity Debugger to the firefox.exe process and set a breakpoint on nspr4.PR_Write. In the top-right corner of the OpenRCE website is a login form; set a username to test and a password to test and click the Login button. The breakpoint you set should be hit almost immediately; keep pressing F9 and you'll continually see the breakpoint being hit.
1 See http://www.wireshark.org/.
2 For the Firefox download, go to http://www.mozilla.com/en-US/.
Eventually, you will see a string pointer on the stack that dereferences to something like this:
[ESP + 8] => ASCII "username=test&password=test&remember_me=on"
Sweet! We can see the username and password quite clearly, but if you were to watch this transaction take place from a network level, all of the data would be unintelligible because of the strong SSL encryption. This technique will work for more than the OpenRCE site; for example, to give yourself a good scare, browse to a more sensitive site and see how easy it is to observe the unencrypted information flow to the server. Now let's automate this process so that we can just capture the pertinent information and not have to manually control the debugger.
To define a soft hook with PyDbg, you first define a hook container that will hold all of your hook objects. To initialize the container, use this command:
hooks = utils.hook_container()
To define a hook and add it to the container, you use the add() method from the hook_container class to add your hook points. The function prototype looks like this:
add( pydbg, address, num_arguments, func_entry_hook, func_exit_hook )
The first parameter is simply a valid pydbg object, the address parameter is the address on which you would like to install the hook, and num_arguments tells the hook function how many parameters the target function takes. The func_entry_hook and func_exit_hook functions are callback functions that define the code that will run when the hook is hit (entry) and immediately after the hooked function is finished (exit). The entry hooks are useful to see what parameters get passed to a function, whereas the exit hooks are useful for trapping function return values.
Your entry hook callback function must have a prototype like this:
def entry_hook( dbg, args ): # Hook code here return DBG CONTINUE
The dbg parameter is the valid pydbg object that was used to set the hook. The args parameter is a zero-based list of the parameters that were trapped when the hook was hit.
The prototype of an exit hook callback function is slightly different in that it also has a ret parameter, which is the return value of the function (the value of EAX):
def exit_hook( dbg, args, ret ): # Hook code here return DBG CONTINUE
To illustrate how to use an entry hook callback to sniff pre-encrypted traffic, open up a new Python file, name it firefox_hook.py, and punch out the following code.
Was this article helpful?