This post is the fifth of 7 exam assignments of the Pentester Academy's x86 Assembly Language and Shellcoding on Linux course. Success in these 7 assignments results in the Pentester Academy's SLAE32 certification.The files used in this assignment are here:
SLAE - 901
SLAE - 901
Assignment 5 Requirements
For this assigment I'll analyze and present 2 msfvenom linux/x86 payloads and one payload from shell-code.org.
Payload 1 - msfvenom linux/x86/shell/reverse_tcp
I checked to see what payloads were available.
I chose the linux/x86/shell/reverse_tcp shell.
I checked the options for the payload.
I extracted the shellcode using msfvenom in C format.
After visually confirming that the shellcode byte string contained no null bytes (x00), I put the byte string in the shellcode.c template.
I compiled it using gcc with the extra options.
After putting the shellcode in gdb, I located the start of the shellcode portion of the script (0x804a040), set a breakpoint for it, then ran the script which stopped at that breakpoint.
I noted that the shellcode is 31 bytes in length.
I disassembled the code and inspected the instructions.
First, I verified that the shellcode loaded into memory as intended by using gdb's examine command (x) so that it would display the 31 bytes starting at the alleged start of the shellcode.
I compared the string with the shellcode bytes I placed in the shellcode.c template earlier and was satisified that they were the same and that the shellcode was loaded into memory as intended.
I ran the shellcode byte string through ndisam and inspected the output. I found that the size of the shellcode byte string overmatched ndisasm's usefulness.
I ran the shellcode string through libemu.
Using libemu, I confirmed that the shellcode was as, in fact, what msfvenom alleged.
I made a graphical depiction of libemu's sctest output.
This confirmed that the shellcode was a valid and safe TCP reverse shell.
Once confirming the shellcode was low-risk, I executed it.
It worked. Yay.
Payload 2 - msfvenom linux/x86/exec
I planned to execute the "cat /etc/passwd" command with this shell.
$ msfvenom -l payloads | grep "linux/x86"
$ msfvenom --payload-options -p linux/x86/exec
$ msfvenom -a x86 --platform linux -f c -p linux/x86/exec CMD="cat /etc/passwd" -b \x00
(note: originally there were two null bytes in the shellcode byte string; I used msfvenom's -b switch (bad characters) to eliminate them)
From the output of the above command, I copied the resulting shellcode byte string into the shellcode.c template. I then compiled using gcc as I did with the previous payload.
I ran the payload through ndisasm and inspected the instructions. Again, I found ndisasm to be of limited usefulness in analyzing shellcode of this size.
I examined the shellcode in gdb and noticed a syscall of some kind (int x80). I set a break point for the start of the syscall [(gdb) break *0x0804a08c], invoked gdb's run command and disassembled the instructions at that break point. I ran gdb's info registers command so that I could examine the condition of the general registers.
I noticed the prior to the script executing the syscall that the eax register was set to the value of 11.
I reviewed /usr/include/i386-linux-gnu/asm/unistd_32.h for the system call numbers and confirmed that the system call was execve, which the normal way that x86 architectures execute commands.
I used gdb's stepi (step instruction) command. This executed the system call which ran the CMD argument "cat /etc/passwd" as advertised.
I ran the payload through libemu's sctest and examined the output.
The libemu tool confirmed that it was an execve function.
I ran the dot command to turn libemu's sctest output into an image graph:
# dot jk.dot -Tpng -o /root/Desktop/jk.png
The graph output further confirmed the payload was as is alleged by msfvenom.
After fully analyzing the shellcode, I executed it.
It worked. Yay.
Payload 3 - Surprise shell code from shell-storm.org
(P.S. it's actually a bind shell but we are going to pretend we don't know that, okay?...Work with me...)
I took a shellcode extract from a payload in shell-storm, pasted it into the shellcode.c template and compiled it. Then I brought it into gdb. Then I used the examine command to find the memory location of the start of the shellcode. I set that as a breakpoint, ran it, and gdb stopped execution at that breakpoint.
I noted the length of the shellcode (73 bytes).
I disassembled the instructions at that break point.
I noticed several syscalls (int 0x80) in these instructions and set out to analyze them to see what this payload does.
I noted the memory location of the first syscall.
I set a breakpoint at that memory location and continued on to that breakpoint.
At that breakpoint I examined the state of the general registers.
I noticed the eax had a value of 102.
Again, I pulled up /usr/include/i386-linux-gnu/asm/unistd_32.h.
The ebx has a value of 1.
So, it's a socket creation function.
It stepped past the syscall and examined the registers
I noticed that the eax has a value of 7, which is the return value from a successful socket creation.
I noted the memory location of the next syscall, set a breakpoint for it, continued, then disassembled the instructions at that breakpoint (prior to the next syscall).
I ran gdb's info registers command to examine the state of the registers prior to the second system call.
Noting that the ebx has a value of 2...
This is a bind command.
Since the bind's port will be in the stack arguments, I examined the instructions to see if I could see where the port number is pushed on the stack.
0x672b is little endian format for the hex value of \x2b\x67 which is 11111 in decimal. This is the port for the intended bind shell.
Looking at the next syscall, I examined the registers state prior to the call.
The ebx register has a value of 4...
4 equates to a Listen call.
So this code is looking and smelling like a bind shell exploit so far.
Well, I think I may be boring the readers at this point, so let's execute the shellcode.
And it is a bind shell. Yay.