[3253] in bugtraq
Re: libresolv+ bug
daemon@ATHENA.MIT.EDU (Zygo Blaxell)
Thu Aug 22 15:34:58 1996
Date: Thu, 22 Aug 1996 10:52:45 -0400
Reply-To: Bugtraq List <BUGTRAQ@NETSPACE.ORG>
From: Zygo Blaxell <zblaxell@MYRUS.COM>
X-To: tqbf@enteract.com
To: Multiple recipients of list BUGTRAQ <BUGTRAQ@NETSPACE.ORG>
In-Reply-To: <199608220521.AAA27040@enteract.com> from "Thomas Ptacek" at Aug
22, 96 00:21:50 am
Quoted from Thomas Ptacek:
> > 1. A general-purpose setuid program that acts as a switching point for
> [ elided ]
> > 2. An interface script written in a language that handles its own memory
> > allocation, like perl, or even GNU flavors of sed and awk; tcl would
>
> Something to consider: I'm guessing that the reason everyone didn't
> instantaneously know about the 'suidperl' program, the minute that
Gee, I just guessed that there was probably that sort of problem, and
removed the setuid bits on sight.
> the program was brought into the afflicted operating systems, is that
> none of the people that normally run through source code finding bugs
> wanted to read 'perl'.
I do agree that it should be simpler than perl. I did say *like* perl.
I forgot to say "but not perl" or "like mini-perl".
It's really hard to do buffer-overrun attacks (or imbedded-0 attacks,
malformed-input attacks, etc) when you have perl-style data types and
regular expressions. Perl will allow you to imbed nulls in a string,
then do regexp matches against it. It's easier to validate a perl script
than a C program, because there's much less code to evaluate and more
details are handled by the language.
So, *assuming* that you can make the implementation of the scripting
language secure, you can use it as an algorithmic policy enforcement
agent. You'd have to start from the ground up designing the thing to
be secure (i.e. it would have to have decent exception handling, robust
string types, array bounds checking, and all that good stuff to make
even trivial programs secure without much thought). It would have to
be hand-tuned for every OS it was ported to, and it would have to be
able to interact properly with the kernel within the scripting language--
if it didn't, then you would have to validate any external programs called
from the scripting language in their entirety.
If the language is byte-compiled, it can be implemented directly in the
kernel, to boot. At exec() time, the kernel would spawn a user-mode
interpreter, interpret the privilege rules for the program in question,
then drop the privilege-modification-privilege (unless the p-m-p is one
of the privileges that the exec()ed program must have) and continue the
exec() in normal Unix style.
This is about as general as you can get; unlike authorization vectors
or magic privileged groups, this one lets you make arbitrary decisions
about who gets access to what, without actually modifying the software
that provides the basic functionality.
> > - binding to privileged ports (call bind(), drop privileges, exec
> > child; inndstart does this with innd)
>
> Bad!
>
> We're talking about problems (in this specific instance) in free, open
> operating systems, in which anyone can go tinker around in the kernel and
> fix whatever it is that concerns them.
>
> Why would you continue forcing programs to run as root, just so they can
> do something as trivial as binding to a privileged port (the concept of
> privileged ports strikes me as one of the worst concepts ever introduced
> into Unix networking code), instead of hacking your kernel so that some
> other UID or GID can do it instead (say, anything running as UID "netpriv"
> or GID "network"), thus eliminating any real concerns of far-reaching
> security programs in a whole ugly host of user-level networking programs?
Well, the point of this structure is that there is exactly one setuid-root
program running as root on the entire machine, which gives away individual
privileges selectively to other programs. The difference is that in this
model you secure that one program and then you're done; effectively this
is the same as implementing security policy in the kernel, except that
it can be ported to some of the existing Unix systems as well.
If I just wanted to modify the kernel, then I would just put inheritable
authorization vectors in process table entries, with one bit per
privileged function, and then put an authorization vector in the program
text somewhere for setuid^H^H^H^H^H^Howner-privileged programs. If the
owner's privelege vector is ANDed with the program's privilege vector,
then ORed with the invoking process's privilege vector, then exec()ed
normally.
Of course, it isn't sufficient to assign minimum privileges with
authorization vectors. A user can do a lot of damage even with just the
privilege to bind to a low port; if I attack some obscure POP client that
uses rcmd(3)-based authorization, and get its bind-to-privileged-port bit,
then I can impersonate anyone I want on the affected machine as far as
rlogin, rsh, etc. are concerned. I can remove print jobs submitted by
anyone on the machine (or generate them). I can shut down telnet on the
machine by causing inetd to stop listening to the port, then bind to the
telnet port and impersonate the attacked system.
Certainly the minimum-privileges idea is a good one, but you still can't
have security until all of the privileged programs (no matter how small
their privileges) become robust.
--
Zygo Blaxell. Unix/soft/hardware guru, was for U of Waterloo CS Club, now for
(name withheld by request). 10th place, ACM Intl Collegiate Programming Contest
Finals, 1994. Admin Linux/TCP/IP for food, clothing, anime. Pager: 1 (613)
760 8572. "I gave up $1000 to avoid working on windoze... *sigh*" - Amy Fong