Friday, November 12, 2010

Quick checks on VxWorks images - part 1

In GNIF, we are seeing lots of different equipments being deployed for running networks. Many of them are working with VxWorks, especially version 5.5 that is common. It is a real-time OS supplied by WindRiver. For some initial views (still quite complete) on the particularity of this OS and its analysis, you can report to the following posts:

- Matasano
- HD Moore
- Newsoft

This OS is running on many different systems, such as helium balloon for expanding satellite network or IP-enabled fridge and microwave oven. GNIF is proud to provide you some quick results on applying some existing reversing techniques on these systems.

In this 1st part on VxWorks, we are not going to dive into the system itself, but just going to check what you have in your hands when you get such a firmware. Let's go with the helium balloon: we have a binary file of some MB of data suffixed with a .bz, however file indicate it's just data. Let's open it with an hex-editor: we can first see an ascii header followed by hex data.

$ strings -a | head -20
AZC File Signature
* Header Length : 358 Bytes
* Product Version : Rel_9_0_0_8666
* Date & Time : Wed Nov 09 12:03:31 2004
* Code Length : 2358544 Bytes
* Bootrom Length : 176500 Bytes
* Unit Type : PIPO
* HW Revision : 8
* SW Type : S
************* End of Header *****************

The data following the header is very entropic. One can guess it is compressed data, thanks to the zlib magic number few bytes after the end of the header: 0x789c. Furthermore, from the header, it looks like we have 2 images (one system and one bootrom). So we will use the most basic strategy to uncompress thoses files: the brute-force! Scan the file for the magic bytes 0x789c, and try to uncompress from the offset... and see what you get.

In few lines of python:

fd = open('', 'ro')
a =; fd.close()
from zlib import decompress
of, f = 0, a.find('\x78\x9c')
while f >= 0:
    of += f
        data = decompress( a[of:] )
        print 'decrompressed at: 0x%x' % of
    f = a[of+2:].find('\x78\x9c')
    of += 2

This returns the following address:
decrompressed at: 0x210
decrompressed at: 0x2b384

OK, we have our 2 offsets corresponding to our 2 parts; furthermore, we see that the size of the compressed sections is equal to the length provided in the text header. We can now decompress it in files to check it further.

In [107]: fd = open('p1', 'wb')
In [108]: fd.write( decompress( a[0x210:] ))
In [109]: fd.close()
In [112]: fd = open('p2', 'wb')
In [113]: fd.write( decompress( a[0x2b384:] ))
In [114]: fd.close()
In [115]: !ls -l
total 11740
-rw-r--r-- 1 prout users 2535572 Dec 2 14:31
-rw-r--r-- 1 prout users 178685 Dec 2 15:06 p1
-rw-r--r-- 1 prout users 9065873 Dec 2 15:07 p2

That's it!
Now let's move to the image of the IP-enabled fridge. Again, we have a file suffixed with .bin. File command does not recognize it => hexedit.

$ hexedit image.bin
00000000 76 65 72 20 39 38 32 00 00 00 00 00 00 00 00 00 ver 982.........
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 01 01 63 00 00 07 85 53 00 00 01 00 00 00 00 00 ..c....S........
00000050 D6 0F E5 B9 66 00 00 00 00 00 00 00 00 00 00 00 ....f...........
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000A0 08 78 9C B4 5A 0D 70 54 55 96 3E 9D 0E 49 77 88 .x..Z.pTU.>.

We have some kind of binary header with a file version, and what could be file size and checksum, and again our gzip magic number: 0x789c. After checking the size of the file section after the gzip magic bytes, we get the corresponding value in the header at offset 0x44: 0x78553. We check in the same way the CRC32 of the file section and get the corresponding value in the header at offset 0x50: 0xD60FE5B9. This is good to know if we want to patch the firmware afterwards.
Now, we can apply the same decompressing script and get a single system image.

We have some VxWorks system images. Next step will be to start the statical analysis, try to retrieve the VxWorks symbol table (inspired from the Matasano recipe) and retrieve the firmware loading address in order to be able to disassemble it properly.

To conclude, we have seen that VxWorks images have similarities in that they are compressed sections with zlib after a header section. However, due to the diversity of board, CPU and uC suppliers, bootloading procedures may vary and may take different kind of header format.

Friday, November 5, 2010

Friday hexadecimal entertainment

  • OllyDBG works like a charm in Wine
  • Looking into malwares on Friday is fun

Working on fridays sucks. So here is a little reverse-engineering fun.

On a supposedly "empty" USB stick, I found a weirdly-named file:
$ ls
$ file gy.cmd
gy.cmd: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

You can get it there (pass: GraLandSec).

A quick visit to Virus Total confirms that it is a Trojan. And here is something fun to do before week-end !
First, a quick look at the file with IDA, now with a native Qt interface under Linux. No need to boot a VM, my good old XP in VirtualBox is now officially half-useless (as we will see later, we can do a lot of things with PE juste with Linux). Here is what the flow-chart looks like at the entrypoint:

Very simple and linear, except for what looks like a loop at the end. Let's zoom in:

This really looks like a decoding loop (with the memory acces sub [esi], al). After the loop, we apparently have junk / random bytes. At this point, we can say that the program is packed, with a simple decoding routine at the entrypoint. How can we continue the analysis ? Under Linux, IDA have debugging capabilities for Linux executables, or using a remote debugger.
So here comes our second tool, the best for PE32 debugging: OllyDbg. Even if it is only distributed for Windows, it runs perfectly under Wine. Lets see what our loop looks like :

We have a lot of junk code (useless instructions like add eax, N; dec eax, N). Fill it with NOPs. Looking at the bottom of the loop, we can see that ECX is the loop counter. Let's track operation on it. After a bit of cleanup, our code looks like this:

Much cleaner ! Now, we can run the program in the debugger and make it decode itself. Set a break point on the bottom of the loop, and watch it do the work ! You'll see that our counter is indeed ECX, and it is decremented at each loop. You can set a conditionnal breakpoint to make the program stop when ECX==0.
The next part is another decoding loop, similar to the first one. The decoding loop counter is in EDX, the "key" is stored in ESI, the write index is ECX. I'll let you look at it, there is a lot of funny stuff to see in this file. Happy native-PE32-linux-debugging !

Blackhat parallel sessions

A colleague who attended the last blackhat conference could unfortunately not see all the 8 parallel talks (he is not -yet- ubiquitous). Someone asked why the conference's organisators were proposing so much sessions in parallel...

The answer is quite simple: because they put 4 steaks into one single burger! That's the U.S.A.