Assignment 5 – Msfvenom Shellcode Analysis
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-1112
This is the fifth from seven assignments in order to complete the SLAE (32bit) certification.
In this Assignment the objective is analyze three Shellcodes generated via MSFvenom using tools such as gdb, ndisasm and libemu.
The three Shellcodes to be analized are:
As the name suggests, this Shellcode uses an execve syscall in order to execute commands. I started by generating the Shellcode via msfvenom and piped it through ndisasm in order to view the disassembled instructions:
Now the fun part, analyzing the instructions. In order to explain the instructions I thought of posting an image with comments for each line:
This Shellcode uses the Jmp-Call-Pop technique and is pretty straightforward from line 1 to 10. On line 11 there is a jump to 0x24, which is on line 16 after the opcodes 69 00. As usual, after a call is made, the address of the next instruction is pushed onto the stack. In this case, before the call is made, eip was pointing to line 12, where the “whoami” command is stored (77 68 6F 61 6D 69 00).
Line 16 requires special attention and was broken down to two parts:
- 69 00 – represent the last character from whoami and the null byte (“i\00”).
- 57 53 89 E1 – represent the last instructions needed before invoking the syscall.
In order to understand it better here’s a printscreen from gdb, hitting a breakpoint right after the call. As we can see, “whoami” is on the stack and the subsequent instructions have changed:
In the following printscreen it is possible to take a look at the registers and see that we have everything that we need in order to execute the command “whoami”:
Same process as the last one, the Shellcode was generated with msfvenom and piped through ndisasm:
Here’s a detailed analysis of the code:
Just like the last one, this Shellcode leverages the Jmp-Call-Pop technique. As you can see, it starts by performing a jmp short 0x38, and right after that a call dword 0x2, transfering execution to the second line (mov eax, 0x5). This sequence of instructions push the address 0000003D onto the stack (the start of /etc/passwd):
As we can see in the previous image, “/etc/passwd” is in the top of the stack. After that, eax is set as 0x5 (sys_open), the address of “/etc/passwd” is popped to ebx and ecx is set to 0 (O_RDONLY – Read only) with the xor.
After performing the syscall, a file descriptor is returned to eax and moved to ebx, eax is then set to 0x3 (sys_read) in order to read the file and the pointer to “/etc/passwd” is moved to ecx .
After performing the sys_read syscall, eax will hold the number of read bytes and this value must then be stored in edx. At this point, we can set eax to 0x4 (sys_write), set ebx to 0x1 (write to stdout) and ecx remains untouched (pointing to “/etc/passwd”). This syscall will write the number of bytes currently in edx starting at a *buf (ecx).
Finally, the program exists gracefully with the exit syscall (0x1).
The last Shellcode that I chose is a Meterpreter Reverse TCP. Meterpreter is an advanced, dynamically extensible payload that uses in-memory DLL injection stagers and is extended over the network at runtime. Also, Meterpreter resides entirely in memory and doesn’t write anything to disk.
The starting point of this analysis is, once again, generating the Shellcode via msfvenom and pipe through ndisasm in order to view the disassembled instructions:
This Shellcode is slightly bigger than the others, being 123 bytes long. Now, analyzing the instructions:
The Shellcode starts by creating a Socket and connecting back to the attacker’s machine. This process (line 3 to 25) is pretty simple and was covered before in Assignment 2.
Right after that, we have some sort of failure handler. On line 27 and 28 we have test eax, eax followed by jns 0x48. The reason behind these instructions is to check if the value of eax (returned value from the previous syscall) is positive or not.
If an error occurs, sys_socketcall returns -1, and thus test eax, eax will set the Sign Flag (SF) to 1. If SF is set to 1, jns 0x48 won’t perform the jump and will lead us to the next instruction. Otherwise SF remains 0 and jns 0x48 will transfer execution to line 42.
If the jump jns 0x48 is not taken, we will reach line 29, where esi is decremented (esi is used as a counter of retry attempts). If esi reaches 0, the Zero Flag (ZF) is set to 1 and the jump on line 30 will take us to line 62. If not, from line 31 to 37 we have the set up of the sys_nanosleep syscall, which will make our code sleep for 5 seconds before attempting to create the socket again.
From line 42 to 48 we have the setup of the memory protection bit for 0x1000 bytes of memory to READ, WRITE and EXEC.
From line 52 to 57 the Shellcode reads 0xC00 bytes from the attacker’s machine (which at this point has started sending some stage code to this stager) and executes the received code in memory.
Last, but not least, from line 62 to 64 we have the sys_exit syscall that is used for the program to exit gracefully.
As a wrap-up for this Assignment, since everyone likes Shells, the result of the execution of the third Shellcode:
As usual, the code can be found in my SLAE Github repository.
That is all for this Assignment, see you on the next one.