Msfvenom Exec Payload Analysis
Introduction
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
Exec
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[] =
"\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";
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, theargv[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.
#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\x03\x00\x00\x00\x69"
"\x64\x00\x57\x53\x89\xe1\xcd\x80";
void main()
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
We will stepi
forward to the last int 0x80
call and explain the code using peda
[----------------------------------registers-----------------------------------]
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)
[-------------------------------------code-------------------------------------]
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
[------------------------------------stack-------------------------------------]
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