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
Pingback: SLAE #6: Polymorphic Shellcode for Linux/x86 – DMFROBERSON