Chip Security TestingΒ 
Binary Security AnalysisΒ 
ResourcesΒ 
Blog
Contact us
Back to all articles
Vulnerability Research

Analysis of the Uroburos malware with esReven

11 min read
Edit by Mathieu FavrΓ©aux β€’ Jun 12, 2019
Share

In this post, we present how Timeless Analysis can be used to analyze a few mechanisms of a Uroburos recent version. We use esReven and its integration with Volatility and IDA to detect indicators of compromise, analyze the dropping mechanisms and circumvent tricks the malware uses to hide itself.

Β 

The starting point of this analysis is a 50 seconds record of the Uroburos dropper executed from the desktop on a Windows 7 x64 SP1.

This article is also available as a video walkthrough:

VIDEO_1.jpg

The sha256 of the analyzed dropper sample is bcf10059be39f6ce338535a311508239c8db710fbbbc47b69249cb15b1454370, and a partial analysis of the driver already exists by Stefan Le Berre (@heurs).

Β 

Disclaimer: This analysis shows how esReven can be used to analyze some parts of a Uroburos version. There are multiple easily available analysis on older version of Uroburos that are way more exhaustive. Furthermore, we can see that this version of the malware is very light. One of the first thing that can be noted is that it doesn’t include any PatchGuard bypass, hence limits the amount of hooks compared to older versions.

Β 

Detecting IOC with REVEN and third party tools

Β 

First type of callback

Β 

esReven integrates really well with the tool Volatility. To use this tool, one usually have to create a dump, which is limited to a single moment in time. With esReven, Volatility can be applied to any moment in time of the recorded execution. We will see later that this specificity is of interest in our case.

Β 

CODE_1.png

Β 

In these results we can see a β€œGenericKernelCallback”, at 0xfffffa8001c77874, that has been set by an UNKNOWN module, which is suspicious. With esReven we can search its address in the trace to determine if and where this callback is executed:

IMAGE_1.png

Β 

We can see from the above screenshot that this callback is executed six times in the trace, and the code of the callback belongs to an unknown binary. If we look at the instruction view or the backtrace for each of these executions, we are always in the context of a process termination, hence we can deduce that this callback has been set by ntoskrnl!PsSetCreateProcessNotifyRoutine(Ex). We can look for calls to this function:

IMAGE_2.png

It is called only once, and the notify routine argument is the aforementioned callback so this is the right place.

Β 

If you’re familiar with how the Windows system operates with process creation callbacks, you would know that the list of callback objects is stored in an array, that can be easily seen with esReven. The algorithm is simple, Ps(p)SetCreateProcessNotifyRoutine looks for the first available entry in the array and fills it with the new pointer to the callback object with ExCompareExchangeCallback. Accordingly, using the Memory History feature on this entry, we are able to find when the write of the new callback object occurs:

IMAGE_3.png

As an alternative, we could use the esReven Python API to script and automate the detection of rogue callbacks that are not set with PsSetCreateProcessNotifyRoutine.

Β 

Second type of callback

Β 

The second type of callback set by Uroburos are network callouts. They can be detected in two manners. The first one is by searching for the execution of fwpkclnt!FwpsCalloutRegister0. The second one is by looking at the array of callouts. As a matter of fact, Fwps callouts use the same idea than the CreateProcess callbacks, which is an array of structures defining the callouts. More precisely, the callout entries are added with netio.sys!FeAddCalloutEntry and in this function the callout array can easily be distinguished.

Β 

For this analysis, Uroburos calls FwpsCalloutRegister0 four times and we can retrieve the callback argument when it is pushed on the stack:

IMAGE_4.png

Β 

The four callbacks given as argument to FwpsCalloutRegister0 are:

  • 0xfffffa8001c8e580
  • 0xfffffa8001c8eca0
  • 0xfffffa8001c8ede0
  • 0xfffffa8001c8e580 (second time)

Of course these are addresses from the loaded driver, not offsets.

Β 

