Bugtraq mailing list archives

Re: pt_chmod


From: peter () haywire DIALix COM (Peter Wemm)
Date: Sun, 4 Dec 1994 04:10:34 +0800 (WST)


Bela Lubkin writes:

Carson Gaspar wrote:

Does anyone know what the pt_chmod hole is?  The same suid program exists in
Solaris 2.x, and knowing Sun's track record...

By my testing, exactly the same bug exists on Solaris 2.3/SPARC;
however, it does not cause a security hole there.  The security hole is
caused by how the SCO execution environment treats NULL dereferences.
The same bug probably exists in the pt_chmod source on most System V
systems; whether it causes a security problem depends on how the OS
treats NULL dereferences.

Full disclosure has been sent to CERT for dissemination to other OS
vendors.  I am not in a position to publically disclose full details at
this time; I also think that to do so would be rude to other OS vendors
who have not had a chance to issue their own fixes.

Your pt_chmod is safe if it coredumps when run as `pt_chmod <
/etc/termcap`.  If not, it might or might not be safe.  Ask your OS
vendor, "trace" or "truss".

I'm sorry that I can't say more.  

Bela<


I had a look at the truss/trace output of pt_chmod on several systems,
including a SCO one.

Going purely by the truss output (what little there is), it appears
that pt_chmod does something approximately like this: 
main(int argc, char **argv)
{
        chown(ptsname(atoi(argv[1])), getuid(), getgid());
}
Note the lack of check for NULL on the return value from ptsname().
Which effectively makes it do a "chown(NULL, your_uid, your_gid)"

What happens next depends on what is at memory location zero:

Apparently:
SCO unix:  (char *)NULL =
0000    4c 01 04 00 ce b6 e0 2e  b4 35 00 00 fb 01 00 00   L........5......

SVR4:      (char *)NULL = "";
0000    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................

I think Solaris has an unmapped page zero, which will cause a core
dump.  If not, then it's probably the SVR4 case.

Fortunately for SVR4 (and probably solaris) systems, the filesystem
always returns an "ENOENT" if the user trys to create a file with zero
length, so the "chown("", uid, gid)" should never succeed.  However, on
SCO systems and maybe other SVR3 systems, the chown() can be made to
succeed. 

There.  I think there's enough information there to convince people
that there's a problem, but there's not enough (I *hope*) for the
lamers to wreak havoc with.  The "elite" crackers will already have
figured this out long ago, as soon as the fix was announced, and would
have run trace/truss themselves and figured it out.  If you need an
exploit script, wait for 8lgm on monday.

***IF YOU HAVE A SCO SYSTEM, INSTALL THE FIX!!!!***

Hmm. something else I though of too.  Imagine:  root is logged in on
/dev/pts/34, and has the tty set to mode 0622.  Guess what this would
do if you were a normal user: /usr/lib/pt_chmod 1 > /dev/pts/34
You could then TIOCSTI to your hearts content.

A plea to OS programmers: 
*dont* use "chown" on the result of the ptsname() - use fchown() - the
user might have passed a fd in that's from a network mounted partition in
an attempt to change the ownership of the local alias of the device.
Also, RFS makes things interesting too, as the ioctl() in ptsname() is
evaluated on the remote machine and returned back.

Imagine this: 

$ ls -l /remotesys/dev/pts/34
crw--w----   1 joe      tty       12, 34 Dec  3 20:34 /remotesys/dev/pts/34
$ ls -l /dev/pts/34
crw--w----   1 root     tty       12, 34 Dec  3 20:34 /dev/pts/34
$ /usr/lib/pt_chmod 0 < /remotesys/dev/pts/34
$ ls -l /dev/pts/34
crw--w----   1 joe      tty       12, 34 Dec  3 20:34 /dev/pts/34

OK. so this is unlikely to be configured this way in a well configured
network, and RFS is practically dead.. but you never know what else
might turn up in the future as NFS Version 95, or whatever.

If you a SYSV derived system, you might like to replace
/usr/lib/pt_chmod with something like the code below.  No promises
that it even works, but at least it should prevent some of the abuse
above.  Read through it and once you are happy that it wont screw up
any more than the standard pt_chmod, make it mode 4111.

---------------
/*
Copyright (C) 1994, Peter Wemm. All rights reserved.

Standard disclaimer:
If this doesn't work: tough. If you lose millions because this messes
up, it's you that's out the millions, not me. If you don't like this
disclaimer: tough. I reserve the right to do the absolute minimum
provided by law, up to and including nothing. This is basically the
same disclaimer that comes with all software packages, but this is in
plain English and theirs is in legalese. I didn't want to include any
disclaimer at all, but the lawyers insist.
[inspired by Haventrees Software's EasyFlow disclaimer, as posted on usenet]
*/

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

int
main(int ac, char **av)
{
        int fd;
        int gid = getgid();
        int uid = getuid();
        int mode = 0600;
        int accmode;
        struct group *gr;

        if (ac != 2)
                exit(255);      /* not enough args */
        
        /* look for a secure tty group, and alter the permissions if found */
        if ((gr = getgrnam("tty")) != NULL) {
                gid = gr->gr_gid;       /* found protected group 'tty' */
                mode = 0620;
        } else if ((gr = getgrnam("terminal")) != NULL) {
                gid = gr->gr_gid;       /* found protected group 'terminal' */
                mode = 0620;
        }

        fd = atoi(av[1]);
        if (ptsname(fd) == NULL)
                exit(255);      /* not a pty */

        if ((accmode = fcntl(fd, F_GETFL, 0)) < 0)
                exit(255);      /* paranoid */

        if (((accmode & O_ACCMODE) != O_RDONLY) &&
            ((accmode & O_ACCMODE) != O_RDWR))
                exit(255);      /* not opened in readable mode */

        if (fchmod(fd, mode) < 0)
                exit(255);      /* couldn't chmod */
        if (fchown(fd, uid, gid) < 0)
                exit(255);      /* couldn't chown */
        exit(0);
}

-------------
Feel free to distribute this wherever and however you like.  If you
think you can sell it (or a derivative of it) in your OS, go for it
and good luck.  I only ask for a breif credit in the user-visible
man-page for the function that calls pt_chmod, ie: normally where
grantpt() is documented.

-Peter



Current thread: