Roll your own 64-bit Linux reverse TCP shellcode

Reverse TCP or “connect-back” shellcode connects to a predetermined host and presents a shell from the system where the code is running. If you didn’t already know that, or you don’t understand what that means, you’re in the wrong place. You should probably backtrack to the intro to 64-bit Linux shellcode tutorial or your local library before proceeding further.

The recipe

The shellcode and its prototype each take the following steps:

  1. Run setreuid() so execve() can run with maximum privileges.
  2. Create a new socket file descriptor with socket().
  3. Populate the sockaddr_in data structure with the destination ip, port and connection type.
  4. Using the information from sockaddr_in, create a TCP connection with connect(). If the connection fails, exit.
  5. Designate the socket as the source and destination for stdin, stdout and stderr.
  6. When everything else is done, use execve() to execute /bin/sh.

A zip file containing the files from this post can be found here.

Connect-back prototype in C

The functionality of reverse-tcp shellcode is demonstrated by the following C program, which connects to localhost:4444 and presents a shell from its host system (which should also be localhost, unless something strange happened).

When a tcp listener is established on HOST:PORT (designated by the precompilation #defines) with the command  netcat -l 4444 and the connect-back program is run, it creates a shell on the system where it’s running and forwards all input and output from the shell to the listening port on the remote host. To test the prototype or subsequent examples, open two terminals. In the first, type  netcat -l 4444. In the second, run the connect-back executable:

When the connect-back program (shellcode or prototype) connects to the host running netcat, netcat will print a newline. Since we didn’t give any arguments to /bin/sh when we called it from execve(), the connect-back shell won’t print an actual prompt. Try typing a command and hitting enter anyway and it should work.

Reverse-connect Shellcode Prototype

The following code is an assembly prototype that implements the same functionality as the C connect-back routine:

The sequential blocks of instructions perform the same steps, in the same order, as the c routine. Some of the registers and syscalls may be a little disorienting at first, but hopefully the comments help. The most disorienting part of the process (for me at least) was recreating the sockaddr_in structure and pushing it onto the stack so that everything ends up in the right place. sockaddr_in is defined as follows:

In memory, sockaddr_in looks like this:

To create a sockaddr_in structure, the assembly routine pushes eight zero bytes onto the stack, followed by a sequence of bytes that represents the connection family (AF_INET), the destination port and ip address. These values are represented by the sequence 0x0100007f5c110002, where 0100007f is the long int, network byte-order representation of 127.0.0.1, 5c11 is the network-order hex representation of the port number 4444 and 0002 represents AF_INET. Once the contents of the sockaddr_in structure have been pushed onto the stack, esp functions as the pointer to the data.

Running the reverse-connect prototype through nasm2shell shows that the assembly isn’t fit for shellcode yet. For starters, each mov instruction generates a bunch of nulls. Replacing each mov with xor+add instructions cleans up most of the nulls with one, key exception: The IP address, port and connection family bytes in the sockaddr_in structure. The data in the sockaddr struct is crucial, so we can’t get rid of it or fix it by changing instructions. We’ll have to encode it without nulls somehow.

The Finished Connect-back shellcode

The final connect-back assembly routine looks like this:

The shellcode’s assembly routine follows the same recipe as the C and assembly prototypes. mov instructions have been replaced with xor+add, and the process of duplicating the socket file descriptor has been turned into a loop.

Encoding Nulls

The biggest difference between the shellcode routine and its prototypes is the treatment of the data in the sockaddr_in structure. The byte array containing the destination IP, port and connection family has been added to a byte array containing 0×0101010101010101. This additive de-nulling transformation is a classic trick. The addition transforms the original null-containing byte array into a null-free array that is safe for shellcode. To recover the original byte array, 0×0101010101010101 is subtracted from the stored value at runtime and the code proceeds as it did before.

Connect-back shellcode generator

Given an IP address and port, the following C program will generate the connect-back shellcode automatically, including correction for null bytes:

The generator’s functions are pretty straightforward, so the details are left as an exercise to the reader.

The zip file containing the files from this post can be found here.

Bonus

On most linux distributions, the following bash one-liner will function in the same way as reverse TCP shellcode:

A similar technique is used by some reverse-connect shellcode.

 

Incoming search terms:

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">