For the second part of this analysis we will show how to retrieve a sound version of binaries involved in the dropping of this malicious driver, and the driver itself.

Β 

Following and retrieving binaries during the dropping process

Β 

First insights with the Taint feature from esReven

Β 

The Taint feature is very powerful when analyzing crashes and vulnerabilities. When working on malware it is also very useful when combined with the Backtrace to follow each and every binaries involved.

Here, we will simply taint a byte of the code, for example from the function that calls the PsSetCreateProcessNotifyRoutine: in less than 1 second, the backward taint is propagated in the trace through half a billion instructions. The results show the propagation of the taint through each memory area, and we will analyze some of them.

IMAGE_5.png

This first β€œmemcpy” is responsible for the copy of the driver code. If we use the backtrace to go back to the call, we can get all its arguments, including the target address, which is the base address of Uroburos in this record.

Β 

Continuing to follow the taint propagation by double clicking the results, we find another β€œmemcpy”, from a binary called usbehub.sys. Now this is interesting because the legit driver from Windows is called usbhub.sys, not usbehub.sys.

IMAGE_6.png

This is definitely a point of interest for us and we will see that later.

Β 

Next taint propagation shows another memcpy, and then we can see a user 32-bit β€œmemcpy”, invoked by a binary named pxinsi64.exe:

IMAGE_7.png

Also, since the previous taint was pointing to Kernel mode code and the current one is user mode, this binary is a point of interest as it seems to be the junction between User and Kernel mode.

Β 

Continuing this analysis, we reach the last β€œmemcpy” detected by the taint, and the backtrace shows that it comes from the (renamed) dropper wololoooo.exe:

IMAGE_8.png

In the next part we will show how we are able to dump each binary and how we circumvented some tricks the malware uses to hide itself.

Β 

Dumping the Uroburos driver

Β 

We showed in the previous part that we are able to see the memcpy argument, and in particular that the base address was available. In this record, it is 0xfffffa8001c6d000, so we can use once again Volatility to dump it as it includes the moddump command that reconstruct the binary from the loaded image. We dump it near the end of the trace so that the driver is fully loaded:

CODE_2.png

Β 

The result of the command is somewhat wrong because of a bad DOS signature, but we can analyze this problem quickly with esReven by observing the memory history of this header. In the following screenshot, we can find that the two first bytes of the MZ header are overwritten, and with the memory history, we can know exactly when.

IMAGE_9.png

Β 

To perform a valid dump, we just need to indicate Volatility a moment in time after the loading of the malware but before the aforementioned overwrite. Right before the overwrite, at transition 491536015 seems ok:

CODE_3.png

This is where having esReven instead of dumping memory at an uncontrolled moment is useful.

Β 

The malware driver is now dumped and we can analyze it with our favorite disassembler. A comfortable approach of this is to rebase the binary to 0xfffffa8001c6d000 so that the disassembly correspond to the recorded trace. Then, no delta computation is necessary and for example, verifying if an unnamed function is executed or not is instantly performed through the Search feature.

Β 

Dumping the usbehub.sys driver

Β 

Now that we have dumped the malware driver, we are interested in this usbehub.sys we saw earlier. Following the same methodology we used for the malware driver, we can simply taint backward a byte of code of this binary to find out more precisely where it comes from. For this binary there are less results, yet combined with the backtrace we find some interesting information. For example, the fact that at some point this driver has been loaded from disk, and that the load implied a cryptographic validation with ci.dll!CiValidateImageHeader:

IMAGE_10.png

Β 

Almost right after in the taint results, we can see the ntoskrnl!NtWriteFile routine in the backtrace. This is useful for us because now we only need to dump the original buffer from the arguments. To do so, we can go back to the user call responsible for the Write, simply by scrolling up a bit in the trace and see that the WriteFile is performed by the dropper itself at this point, and that we can easily retrieve the buffer and the size in the pushed arguments:

IMAGE_11.png

Β 

Since we know exactly what buffer is written on disk, we don’t need to reconstruct the binary from a loaded image, the easiest way is simply to dump the buffer with the Python API from esReven:

