Assignment 1 – TCP Bind Shell
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-1112
This is the first from seven assignments in order to complete the SLAE (32bit) certification.
The objective of the first assignment is to create a TCP Bind Shell shellcode with the following requirements:
- Binds to a local port
- Execs a shell on incoming connection
- The port number should be easily configurable (via wrapper)
In order to create the bind shell it’s necessary to use several syscalls in a specific order. The shellcode can divided in six parts:
- Creat the Socket
- Bind the Socket to an Address/Port
- Listen for incoming connections
- Accept a new connection
- Redirect stdin, stdout and stderr to the Socket via dup2
- Call Execve to run /bin/sh
The following website will be used as a reference throughout the rest of the Assignment:
Create the Socket
In order to use this syscall we need to set al to its syscall number (0x66).
The Socketcall documentation helps us to understand the required arguments in order to create the socket:
- call – determines which socket function to call.
- args – points to a block containing the arguments.
The function call we are looking for is SYS_SOCKET, which creates an endpoint for communication and returns a file descriptor that refers to that endpoint. According to the file /usr/include/linux/net.h, the value for SYS_SOCKET is 1. This value is passed to ebx.
In the Socket documentation we can obtain the function’s syntax. It requires three integers:
- domain – specifies a communication domain.
- type – specifies the communication semantics.
- protocol – specifies a particular protocol to be used with the socket.
In order to create a TCP Socket we need to push into the stack the protocol value (0), type value SOCK_STREAM (1) and domain value AF_INET (2) .
The following code snippet summarize the previous explanation:
The socket file descriptor is then returned to eax.
Bind the Socket to an Address/Port
The following task at hand is to bind the socket to Address 0.0.0.0 and Port 4444.
We’ll start by saving the file descriptor previously returned to eax in edi.
We will use the function call SYS_BIND in order to assign an address to the socket. Using /usr/include/linux/net.h, we find out that the value for SYS_BIND is 2.
Bind requires 3 arguments, a socket file descriptor, a structure called sockaddr and an address length.
Sockaddr is composed by sin_family (Address family), sin_port (Port number) and a structure called sin_addr (Address).
First, lets create the sockaddr structure. We start by pushing into the stack the value 0, indicating that the address we will bind the socket to is 0.0.0.0, followed by the port (4444) and finally the value 2 (address family AF_INET).
Then we save this structure to ecx. Now that we have the sockaddr structure ready, we need to push into the stack the bind function arguments. First of all we need to push into the stack the value 16 (address length), followed by the previously created sockaddr structure and finally the file descriptor that we have on edi.
At this point we have everything ready to perform the syscall:
Listen for incoming connections
The next stage is to listen for incoming connections. In order to to this we will use the function call SYS_LISTEN. The value of SYS_LISTEN is 4.
The arguments of Listen are the file descriptor and a backlog:
Accept a new connection
Now that our socket is listening for incoming connections we need to configure it to accept them. For that purpose we will use SYS_ACCEPT. The arguments for accept are a file descriptor and the pointers addr and addrlen which we will set to NULL:
Redirect stdin, stdout and stderr to the Socket via dup2
Now that our Socket can accept connections we need to redirect the file descriptors stdin (0), stdout (1) and stderr(2) to the client socket file descriptor. To accomplished this we will use SYS_DUP2 syscall.
In order to use it we need to set eax to 0x3F (sys_dup2 syscall number), ebx to the old file descriptor and ecx to a new file descriptor.
Since we need to call sys_dup2 three times, a loop is going to be used:
Call Execve to run /bin/sh
Now that stdin, stdout and stderr have been redirected to the client socket file descriptor, we need to execute a /bin/sh.
For that we’ll use SYS_EXECVE. Execve() have three arguments, a pointer to the filename we want to execute, an array of arguments strings passed to the new program (argv) and an array of strings that are passed as environment to the new program (envp):
After assembling and linking the file and executing our binary we get a bind shell on Port 4444.
The last objective to accomplish is to make the port number easily configurable. In order to achieve this I extracted the shellcode from the binary file using objdump and identified the bytes that represent the port number (highlighted in red in the following image):
With this, all I had to do was create a Python script that would concatenate all the bytes prior to the port with a new port bytes followed by the rest of the shellcode.
The port is passed by argument and can take all values ranged from 1 to 65535. Note that if you provide a port lower than 1024 the shellcode must be executed as root. Another feature of the script is to detect if the port generates a nullbyte (e.g. port 1024 would generate the following bytes: \x04\x00).
Here is an example of the output of the script:
The full code can be found in my SLAE Github repository.