SLAE #7: Shellcode Crypter for Linux/x86

Introduction

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

Student ID: SLAE-877

To get the code provided in this exercise:

% git clone https://github.com/droberson/SLAE.git

The code will be within the Assignment-7 directory.

RC4

I decided to use the RC4 algorithm due to the fact that it is easy to implement and there were examples of RC4 ciphered text within this course. This made it easy to verify that my implementation of this algorithm was working properly.

The purpose of a crypter in the context of this course is to encrypt an executable payload with a key, making the shellcode very hard to identify. The decrypter will decrypt the payload and execute it, provided the supplied passphrase is correct.

This approach has the added benefit of being able to compile on basically anything with a C compiler and does not rely on any external libraries.

Crypter

Below is the source code for the crypter. This takes a passphrase and a file containing shellcode as input:

% ./crypter passphrase shellcode

/* crypter.c -- RC4 encrypt a file using specified key, output as escaped hex
 *           -- by Daniel Roberson @dmfroberson daniel@planethacker.net
 * SLAE-877
 *
 * For more information about RC4: https://en.wikipedia.org/wiki/RC4
 */


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main (int argc, char *argv[]) {
  int i;
  int fd;
  int rc4i;
  int rc4j;
  unsigned char rc4s[256];
  unsigned char *key;
  unsigned int tmp;
  unsigned char *data;
  struct stat s;

    
  if (argc != 3) {
    fprintf (stderr, "usage: %s  \n", argv[0]);
    exit (EXIT_FAILURE);
  }

  if (strlen (argv[1]) > sizeof (rc4s)) {
    fprintf (stderr, "error: key must be under %ld bytes\n", sizeof (rc4s));
    exit (EXIT_FAILURE);
  }

  key = argv[1];

  /* read input file */
  if (stat (argv[2], &s) == -1) {
    perror ("stat");
    exit (EXIT_FAILURE);
  }

  fd = open (argv[2], O_RDONLY);
  if (fd == -1) {
    perror ("open");
    exit (EXIT_FAILURE);
  }

  data = malloc (s.st_size);
  if (read (fd, data, s.st_size) != s.st_size) {
    fprintf (stderr, "unable to read %ld bytes from %s\n", s.st_size, argv[2]);
    exit (EXIT_FAILURE);
  }

  close (fd);

  /* Key-scheduling algorithm */
  for (i = 0; i < sizeof (rc4s); i++) {
    rc4s[i] = i;
  }

  for (rc4i = 0, rc4j = 0; rc4i < sizeof (rc4s); rc4i++) {
    rc4j = (rc4j + rc4s[rc4i] + key[rc4i % strlen (key)]) % sizeof (rc4s);

    /* swap s[i] and s[j] */
    tmp = rc4s[rc4j];
    rc4s[rc4j] = rc4s[rc4i];
    rc4s[rc4i] = tmp;
  }

  /* encrypt the string with supplied key and output as escaped hex */
  for (rc4i = 0, rc4j = 0, i = 0; i < strlen(data); i++) {
    rc4i = (rc4i + 1) % sizeof (rc4s);
    rc4j = (rc4j + rc4s[rc4i]) % sizeof (rc4s);

    /* swap s[i] and s[j] */
    tmp = rc4s[rc4j];
    rc4s[rc4j] = rc4s[rc4i];
    rc4s[rc4i] = tmp;

    tmp = rc4s[(rc4s[rc4i] + rc4s[rc4j]) % sizeof (rc4s)];
    printf ("\\x%.02x", data[i] ^ tmp);
  }

  printf("\n\n");

  free (data);

  return EXIT_SUCCESS;
}

For this example, I re-used the write(stdout, “hi there\n”, 9) shellcode developed in a previous lesson for demonstration purposes:

 % ../Assignment-6/test write
Testing shellcode contained in write

char shellcode[] = "\x42\x4a\x42\x4a\x31\xc0\x31\xdb\x31\xc9"
                   "\x31\xd2\x83\xc0\x04\x43\x6a\x0a\x68\x68"
                   "\x65\x72\x65\x68\x68\x69\x20\x74\x89\xe1"
                   "\x83\xc2\x09\xcd\x80\x31\xc0\x40\x4b\xcd"
                   "\x80";