[CODE_4]

$ python2 dump_mem_reven2.py --host 127.0.0.1 --port 40687 -p 279323504 --mem "0x23:0x20330e8" --size 68288 --filename usbehub_279323503_20330e8_68288.bin Done

Β 

Now, if we have a look at this driver we can see an interesting thing: it is a signed driver:

IMAGE_12.png

Β 

And simply opening it in your favorite disassembler will unveil some obvious strings and ask for pdb for the driver VBoxDrv.sys. So, clearly we’re facing the infamous VirtualBox driver used by many malware to install their own unsigned driver.

Β 

The next binary that we will dump is pxinsi64.exe, and at first sight it is the one responsible for the exploit of the driver, but we will see that it’s not that straightforward, and how esReven can help us with that.

Β 

Dumping the pxinsi64.exe binary

Β 

Just like we did with the usbehub.sys binary, to dump pxinsi64.exe we can use the taint to find the ntoskrnl!NtWriteFile, then the kernel32!WriteFile, and dump the binary from the buffer passed as argument:

IMAGE_13.png

Β 

As we suppose that pxinsi64.exe is responsible for the exploit, we pursue the analysis by going back to the execution of usbehub.sys, and spot the NtDeviceIoControlFile in the backtrace. This lookout confirms our supposition as NtDeviceIoControlFile is originated by pxinsi64.exe:

IMAGE_14.png

Β 

What we can do now is use the IDA synchronization plugin, an adapted version of ret-sync from A. Gazet and link IDA with esReven to analyze with ease this exploit. But soon enough we realize that the executed function doesn’t correspond to the one in IDA, even though addresses are correct:

IMAGE_15.png

Β 

This difference is interesting as it points out that something happens on this portion of code. Using the memory history feature on it, we see that the last write on this portion of code is originated from a NtWriteVirtualMemory, which itself comes from pxinsi64.exe, but this time, the synchronisation is correct:

IMAGE_16.png

Β 

This means that pxinsi64.exe is rewriting itself with the exploit version of itself. With more analysis, the above loop is actually the loading of each section of the exploit binary, and the raw version is available in memory so we can dump it and analyze the exploit with IDA synchronized:

IMAGE_17.png

Β 

This is exactly the routine where the VirtualBox exploit is implemented, and now the analyst can explore it precisely with timeless debugging and IDA, without the pain of a kernel debugger.

Β 

Conclusion

Β 

This analysis focused on tracking suspicious behavior throughout the execution of a malware. Among other, we showed that esReven allows to quickly find the code responsible for setting malicious callbacks or exploiting a vulnerability, even if it lies in a kernel module, and dump the full binary if needed.

Especially, thanks to its Python API, we showed that not only it is easy to interact with the trace, but also that esReven integrates really well with third party tools such as IDA or Volatility in this case.

Generally speaking, since esReven allows us to instantly time-travel in memory, and that all memory accesses are indexed, dealing with hidden behavior or kernel exploits is very straightforward.

Β 

To go further

Β 

For more information about Reven, have a look at the following:

  • This blog entry from Cisco Talos, showing how to prove or disprove exploitability of a crash
  • This blog entry from eShard, showing how to analyze a Use-After-Free in Internet Explorer
  • This blog entry from Thanh Dinh TA, reversing a deeply obfuscated challenge
  • This white paper from Luc Reginato, presenting an updated analysis of PatchGuard on Windows 10 RS4

Β 

Β  esReven_Banner.png

Share

Categories

All articles
(99)
Case Studies
(2)
Chip Security
(29)
Corporate News
(11)
Expert Review
(3)
Mobile App & Software
(27)
Vulnerability Research
(35)

you might also be interested in

Vulnerability Research
Corporate News

Introducing esReverse 2024.01 β€” for Binary Security Analysis

4 min read
Edit by Hugues Thiebeauld β€’ Mar 13, 2024
CopyRights eShard 2024.
All rights reserved
Privacy policy | Legal Notice