Tuesday, April 26, 2011

Episode #144: What the Hex?

Tim has a sugar high

Recently, I've been going through some exploit development tutorials. One of the exploits was for a file format vulnerability. I created my malicious file and saved it on my Windows machine, and I wanted to take a quick peek at the file and confirm that I had written the correct information. I wanted to take a look at the bytes, but not all the bytes are printable. Of course there are a million ways to view this file, but I decided to try PowerShell since I didn't have any other tools installed in this clean install of Windows.

PS C:\> get-content -encoding byte -totalcount 1000 shellcode.bin
80
83
81
82
86
87
85
156
...


This uses the good ol' Get-Content cmdlet. It reads raw bytes by setting the Encoding parameter to Byte. I used the TotalCount parameter since I only want to see the first 1000 bytes.

Of course, the output isn't nice. First, the output is in decimal form instead of hex. We can quickly fix that:

PS C:\> get-content -encoding byte -totalcount 1000 shellcode.bin | % { "{0:X2} " -f $_ }
50
53
51
52
56
57
55
9C
...


We use the ForEach-Object cmdlet (alias %) to format each byte as hex. Now to fix the second output option, the vertical display.

PS C:\> (get-content -encoding byte -totalcount 1000 shellcode.bin | % { "{0:X2}" -f $_ }) -join " "
50 53 51 52 56 57 55 9C ...


Simply wrapping the entire command in paranthesis and using the Join operator effectively rotates our output.

If you want a different format you can modify the format string. Say we wanted it with a prepended '\x'.

PS C:\> (get-content -encoding byte -totalcount 1000 shellcode.bin | % { "\x{0:X2}" -f $_ }) -join " "
\x50 \x53 \x51 \x52 \x56 \x57 \x55 \x9C ...


Not to bad huh? Of course, this is super simple for Hal. <Sigh>

Hal is still Bali Hai

Thanks for taking it easy on me as I'm coming down off my vacation, Tim. How's that competition snow shoveling working out for you?

As Tim points out, this one is easy for Unix because (being a programmers' operating system) we have built-in hex dumpers. The old standby is the "od", or "octal dump" command. Despite the name, od can output in a variety of formats, including hex:

$ od -N 48 -x /bin/bash
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000020 0002 003e 0001 0000 f210 0041 0000 0000
0000040 0040 0000 0000 0000 3a80 000e 0000 0000
0000060

Here I'm using the "-N" option to only dump out the first 48 bytes of the file, and "-x" specifies that I want the output in hex format. If I wanted the output grouped as single bytes rather than pairs, I could use a slightly different option:

$ od -N 48 -t x1 /bin/bash
0000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
0000020 02 00 3e 00 01 00 00 00 10 f2 41 00 00 00 00 00
0000040 40 00 00 00 00 00 00 00 80 3a 0e 00 00 00 00 00
0000060

The "-t" option lets you specify the output format more completely. The first letter denotes the type of output you want: "x" for hex, "o" for octal, "a" and "c" for character types, "f" for floating point, and so on. The number following the letter lets you choose the size groups you want in the output.

But since I generally only ever want hex dumps, I usually use xxd instead of od:

$ xxd -l 48 -g 1 /bin/bash
0000000: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 .ELF............
0000010: 02 00 3e 00 01 00 00 00 10 f2 41 00 00 00 00 00 ..>.......A.....
0000020: 40 00 00 00 00 00 00 00 80 3a 0e 00 00 00 00 00 @........:......

xxd is a pure hex dumper (although it can dump bits if you use "-b") so we don't need a special option to output hexadecimal. Use "-l" to specify how many bytes you want to read, and "-g" to specify the number of bytes for grouping the output. Like od, the default output grouping is 2 bytes, but I specified 1 byte output in the command above.

If you don't want all the extra frippery that the normal xxd output gives you-- like byte offsets and ASCII translation-- you can use the "-p" (plain) option to just get the raw bytes:

$ xxd -p -l 48 /bin/bash
7f454c4602010100000000000000000002003e000100000010f241000000
00004000000000000000803a0e0000000000

This format is particularly useful when you want to pipe the output into something else. For example, I could now use sed to produce the "\x" notation similar to Tim's last example:

$ xxd -p -l 48 /bin/bash | sed 's/\(..\)/\\x\1 /g'
\x7f \x45 \x4c \x46 \x02 \x01 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x02 ...
\x00 \x00 \x40 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x80 \x3a \x0e \x00 \x00 \x00 \x00 \x00

Now if I could only figure out a way to use the shell to dump myself as quickly from one side of the Pacific to the other, that would be quite a feat! Oh well, perhaps the long flight will inspire me with some new shell fu for next week.