Wednesday, October 18, 2017

SLAE64 Exam - Assignment 5 of 7 (Analysis of Shellcode)

This post is the fifth of 7 exam assignments of the Pentester Academy's x86/64 Assembly and Shellcoding on Linux.

SLAE64 - 1501

Success in these 7 assignments results in the Pentester Academy's SLAE64 certification.

http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html


  •  Take up at least 3 shellcode samples created using Msfpayload for linux/x86_64
  •  Use GDB to dissect the funcSonality of the shellcode
  •  Document your analysis 
All 3 shellcode.c's used in this assignment are here:

I chose 3 msfvenom shell to analyze and disect with GDB:

  • linux/x64/shell_bind_tcp
  • linux/x64/shell_reverse_tcp
  • linux/x64/exec

linux/x64/shell_bind_tcp

I reviewed this shell code's basic options:


The only required option for this shellcode is the LPORT which defaults to 4444

I generated shellcode in c format:

I noticed a few null bytes ("\x00") in the shellcode, so I re-ran the command with the -b (bad character removal) option:


I noted that the shellcode size was 127 bytes.

I pasted the shellcode into the shellcode.c template:


I compiled it with the following command:


 gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

I loaded the shellcode binary into GDB with the following command:

$ gdb -q ./shellcode -tui

I set up the GDB interface as follows:


Note: I defined the intel syntax via the .gdbinit file.

I "stepi'd" until the decoding loop finished:


I noticed that the code at <code+39> had decoded into something resembling a syssocket syscall (0x29).  I advanced the execution to the first syscall and examined the registers:

Note also used the "x/6xg $rsp" command to show the first six positions on the stack.


I noticed that prior to the execution of the syscall command, that rax had the syssocket value of 41, the rdi had 2, the rsi had 1 and rdx had 0.  I executed the first system call and noted the return value of 3 in rax.  



I stepi'd to the next system call and examined the registers and stack:


This time the rax had 49 (bind), the rdi had 3, the rsi had the value of the default port 4444 (0x5c11) and the rdx had a value of 16.  I executed the system call and noted the return value of 0.

I stepi'd to the next system call.


The rax had 50 (listen).  The rdi had 3 (int fd) and the rsi had memory location of port 4444.

I steps'd to the next system call.



The rax had 33 (dup).  The rdi had 4 (oldfd) and the rsi has 2 (newfd).  The syscall was followed by a jne command which repeated the syscall until the rsi decremented to 0.  Then the syscall executed with a return value of 0 in rax.

I stepi'd to the last system call.



The rax had 59 (execve).  The rdi had the memory location that holds the /bin//sh string (in hex) and the rsi had a pointer which pointed to the memloc of the /bin//sh string.

I executed the syscall, and in another terminal connected to the bind via netcat.



It worked.  Yay.

inux/x64/shell_reverse_tcp


I reviewed this shell code's basic options:


I noticed that it had two basic options; the LHOST and the LPORT(which defaults to port 4444).

I generated the shellcode in c format:

I noticed a null byte ("\x00"), so I reran it adding msfvenom's -b (bad character removal) switch:



Next, I  pasted the shellcode in the shellcode.c template:


I compiled it with the following gcc command:


$   gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

I put the resulting binary (shellcode) in gdb and examined the state of the registers and stack at the start of the code section of the binary.

$ gdb -q ./shellcode -tui


I noticed that the decoding stub ended at <code+37> (after the loop finishes) and that the rest was gibberish that would decode when the loop finished.  I advanced to when the loop finishes and examined the decoded shellcode (starting at <code+39>).



After the decoding loop finished, I examined the first 8 assembly instructions and notice that now the opcode resembled a syssocket system call set up (0x29; 41).  I advanced the the first system call and examined the state of the registers and stack.



Prior to the first system call the rax contained 41 (syssocket).  The rdi contained 0; rsi was 1, rdx was 0.
I executed the syscall and noted a return value of 3 in the rax.

I advanced to the next syscall and examined the state of the registers and stack.



This time the rax held 42 (connect).  The rdi had 3; rsi held the memory location of the IP (0x0100007f; which is 127.0.0.1) and the port (0x5c11; which is 4444).  The rdx held 16 (length of string in rsi).  I executed the syscall.


Next was the dup section (33).  I stepi'd through the jne loop and watched as the rsi decremented to 0.   I executed the syscall and noted the return value of 0 in the rax.

I advanced to the next syscall.



The rax held 59 (execve). The rdi had the stack pointer to the /bin//sh string.  The rsi had the stack pointer that pointed to the memloc of the /bin//sh string.  The rdx held 0.

I executed the syscall.



It worked. Yay.

linux/x64/exec

I reviewed this shell code's basic options:


I noted that the only argument was the CMD.  I planned to the use the string "cat /etc//passwd" (added an extra "/" to the string to make it an even 16 bytes).

I generated and examined the shellcode in c format.


I noticed some null bytes, so I reran the command with the -b switch.


I pasted the shellcode into the shellcode.c template as before and compiled it with a modified gcc command as before.

Then, I put the shellcode binary in gdb.

gdb -q ./shellcode -tui



I set up gdb by setting a breakpoint for the beginning of the shellcode ("code") section of the c-based binary.  I also set up the tui interface to display the assembly and registers.

I saw that the decoder stub ended at the loop command (<code+37>).  Noticed that after the loop were commands that were unrecognized by gdb or unusual in shellcode.  I stepi'd through the loop function and noticed that the code from <code+39> changed to recognizable syscall preparation commands.



Seeing indications that the code after the stub had decoded properly, I advanced to the first syscall and inspected the state of the registers and stack.



The rax held 59 (execve).  The rdi held memloc of the "/bin/sh" string.  The rsi held memloc pointer to the "/bin/sh" string.  I executed the syscall.



The "cat /etc/passwd" command successfully executed.

It worked. Yay.


No comments:

Post a Comment