Msfvenom generated Exec shellcode analysis - exec shellcode
in Blog
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification. The task for 5.1/7 assignment is to analyse at least 3 shellcode examples created using Msfpayload for linux/x86_64. Since msfpayload is outdated, I used msfvenom instead. The analysis of the shellcodes is carried out using the gdb debugger and 1/3 shellcode analysed in this article is the linux/x64/exec payload.
Student ID: SLAE64 - 1594
MSFvenom generated linux/x64/exec payload
The first payload I chose is the linux/x64/exec payload, which is used to execute an arbitrary command which I have specified in the CMD commandline argument. In order to generate the payload I used the following command:
root@kali:~# msfvenom -p linux/x64/exec -f c CMD=whoami
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 46 bytes
Final size of c file: 220 bytes
unsigned char buf[] =
"\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53"
"\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6\x52\xe8\x07\x00"
"\x00\x00\x77\x68\x6f\x61\x6d\x69\x00\x56\x57\x48\x89\xe6\x0f"
"\x05";
Shellcode test program
In order to analyse the generated payload I am placing it into the C program where we will be executing the shellcode:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53"
"\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6\x52\xe8\x07\x00"
"\x00\x00\x77\x68\x6f\x61\x6d\x69\x00\x56\x57\x48\x89\xe6\x0f"
"\x05";
int main()
{
printf("Shellcode Length: %d\n", (int)strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
and then compile it as follows:
gcc -m64 -fno-stack-protector -z execstack testshellcode.c -o testshellcode -no-pie
Analysis
I started the debugger gdb ./testshellcode
and looked at the state of all the important registers just before taking the syscall - rax, rdi, rsi and rdx. From that we can construct that the syscall to be executed:
- is execve as
rax
is 0x3b (59 in decimal) - the program which will be executed is
/bin/sh
as we can find it from registerrdi
rsi
points to an array at 0x7fffffffdc28 with 3 array elements [“/bin/sh”, “-c”, “whoami”] as array elements are layed out into memory from lower addresses to higher addresses- we pass no environment variables to the syscall.
So the final syscall, which this shellcode will execute is in following format:
execve("/bin/sh", ["/bin/sh", "-c", "whoami", 0])
Related posts:
- 64-bit bindshell with a passphrase protection
- 64-bit reverse shell with passphrase protection
- Egghunter (64-bit Linux) using access() syscall
- Writing a 64-bit custom encoder (reversed byte order of 4 byte chunks)
- Msfvenom generated Exec shellcode analysis - exec shellcode
- Msfvenom generated bind_tcp shellcode analysis
- Msfvenom generated shell_reverse_tcp payload
- Polymorphic shellcodes for samples taken from Shell-Storm
- Custom encrypter - One-time pad (OTP)