Metasploit exec Analysis with Libemu (SLAE Exam Assignment #5.3)

My last SLAE assignment #5 solution is my Metasploit exec analysis.

Metasploit chmod Analysis - Introduction

One more shellcode to analyze, and one more tool to use.

In this case, I will be analyzing the exec shellcode using libemu.

For more information on installation and configuration, you can see my earlier blog post.

I was originally planning on analyzing the chmod shellcode, but I ran into a few issues. It turns out that libemu chokes/breaks on a lot of the Metasploit payloads. If you have any ideas what might cause this, then I'd love to know!

Since I've already written my bind/reverse shells, I figured execve is good enough to show off some libemu usage.

Exec Shellcode - Payload Generation

For the exec payload, we just need to set a file to change and the file mode.

doyler@slae:~/slae/_exam/msf_analysis$ msfvenom -p linux/x86/exec --payload-options
Options for payload/linux/x86/exec:


       Name: Linux Execute Command
     Module: payload/linux/x86/exec
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 36
       Rank: Normal

Provided by:
    vlad902 

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
CMD                    yes       The command string to execute

Description:
  Execute an arbitrary command

In this case, I decided to cat /etc/passwd, similar to my earlier post.

Payload Execution

With my options selected, I generated the payload that I wanted.

doyler@slae:~/slae/_exam/msf_analysis$ msfvenom -p linux/x86/exec CMD='cat /etc/passwd' -f c
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: 51 bytes
Final size of c file: 240 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\x10\x00\x00\x00\x63"
"\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00"
"\x57\x53\x89\xe1\xcd\x80";

Next, I added the payload to my wrapper program and executed. As usual, the shellcode length is incorrect due to null bytes. That said, the passwd file properly printed!

doyler@slae:~/slae/_exam/msf_analysis$ gcc -o shellcode -z execstack -fno-stack-protector shellcode.c 
doyler@slae:~/slae/_exam/msf_analysis$ ./shellcode
Shellcode Length: 15
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh

Metasploit exec Analysis - Libemu

First, I ran the shellcode through libemu's sctest binary.

The -vvv flag increases the verbosity, -S reads the shellcode from stdin, -s runs the code up to 100k steps, and -G outputs the call graph to a dot file.

doyler@slae:~/libemu/tools/sctest$ msfvenom -p linux/x86/exec CMD='cat /etc/passwd' -f raw | sudo ./sctest -vvv -Ss 100000 -G metasploit_exec.dot
graph file metasploit_exec.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: 51 bytes

Libemu CPU States

As you can see, Libemu tracks operation execution, and the state of each register.

The following instructions get the registers ready for the system call.

[emu 0x0x8997090 debug ] cpu state    eip=0x00417000
[emu 0x0x8997090 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] cpu state    eip=0x00417000
[emu 0x0x8997090 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 6A0B                            push byte 0xb
[emu 0x0x8997090 debug ] cpu state    eip=0x00417002
[emu 0x0x8997090 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 58                              pop eax
[emu 0x0x8997090 debug ] cpu state    eip=0x00417003
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 99                              cwd 
[emu 0x0x8997090 debug ] cpu state    eip=0x00417004
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 52                              push edx
[emu 0x0x8997090 debug ] cpu state    eip=0x00417005
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 66682D63                        push word 0x632d
[emu 0x0x8997090 debug ] cpu state    eip=0x00417009
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fc8  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 89E7                            mov edi,esp
[emu 0x0x8997090 debug ] cpu state    eip=0x0041700b
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fc8  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 682F736800                      push dword 0x68732f
[emu 0x0x8997090 debug ] cpu state    eip=0x00417010
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fc4  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 682F62696E                      push dword 0x6e69622f
[emu 0x0x8997090 debug ] cpu state    eip=0x00417015
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8997090 debug ] esp=0x00416fc0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 89E3                            mov ebx,esp
[emu 0x0x8997090 debug ] cpu state    eip=0x00417017
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fc0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 52                              push edx
[emu 0x0x8997090 debug ] cpu state    eip=0x00417018
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fbc  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] E8                              call 0x1
[emu 0x0x8997090 debug ] cpu state    eip=0x0041702d
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb8  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 57                              push edi
[emu 0x0x8997090 debug ] cpu state    eip=0x0041702e
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb4  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 53                              push ebx
[emu 0x0x8997090 debug ] cpu state    eip=0x0041702f
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00000000  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 89E1                            mov ecx,esp

As you can see, the registers are all properly set before the program executes the syscall.

[emu 0x0x8997090 debug ] cpu state    eip=0x00417031
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00416fb0  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] CD80                            int 0x80
execve
int execve (const char *dateiname=00416fc0={/bin/sh}, const char * argv[], const char *envp[]);
[emu 0x0x8997090 debug ] cpu state    eip=0x00417033
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00416fb0  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
[emu 0x0x8997090 debug ] 0000                            add [eax],al
cpu error error accessing 0x00000004 not mapped

stepcount 15

For your reference, this is how the registers look before execution:

  • EAX - 0xb (sys_execve)
  • EBX - 0x00416fc0 (pointer to the filename, `/bin/sh`)
  • ECX - 0x00416fb0 (pointer to the argv string, `-c 'cat /etc/passwd'`)
  • EDX - 0x0 (envp)

