SLAE64 Assignment 5 - MSFVenom Execve Analysis

6 minute read


For the fifth assignment of the SLAE64, I analyzed three payloads from msfvenom. This is the first payload, linux/x64/exec.

Execve Anaylsis

We will be analyzing the msfvenom execve payload. This payload has a customizable command that execve will execute. To simplify the analysis, the command whoami was chosen.

Generating the MSFVenom Payload

Here we generate the payload on Kali Linux and output it to the C format. This allows us to easy add it to our host shellcode.c program.

root# msfvenom -p linux/x64/exec -f c -v shellcode CMD='whoami'
Payload size: 46 bytes
unsigned char shellcode[] =

Shellcode.c Host Program

Here we add our shellcode to our C host program. We will compile our host program, and then use GDB for analysis of the execve payload.

// Shellcode Author: Bobby Cooke
// Date:             2020-04-26
unsigned char shellcode[] =
int main()
        int (*ret)() = (int(*)())shellcode;

Compile & Test Shellcode.c

root# gcc -m64 -z execstack -fno-stack-protector shellcode.c -o shellcode
root# ./shellcode

GDB Analysis


Here we will start our shellcode with the Gnu Debugger and set a breakpoint on the main function. After the breakpoint is set, we will run the program.

root# gdb ./shellcode
GNU gdb (Debian 8.3.1-1) 8.3.1
gdb-peda$ b main
Breakpoint 1 at 0x1129
gdb-peda$ r

Finding shellcode[]

We will use the GDB step-into s command to move through our program until we reach the point where execution is passed to the shellcode[] array (our execve shellcode from msfvenom).

=> 0x555555555141 <main+28>:    call   rdx
gdb-peda$ s
  • Step into rdx (shellcode[]).

Dumping MSFVenom Execve Assembly Instructions

With the instruction pointer (RIP) on the first instruction of shellcode, dump the instructions of the entire payload.

=> 0x555555558040 <shellcode>:  push   0x3b
   0x555555558042 <shellcode+2>:        pop    rax
   0x555555558043 <shellcode+3>:        cdq
   0x555555558044 <shellcode+4>:        movabs rbx,0x68732f6e69622f
   0x55555555804e <shellcode+14>:       push   rbx
   0x55555555804f <shellcode+15>:       mov    rdi,rsp
   0x555555558052 <shellcode+18>:       push   0x632d
   0x555555558057 <shellcode+23>:       mov    rsi,rsp
   0x55555555805a <shellcode+26>:       push   rdx
   0x55555555805b <shellcode+27>:       call   0x555555558067 <shellcode+39>
   0x555555558060 <shellcode+32>:       ja     0x5555555580ca
   0x555555558062 <shellcode+34>:       outs   dx,DWORD PTR ds:[rsi]
   0x555555558063 <shellcode+35>:       (bad)
   0x555555558064 <shellcode+36>:       ins    DWORD PTR es:[rdi],dx
   0x555555558065 <shellcode+37>:       imul   eax,DWORD PTR [rax],0x89485756
   0x55555555806b <shellcode+43>:       out    0xf,al
   0x55555555806d <shellcode+45>:       add    eax,0x0
gdb-peda$ x/17i $rip


<shellcode>:  push   0x3b
<shellcode+2>:        pop    rax
<shellcode+3>:        cdq
  • In the first 3 commands we can see that rax is set to 0x3b.
    • This is the system call number for execve.
  • cdq is used to clear out the rdx register
    • set it to 0x0 aka NULL

String to Stack

RDI: 0x7fffffffe100 --> 0x68732f6e69622f ('/bin/sh')

<shellcode+4>:        movabs rbx,0x68732f6e69622f
<shellcode+14>:       push   rbx
<shellcode+15>:       mov    rdi,rsp
  • Here we see the string /bin/sh being moved into the rbx register.
  • The string is then pushed to the top of the stack.
  • Once on the stack, the rdi register is set to point to the address of the string.
  • For the execve system call, rdi holds a pointer to the command that will be executed.

Shell Flag

RSI: 0x7fffffffe0f8 --> 0x632d ('-c')

<shellcode+18>:       push   0x632d
<shellcode+23>:       mov    rsi,rsp
<shellcode+26>:       push   rdx
  • Here we see that rdi points to the string -c
  • The push rdx null terminates the string.

Sneaky System Call

<shellcode+27>:       call   0x555555558067 <shellcode+39>
<shellcode+39>:       push   rsi
<shellcode+40>:       push   rdi
<shellcode+41>:       mov    rsi,rsp
<shellcode+44>:       syscall
  • Here we see a sneaky system call.
  • At first look, GDB did not even show us a system call, but as we step through the shellcode we see that it was being obfuscated by the call instruction.

The Command String

When the shellcode performs the call instruction, this pushes the memory address of the instruction after call onto the top of the stack. In this case the next instruction after the call is actually the string whoami.

0x55555555805b <shellcode+27>:       call   0x555555558067 <shellcode+39>
0x555555558060 <shellcode+32>:       ja     0x5555555580ca
0x555555558062 <shellcode+34>:       outs   dx,DWORD PTR ds:[rsi]
0x555555558063 <shellcode+35>:       (bad)
0x555555558064 <shellcode+36>:       ins    DWORD PTR es:[rdi],dx

gdb-peda$ x/s 0x555555558060
0x555555558060 <shellcode+32>:  "whoami"

The System Call

Here we see everything setup perfectly to execute the command /bin/sh -c whoami with the execve system call.

RAX: 0x3b (';')
RDX: 0x0
RSI: 0x7fffffffe0d8 --> 0x7fffffffe100 --> 0x68732f6e69622f ('/bin/sh')
RDI: 0x7fffffffe100 --> 0x68732f6e69622f ('/bin/sh')
RSP: 0x7fffffffe0d8 --> 0x7fffffffe100 --> 0x68732f6e69622f ('/bin/sh')
0000| 0x7fffffffe0d8 --> 0x7fffffffe100 --> 0x68732f6e69622f ('/bin/sh')
0008| 0x7fffffffe0e0 --> 0x7fffffffe0f8 --> 0x632d ('-c')
0016| 0x7fffffffe0e8 --> 0x555555558060 --> 0x5600696d616f6877 ('whoami')
0024| 0x7fffffffe0f0 --> 0x0

SLAE64 Blog Proof

This blog post has been created for completing the requirements of the x86_64 Assembly Language and Shellcoding on Linux (SLAE64):
SLAE/Student ID: PA-10913