Msfvenom Exec Payload Analysis

4 minute read


If we search on internet we will find a lot of ready to use shellcodes of various types, somes are for simple command execution, others adds “secret users” in victim machine, others are bind and reverse shell like the shellcodes wrote in this blog. The question is, shall we trust shellcodes found in internet? Following the general rule “Trust no one” the answer should be a big No, but sometime, for example when we have limited time, we prefer or we are forced to use others shellcode.
In this cases what we suggest is to analyze the downloaed shellcode in sandbox machine before use it, to ensure that it will do what it declare.
For this post we want to show how to analyze 3 samples of shellcodes took from msfvenom payload tool. We can use the msfvenom tool to list payloads that could be produced:

root@slae32-lab:# msfvenom -l payloads |grep linux/x86

We have already build (and analyzed) the bind and reverse shellcode types so we choosed this 3 shellcode samples:

  • linux/x86/adduser “Create a new user with UID 0”
  • linux/x86/chmod “Runs chmod on specified file with specified mode”
  • linux/x86/exec “Execute an arbitrary command”

So let’s start our analysis


First thing, we must create the payload with msfvenom

root@slae32-lab:# msfvenom -p linux/x86/exec CMD=id -f C -a x86 --platform linux
No encoder or badchars specified, outputting raw payload
Payload size: 38 bytes
Final size of c file: 185 bytes
unsigned char buf[] = 

Now we need to analyze it with ndisasm, using the command

root@slae32-lab:# echo -ne "\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\x03\x00\x00\x00\x69\x64\x00\x57\x53\x89\xe1\xcd\x80" | ndisasm -u -

We have one syscall also in this case, the execve

We have already saw the execve syscall, let’s resume it:

  • EAX register contains the execve syscall hexadecimal value (11 or 0xb)
  • EBX register contains the pointer to the filename that should be executed, in our case /bin/id, reverted because we are working in little endian environment.
  • ECX contains a pointer to argv that is an array of argument strings passed to the new program, in our case is the address of the filename to execute, the argv[0]
  • EDX contains a pointer to envp that is an array of strings of the form key=value wich are passed as environment to the new program.

Tha man page tell us also the all the 3 arguments are pointer, because we are talking about pointer to strings we need to remember that all the arguments has to terminate with a NULL char. The argv should contain the address of the filename, but we also have to add a NULL char as terminating char We don’t need envp so EDX could be set to 0. We can use the stack to work with all this information and then save the structure in the relative registers, taking in consideration that we have to work in reverse mode because of the little endian. We will use the stack method to execute the execve syscall.
We will load the shellcode in our C code executor, compile it and debug it.


unsigned char code[] = \

void main()

        printf("Shellcode Length:  %d\n", strlen(code));

        int (*ret)() = (int(*)())code;



We will stepi forward to the last int 0x80 call and explain the code using peda

EAX: 0xb ('\x0b')
EBX: 0xbffff54e ("/bin/sh")
ECX: 0xbffff53e --> 0xbffff54e ("/bin/sh")
EDX: 0x0 
ESI: 0xb7fbb000 --> 0x1b1db0 
EDI: 0xbffff556 --> 0x632d ('-c')
EBP: 0xbffff578 --> 0x0 
ESP: 0xbffff53e --> 0xbffff54e ("/bin/sh")
EIP: 0x804a064 --> 0x80cd
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
   0x804a05c <code+28>:	add    BYTE PTR [ecx+0x64],ch
   0x804a05f <code+31>:	add    BYTE PTR [edi+0x53],dl
   0x804a062 <code+34>:	mov    ecx,esp
=> 0x804a064 <code+36>:	int    0x80
   0x804a066 <code+38>:	add    BYTE PTR [eax],al
   0x804a068:	add    BYTE PTR [eax],al
   0x804a06a:	add    BYTE PTR [eax],al
   0x804a06c:	add    BYTE PTR [eax],al
0000| 0xbffff53e --> 0xbffff54e ("/bin/sh")
0004| 0xbffff542 --> 0xbffff556 --> 0x632d ('-c')
0008| 0xbffff546 --> 0x804a05d --> 0x57006469 ('id')
0012| 0xbffff54a --> 0x0 
0016| 0xbffff54e ("/bin/sh")
0020| 0xbffff552 --> 0x68732f ('/sh')
0024| 0xbffff556 --> 0x632d ('-c')
0028| 0xbffff55a --> 0x84790000 
Legend: code, data, rodata, value
0x0804a064 in code ()

As we can see all is ready for the execve syscall as described above.

 int execve(const char *filename, char *const argv[], char *const envp[]);
     EAX            EBX                   ECX                EDX

EAX: 0xb ('\x0b')                           ; execve syscall
EBX: 0xbffff54e ("/bin/sh")                 ; the path of the binary file to execute
ECX: 0xbffff53e --> 0xbffff54e ("/bin/sh")  ; the pointer to the address where our executable and instructions are stored, the stack
EDX: 0x0                                    ; we don't need envp, it could be NULL

And the stack containing the argv structure.

0000| 0xbffff53e --> 0xbffff54e ("/bin/sh")
0004| 0xbffff542 --> 0xbffff556 --> 0x632d ('-c')
0008| 0xbffff546 --> 0x804a05d --> 0x57006469 ('id')
0012| 0xbffff54a --> 0x0 

Resuming, this time the command executed is /bin/sh -c id .

All the codes used in this post are available in my dedicated github repo.

This blog post has been created for completing the requirements
of the SecurityTube Linux Assembly Expert certification: SLAE32 Course
Student ID: SLAE-1476