Part 6: Writing W32 shellcode

Hello and welcome! Today we will be writing our own shellcode from scratch. This is a particularly useful exercise for two reasons: (1) you have an exploit that doesn't need to be portable but has severe space restrictions and (2) it's good way to get a grasp on ROP (Return Oriented Programming) even though there are some significant differences ROP will also involve crafting parameters to windows API functions on the stack.

To speed things up we will be using the skeleton of the "FreeFloat FTP" exploit that we created in part 1 of this tutorial series. You will also need a program called "arwin" which is a utility to find the absolute addresses of windows functions within a specified DLL. I have included all the relevant information below (the C source and a compiled version).

Introduction

I just want to say a couple of things before we get started. Firstly the shellcode we will write will be OS and build specific (in our case WinXP SP3). Secondly this technique is only possible because the OS DLL's in WinXP are not subject to base address randomization (ASLR). Thirdly Google + MSDN is your biggest friend. Finally don't be discouraged this is much easier than it sounds.

We will be creating two separate "payloads", (1) launching calculator and (2) creating a message-box popup. To do this we will be leveraging two windows API functions (1) WinExec and (2) MessageBoxA.

But first lets have a look at what the shellcode looks like when it is generate by the metasploit framework (take note of the size for later). Don't forget to encode the shellcode to filter out badcharacters.

You can test these payloads later to confirm that they work as intended. Time to see if we can live up to the metasploit framework and write our own shellcode!!

Skeleton Exploit

To make this tutorial as realistic as possible we are going to be implementing our payloads in the "FreeFloat FTP" exploit that we made for part 1 of this tutorial series. The first step is to generate our skeleton exploit, essentially we will be stripping down our previous exploit like this.

This should give us a base to work with. Any shellcode we place in the shellcode variable will be executed. As you can see in the screenshot below we reach our nopsled after stepping through the instructions at EIP.

Nopsled

ASM && Opcode

When you write your own shellcode you will obviously have to deal with assembly and opcode (hex translation of you ASM). You will need some basic knowledge of assembly (push, pop, mov, xor, etc..) nothing to dramatic. The main point here is that your shellcode will be written in opcode so you might ask yourself how do I know what the opcode is for any given instruction. I'll tell you the way I approach the problem.

If you put a breakpoint in the debugger, you can manually edit the instruction there and immunity will provide you with the opcode. In a sense you are using immunity as a dictionary. In the screenshots below you can see the opcode “translation” of several random instructions.

(1) WinExec

Before we can do anything we need to known what the WinExec function looks like and what parameters we need to feed it. You can find that information on MSDN.

Lets take this one parameter at a time. The first thing we need to find is a pointer to WinExec, arwin can help us here since kernel32.dll is non-ASLR in WinXP. Open arwin in a terminal on the debugging machine and type the following.

arwin.exe kernel32.dll WinExec

Next we need to figure out how to write our ASCII string (in this case the command we want to run) to the stack. When doing this for the first time it might seem a bit confusing but it's not that difficult. The best way to understand is by looking at the following examples.

ASCII Text: ASCII Text:
calc.exe abcdefghijkl
Split Text into groups of 4 characters: Split Text into groups of 4 characters:
"calc" "abcd"
".exe" "efgh"
"ijkl"
Reverse the order of the character groups: Reverse the order of the character groups:
".exe" "ijkl"
"calc" "efgh"
"abcd"
Look on google for a ASCII to hex converter Look on google for a ASCII to hex converter
and convert each character while maintaining and convert each character while maintaining
the order: the order:
"\x2E\x65\x78\x65" "\x69\x6A\x6B\x6C"
"\x63\x61\x6C\x63" "\x65\x66\x67\x68"
"\x61\x62\x63\x64"
To write these values to the stack simply add To write these values to the stack simply add
"\x68" infront of each group: "\x68" infront of each group:
"\x68\x2E\x65\x78\x65" => PUSH ".exe" "\x68\x69\x6A\x6B\x6C" => PUSH "ijkl"
"\x68\x63\x61\x6C\x63" => PUSH "calc" "\x68\x65\x66\x67\x68" => PUSH "efgh"
"\x68\x61\x62\x63\x64" => PUSH "abcd"

This seems pretty straight forward however you might have noticed that our ASCII text needs to be 4-character aligned so what happens when it is not? There are quite a few ways of dealing with this, I suggest you read this excellent tutorial written by corelanc0d3r. As always mastery requires effort. I will however show you one technique, look at the example below.

Finally we need to push "1" to the stack. Remember if you don’t know the opcode for an ASM instruction you can type the command live in the debugger which will translate it for you.

uCmdShow needs to be set to 0x00000001 there are a couple of ways you can do this just use your
imagination. We are going to use this:
PUSH 1 => "\x6A\x01" (not to be confused with ASCII "1" = "\x31")
(*) Just to give you an idea, something like this could also work:
xor eax,eax (zero out eax register)
inc eax (increment eax with 1)
push eax (push eax to the stack)

Putting Things Together

We are going to put these three arguments on the stack in the same order as shown on MSDN. There are two things we need to remember: (1) the stack grows downward so we need to push the last argument first and (2) lpCmdLine contains our ASCII command but WinExec doesn’t want the ASCII itself it want a pointer to the ASCII string.

This is a pretty good try but it won't work. Lets see what happens when we execute these instructions in the debugger.

Its pretty close but we can see that when WinExec is called lpCmdLine doesn't know where our ASCII command ends so it appends a ton of data to "calc.exe". We will need to terminate the ASCII string with null-bytes.

This one looks a bit more complicated but it's nothing we can't handle. The only real difference here is that we have two ASCII strings which we need to craft.

Lets start with our pointer to MessageBoxA this time we need to let arwin look in user32.dll.

arwin.exe user32.dll MessageBoxA

Good, lets craft both our ASCII strings just like before. I have cheated a bit to make sure that they are both 4-byte aligned but I encourage you to play around with it and create your own caption and text.

ASCII Text: ASCII Text:
b33f Pop the box!
Split Text into groups of 4 characters: Split Text into groups of 4 characters:
"b33f" "Pop "
"the "
"box!"
Reverse the order of the character groups: Reverse the order of the character groups:
"b33f" "box!"
"the "
"Pop "
Look on google for a ASCII to hex converter Look on google for a ASCII to hex converter
and convert each character while maintaining and convert each character while maintaining
the order: the order:
"\x62\x33\x33\x66" "\x62\x6F\x78\x21"
"\x74\x68\x65\x20"
"\x50\x6F\x70\x20"
To write these values to the stack simply add To write these values to the stack simply add
"\x68" infront of each group: "\x68" infront of each group:
"\x68\x62\x33\x33\x66" => PUSH "b33f" "\x68\x62\x6F\x78\x21" => PUSH "box!"
"\x68\x74\x68\x65\x20" => PUSH "the "
"\x68\x50\x6F\x70\x20" => PUSH "Pop "

The two other parameters that remain, hWnd and uType, need to be set to 0x00000000 which is convenient since we will need to xor a register to pad our ASCII strings in any case. We can then use that register to push null-bytes to the stack for these parameters as well.

This is the shellcode I came up with (but again, other variations are definitely possible).