Best way to gain root privileges

Adam Skutt askutt at
Thu Feb 17 13:40:36 CET 2011

On Thu, Feb 17, 2011 at 2:12 AM, Dan Stromberg <drsalists at> wrote:
> On Wed, Feb 16, 2011 at 6:59 PM, Adam Skutt <askutt at> wrote:
>> On Feb 16, 9:00 pm, Dan Stromberg <drsali... at> wrote:
>>> So yeah, whether you use perl or anything else invoked with #!, you're
>>> pretty much better off with sudo, or a tiny C wrapper that's so simple
>>> it's hard to get wrong.
>> UNIX makes this almost impossible
> Please give a source that includes justifying detail.  Then you have the
> right to ask me if there are well understood ways around each of the issues
> identified.

I did, the sudo source; kindly read the whole paragraph before
replying next time.  Do you think they go through all the contortions
regarding closing FDs, handling signals, etc. just for fun?  Do you
think what they go through is unnecessary?  No, the correct and
portable ways to do many of the necessary actions are hardly obvious.

Almost impossible refers to the fact that tasks that ought to be
relatively simple, like closing all file descriptors, aren't made
trivial by any standard.  Heck, even figuring out what file
descriptors might need to be closed is non-trivial!  There is no one
convenient source that plainly documents everything you must do and
why, beyond the source code of applications that already escalate
privileges safely.  In which case, you might as well just run one of

Very few (any?) programs that run setuid (root) have existed without a
security vulnerability in their history.  On the continuum from
trivial to impossible, writing a program that securely elevates
privilege definitely sits much closer to impossible.

> Actually, they can be.  Here's one, as a very easy-to-find example:
> $ ls -al
> cmd started 2011 Wed Feb 16 10:19:21 PM
> total 8
> drwxr-xr-x  2 dstromberg dstromberg 4096 2011-02-16 22:19 .
> drwxr-xr-x 61 dstromberg dstromberg 4096 2011-02-16 22:18 ..
> -rwsr-xr-x  1 root       dstromberg    0 2011-02-16 22:19
> correct-and-simple-setuid
> benchbox-dstromberg:~/src/correct-and-simple-setuid i686-pc-linux-gnu 12006
> - above cmd done 2011 Wed Feb 16 10:19 PM
> $ ./correct-and-simple-setuid
> cmd started 2011 Wed Feb 16 10:19:24 PM
> benchbox-dstromberg:~/src/correct-and-simple-setuid i686-pc-linux-gnu 12006
> - above cmd done 2011 Wed Feb 16 10:19 PM
> $ echo $?
> cmd started 2011 Wed Feb 16 10:19:26 PM
> 0
> benchbox-dstromberg:~/src/correct-and-simple-setuid i686-pc-linux-gnu 12006
> - above cmd done 2011 Wed Feb 16 10:19 PM
> It's a correct, setuid replacement for /bin/true.  It's 0 bytes long.  Now,
> I expect you to exploit it, since I claim that it's both tiny and simple.
> IOW, it's a reductio ad absurdum.

The only absurd part of this example is why I would do this in the
first place.  If this is the level of discourse you're going to choose
to operate at, then I don't see any reason to waste my time any
further with you.  Counter-examples that do nothing meaningful are
themselves meaningless.

> sudo is an example of something that _isn't_ closely matched with what it's
> running (beyond a little text in a config file), not something that _is_.
>  You're engaging in a category error there.

No, I'm not, the entire point is that any wrapper involving user input
in any capacity (including on the part of the program it ends up
running) must do most, if not all, of the things sudo does wrt
actually running something with privilege.  Trying to make assumptions
on the part of your parent is folly.

> A better example is apache suexec - the helper portion of which is  428
> physical SLOC, and it's more complex than most need to be because it keeps
> many env vars and prunes out others.

(among others) You don't want to be Apache suexec, kids!  It's also
sounds, from GSO's description, rather useless here.

>> Passing things through sudo(1) is really the only sensible route these
>> days but even that can be fraught with peril.
> Wait - I thought you just said that it was almost impossible unless the
> setuid wrapper was well matched with the program in question.
> Oh, you did.

The entire point of my statement was that such a thing is an
impossibility: the wrapper cannot safely make assumptions about
whatever calls it.  Nor is it permissible to make assumptions about
whatever the wrapper calls except in very trivial circumstances.

The inherent contradiction is that we want (legitimately) for our
wrapper to assume it will only be executed by our own code, to reduce
the problems it has to worry about.  Unfortunately, UNIX makes this
impossible and makes assuming literally nothing the only safe choice.

> Quantifier error: You've given an example of why taint isn't perfect, not a
> proof of why it's useless.  I said it would be useful, not that it was 100%
> trouble free.

Those sorts of problems are the hard ones to defend over.  You're
suggesting taint mode like one would suggest locking one's door,
that's great if you want to keep out a thief, but it doesn't even slow
down the police with a battering ram!  The battering ram is what we
want to defend against.  So you'll have to forgive me for calling the
door lock (taint mode) useless.

> Moreover, I'd like to see your code demonstrating the ability to make a
> simple setuid wrapper that doesn't even open a file, append to /etc/shadow.
> If you'd like, I'll write the wrapper for you.
> Note that >> is performed by the shell, not the wrapper.  If that
> unprivileged shell (or unprivileged C program, or whatever) can >>
> /etc/shadow, then you've got bigger problems to worry about.

Yes, you can't use a shell redirect, mea culpa.  Privilege escalation
races are nothing new, however:  Taint mode does not save you
from those.

> Oh, did you mean the _subprogram_ could be exploited?  Why didn't you say
> so?  And why is this an attribute of the wrapper, and not an attribute of
> the subprogram?  IOW, you appear to be reasoning that because the
> _subprogram_ the wrapper invokes /might/ be flawed, the teensy setuid
> _wrapper_ /definitely/is/inherently/ broken.  This, assuming you're really
> suggesting this, is both a category error and a quantifier error.

The entire point of the wrapper is to make the subprogram safe for
escalated execution!  If the subprogram were already safe for
escalated execution, we would just put the setuid bit on it directly
and skip the wrapper altogether!  This includes even a wrapper for the
mere purpose of "executing a script".

>>  Besides, I'm not even remotely convinced that 'removing
>> skill' is a good idea.
> Fine.  Forget Python.  Forget C.  Forget assembly language.  Forget machine
> language.  Forget firmware programming.  Forget plugboards.  Forget GUI's.
> Forget curses.  Forget command line.  Forget punch cards.  Forget toggle
> switches.  In fact, forget electricity where it might remove skill.  Since
> removing skill is a bad idea, I expect that you'll greatly prefer to perform
> your "coding" using levers and gears, along the lines of the Antikythera
> mechanism.  Then again, maybe you're a little more hardcore than that, and
> would prefer to forsake automation, forsake handwriting and do your
> computations strictly in your head.

The fact you think any of this is relevant to my point is absolutely

> Did we change the subject again?  I'm talking about a C wrapper for a
> script.  Are you talking about a script wrapper for a script?  You're
> confusing me.  ^_^

A C wrapper for a script is emphatically not what he needs, he needs a
way to copy files to a privileged area.  Involving a script in that
process seems pretty plainly undesirable, especially in these modern


More information about the Python-list mailing list