Length: 41

Executing shellcode..
hi there

Now, I encrypt the file containing the shellcode with passphrase “harharhar”:

 % ./crypter harharhar write
\x2a\xfd\x35\x3c\x72\x44\x72\x37\x15\x0d\x6e\xbf\x02\x46\x01\xf4\x25\xc6\xf6\x63
\xab\xf1\x89\x5d\x2c\x8a\xa8\x3c\x69\xfc\x29\x25\x3d\x85\xa6\x21\x95\x39\x67\xfa
\x49

Decrypter

Next, I wrote a wrapper that takes the crypted string made with ./crypter and attempts to decrypt and execute the payload:

/* decrypter.c -- RC4 decrypt a string using specified key, execute it.
 *           -- by Daniel Roberson @dmfroberson daniel@planethacker.net
 * SLAE-877
 *
 * For more information about RC4: https://en.wikipedia.org/wiki/RC4
 */


#include 
#include 
#include 
#include 
#include 
#include 


/*
 * crypted payload for write(1,"hi there\n",9)
 * passphrase = harharhar
 *
 * generated with ./crypter harharhar write
 */
unsigned char data[] = \
  "\x2a\xfd\x35\x3c\x72\x44\x72\x37\x15\x0d\x6e\xbf\x02\x46\x01\xf4\x25\xc6"
  "\xf6\x63\xab\xf1\x89\x5d\x2c\x8a\xa8\x3c\x69\xfc\x29\x25\x3d\x85\xa6\x21"
  "\x95\x39\x67\xfa\x49";


int main (int argc, char *argv[]) {
  int i;
  int fd;
  int rc4i;
  int rc4j;
  unsigned char rc4s[256];
  unsigned char *key;
  unsigned int tmp;

    
  if (argc != 2) {
    fprintf (stderr, "usage: %s \n", argv[0]);
    exit (EXIT_FAILURE);
  }

  if (strlen (argv[1]) > sizeof (rc4s)) {
    fprintf (stderr, "error: key must be under %d bytes\n", sizeof (rc4s));
    exit (EXIT_FAILURE);
  }

  key = argv[1];

  /* Key-scheduling algorithm */
  for (i = 0; i < sizeof (rc4s); i++) {
    rc4s[i] = i;
  }

  for (rc4i = 0, rc4j = 0; rc4i < sizeof (rc4s); rc4i++) {
    rc4j = (rc4j + rc4s[rc4i] + key[rc4i % strlen (key)]) % sizeof (rc4s);

    /* swap s[i] and s[j] */
    tmp = rc4s[rc4j];
    rc4s[rc4j] = rc4s[rc4i];
    rc4s[rc4i] = tmp;
  }

  /* encrypt the string with supplied key and output as escaped hex */
  for (rc4i = 0, rc4j = 0, i = 0; i < strlen(data); i++) {
    rc4i = (rc4i + 1) % sizeof (rc4s);
    rc4j = (rc4j + rc4s[rc4i]) % sizeof (rc4s);

    /* swap s[i] and s[j] */
    tmp = rc4s[rc4j];
    rc4s[rc4j] = rc4s[rc4i];
    rc4s[rc4i] = tmp;

    tmp = rc4s[(rc4s[rc4i] + rc4s[rc4j]) % sizeof (rc4s)];
    data[i] = data[i] ^ tmp;
  }

  /* attempt to execute decrypted payload */
  int (*run) () = (int(*)())data;
  run();

  return EXIT_SUCCESS;
}

Using this program and the key “harharhar”, it successfully decrypts and executes the write() shellcode:

 % ./decrypter harharhar                    
hi there

If this does not have the correct passphrase, it will not execute:

 % ./decrypter thispasswordisnotright
zsh: segmentation fault (core dumped)  ./decrypter thispasswordisnotright

One thought on “SLAE #7: Shellcode Crypter for Linux/x86

  1. Pingback: SLAE #6: Polymorphic Shellcode for Linux/x86 – DMFROBERSON

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s