To verify this, I also ran a quick strace on my binary.

doyler@slae:~/slae/_exam/msf_analysis$ strace -e execve ./shellcode
execve("./shellcode", ["./shellcode"], [/* 36 vars */]) = 0
Shellcode Length: 53
execve("/bin//sh", ["/bin//sh", "-c", "cat /etc/passwd"], [/* 0 vars */]) = 0
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh

Once the execution is complete, libemu begins generating the dot file.

copying vertexes
optimizing graph
vertex 0x89ee3d8
going forwards from 0x89ee3d8
 -> vertex 0x89f0578
 -> vertex 0x89f0788
 -> vertex 0x89f0968
 -> vertex 0x89f0a48
 -> vertex 0x89f0d00
 -> vertex 0x89f0dd0
 -> vertex 0x89f0f38
 -> vertex 0x89f1130
 -> vertex 0x89f1318
 -> vertex 0x89f1490
 -> vertex 0x89f1608
 -> vertex 0x89f1780
 -> vertex 0x89f18f8
copying edges for 0x89f18f8
 -> 0x89f4c40
vertex 0x89f1a70
going forwards from 0x89f1a70
copying edges for 0x89f1a70
vertex 0x89f1ef8
going forwards from 0x89f1ef8
copying edges for 0x89f1ef8

Finally, libemu also generates some pseudo-code! This is incredibly handy to see the program and methods. Additionally, it is useful for converting shellcode back into an actual C program.

[emu 0x0x8997090 debug ] cpu state    eip=0x00417035
[emu 0x0x8997090 debug ] eax=0x0000000b  ecx=0x00416fb0  edx=0x00000000  ebx=0x00416fc0
[emu 0x0x8997090 debug ] esp=0x00416fb0  ebp=0x00000000  esi=0x00000000  edi=0x00416fc8
[emu 0x0x8997090 debug ] Flags: 
int execve (
     const char * dateiname = 0x00416fc0 => 
           = "/bin/sh";
     const char * argv[] = [
           = 0x00416fb0 => 
               = 0x00416fc0 => 
                   = "/bin/sh";
           = 0x00416fb4 => 
               = 0x00416fc8 => 
                   = "-c";
           = 0x00416fb8 => 
               = 0x0041701d => 
                   = "cat /etc/passwd";
           = 0x00000000 => 
             none;
     ];
     const char * envp[] = 0x00000000 => 
         none;
) =  0;

Graphing and Visualization

Once libemu completed its execution, I used the `dot` command to convert the dot file into a png

doyler@slae:~/libemu/tools/sctest$ dot metasploit_exec.dot -Tpng -o metasploit_exec.png

As you can see, libemu also generates an awesome little control flow graph! While this one isn't super complex, they can get pretty in-depth.

Metasploit exec Analysis - Control Flow Graph

Null Removal and the Code

In the case of this shellcode, there were five null bytes. Three were for the relative call, one was in the /bin/sh string, and one was at the end of /etc/passwd.

Unfortunately, I ended up increasing the length of the shellcode by two bytes. This was due to the JMP-CALL gadget adding one byte, and my null termination of /etc/passwd adding another.

>
doyler@slae:~/slae/_exam/msf_analysis$ for i in $(objdump -d exec |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo
\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\xeb\x06\x57\x53\x89\xe1\xcd\x80\xe8\xf5\xff\xff\xff\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64
doyler@slae:~/slae/_exam/msf_analysis$ vi shellcode.c 
doyler@slae:~/slae/_exam/msf_analysis$ gcc -o shellcode -z execstack -fno-stack-protector shellcode.c 
doyler@slae:~/slae/_exam/msf_analysis$ ./shellcode

Shellcode Length: 53
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh

You can find my version of the shellcode below.

; Filename: metasploit_exec.nasm
; Author: Ray Doyle (@doylersec)
; Website: https://www.doyler.net
;
; Purpose: SLAE Exam Assignment #5 - Metasploit exec shellcode (Linux/x86) for `cat /etc/passwd` with no null bytes

global _start

section .text

_start:
   push 0xb
   pop eax
   cdq
   push edx
   push word 0x632d
   mov edi,esp
   push edx
   push 0x68732f2f
   push 0x6e69622f
   mov ebx, esp
   push edx

pre_exec:
   jmp call_exec

exec:
   push edi
   push ebx
   mov ecx,esp
   int 0x80

call_exec:
   call exec
   command: db "cat /etc/passwd"

Metasploit exec Analysis - Conclusion

I wish libemu worked on more of the Metasploit shellcodes, but this is still a great tool to use.

This concludes assignment #5, so only two more to go!

Next week is polymorphic shellcode, so back to at least modifying some assembly.

Finally, you can find the code and updates in my GitHub repository.

SLAE Exam Requirement

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

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCP, eCPPT, eWPT, eWPTX, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Senior Penetration Testing Consultant for Secureworks. His previous position was a Senior Penetration Tester for a major financial institution.

When he's not figuring out what cert to get next (currently GXPN) or side project to work on, he enjoys playing video games, traveling, and watching sports.

Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.