Posts Tagged bind tcp
Assignment 1: Shell bind TCP shellcode
Posted by msstavros645 in Shellcode on January 26, 2015
Create a Shell_Bind_TCP shellcode that (a) binds to a port, and (b) executes a shell on incoming connection. The port number should be easily configurable.
In order to work with sockets, we need first to determine the syscall number to use. A look in /usr/include/i386-linux-gnu/asm/unistd_32.h shows the socketcall syscall is number 102 (0x66).
The man page for socketcall is presented below:
So in order to work with sockets, we need to also look into the different functions (accept, bind etc). We can find the valid socket function parameters in /usr/include/linux/net.h file:
The man page for the socket function:
So, the socket function is defined as:
int socket (int domain, int type, int protocol)
The address family values (domain) can be found in /usr/src/linux-headers-3.13.0-37/include/linux/socket.h

The socket type values can be found in /usr/src/linux-headers-3.13.0-37/include/linux/net.h

The protocol values are defined in /usr/include/linux/in.h
From all the above we deduce that in order to create a TCP socket we need to pass the following parameters to the socket function:
• Domain: AF_INET (2)
• Type: SOCK_STREAM (1)
• Protocol: TCP(6)
Let’s try to translate all that into assembly instructions. The system call is 0x66 which should be stored into EAX. EBX should contain 1, in order to use the socket function (effectively to create the socket). The parameters to the socket function will be pushed on the stack, in the reverse order (remember stack is LIFO) from what they appear in the function’s definition (so protocol, type, domain) and then moving the value of the ESP register to ECX, prior to making the call.
To better visualize the parameters and calling convention we can use a diagram:
If the function is successful in creating a socket, the kernel will give us a file descriptor for it, stored into EAX. The following image presents the code for creating the socket:
After creating the socket, we need to:
• Bind it to a port and ip address
• Make it listen for connections
• Accept a connection and execute the shell
First the bind. The man page tell us the following:

From the above, we can see bind expects 3 parameters. First is the socket file descriptor, then a pointer to the sockaddr structure (containing socket parameters) and then the length of this structure. The length should be 14 bytes for sa_data (port and ip address) 2 for the family, 16 bytes in total. Looking at the ip(7) page (man 7 ip) we can see the definition for the sockaddr structure pointer:

The address to bind will be passed through sin_addr:

Since, we do not know a priori the ip address of the host that the shellcode will run on, we will need to pass the INADDR_ANY value. This can be found again in /usr/include/linux/in.h file:

So the INADDR_ANY is 0. If we try to pass this directly, we will introduce NULL bytes to the shellcode. Therefore we will need to cater for that by pushing a zeroed out register instead of the actual 0x00 value we need. Remember that the sockaddr structure must be 16 bytes long. The following diagram aids in visualizing the various parameters (we will bind on port 31452, 0x7ADC):

The tricky part here is the sockaddr structure. For IPv4, this is expected to be 16 bytes long. The values will be laid out as follows:
• Family (AF_INET): 0x0002
• Port (31452): 0x7adc
• IP Address (IPADDR_ANY): 00 00 00 00
• Zero padding: 00 00 00 00 00 00 00 00
All these must be pushed on the stack in reverse order. There are a lot of NULL bytes in this structure that we need to avoid. We will need to push 12 zeros, then the port, then the 0x02 value as word (2 bytes). To get the zeroes, we can use three pushes of a full register, zeroed out (i.e. ESI). The following instructions accomplish that:

After these, the stack holds all the necessary data for the sockaddr structure, and we can store the value of ESP into ECX, to get ready for setting up the stack one more time, for the parameters to the sys_socketcall syscall. The complete bind() call code is presented below:

Having completed the bind, we then need to enable the socket to listen for connections. This is accomplished via the listen() function.

Just two parameters for this function, the socket file descriptor, and a value for the backlog, say 15. The parameter visualization is presented below.

The code for the listen() then can be written.
Finally, we need to accept connections and execute a /bind/sh upon incoming connection. In order to accomplish that, we will need to call the accept() function for the socket, but we will need to communicate with this shell via the socket. This can be done by redirecting the standard input, output and error descriptors of the spawned shell, to our socket. This is valid and characteristic of Unix operating systems, where everything is a file, or as Linus himself said “everything is a stream of bytes” (see http://yarchive.net/comp/linux/everything_is_file.html)
Let’s look at the accept man page:

It takes the socket file descriptor, and two pointers that will store the details of the peer socket (effectively, the client’s port and ip address when it connects to us). These two pointers should be initialized to 0. Care should be taken here, to the fact, that accept() will return a new socket file descriptor (for the client socket), which we will need to use in the input/output/error redirection latter on.

Here is the parameter diagram:

The code for accept() can now be written:

We are almost done. We need to do the standard input, output and error redirection to our socket and then finish off with the execve-stack code that will be executed upon connection. Remember that the socket file descriptor we will use, is the one from the previous accept() syscall. For the redirection the sys_dup2 syscall will be used.

This is straightforward. We will pass only our socket file descriptor from the accept() call. This value is currently stored in EBX, as shown at the end of the accept() code segment above. Remember that the number representations for the 3 file descriptors are:
• Standard input: 0
• Standard output: 1
• Standard error: 2
We can use a register initialized to 2 and loop until 0 in order to have less instructions in the shellcode. The system call number for dup2() is 63, 0x3F (in unistd_32.h)
The following code accomplishes the duplication:

The last part is the execve-stack code, which is presented below:

We are now ready to compile our assembly code. Compile it, and check if there are any null bytes.

Then extract the shellcode and paste it into the C file that will execute it.
For the extraction we can create a simple bash script which executes an objdump and applies some commandlinefu (http://www.commandlinefu.com/commands/view/12151/get-shellcode-of-the-binary-using-objdump, see comment by “arno”):

Copy and paste the shellcode into shellcode.c. We will need to be able to change the listening port easily, so we will write it in a single line to ease identification.

Compile and execute the code:

On a new terminal, execute a netstat to see the listening ports:
Our shellcode seems to be listening. We connect to the port using netcat and execute a command or two (commands entered shown with red arrows):

Upon pressing Ctrl-C the program terminates and the socket is closed.
We can also see the various system calls of our shellcode, by running it under strace:

First we have the socket call, which returns the file descriptor number 3. The bind and listen are successful (observe the file descriptor value in the parameters passed to them). Accept is also successful and returns back the file descriptor 4. This is used for the three dup calls, and finally the execve is executed for /bin//sh.
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-645









Recent Comments