sudo policy basics
John Sonmez has been encouraging me to write more online.
And as the other day I found some discussion and advice online suggesting
something in sudoers I don't agree with I decided to
write on that subject.
This article covers technical basics together with policy. Managers and auditors
might benefit from an improved understanding of what's involved even if they
don't write configuration themselves.
sudo is a setuid root program that allows non-root accounts to run certain
commands as if another account had run them - governed by the configuration which contains
details of who is supposed to run what. Examples can be seen at 
The program and the usual configuration file are documented.
When you are making or amending sudoers content you
are using technology to try to reach policy goals. These might be to allow
execution as root of certain commands (and no others),
to produce usable logging
and to keep the configuration understandable and maintainable.
There's great variation in the commands you might be interested in but that will
not be the subject of the article. There is nothing new in the technical remarks here -
I am explaining the policy implications arising from what
people may have found in the documentation since I first downloaded
sudo in 1994. Anybody who uses a program and expects good
results without reading the manual is likely to be disappointed. In the case of a
program like this that probably means insecure configuration.
A major piece of policy thinking is about whether you want a certain account allowed
to run arbitrary commands as root (e.g. root shell).
If you do you can most easily allow this with a rule for running su.
If you don't then you need to be very careful what you allow.
This suggests these main policy groups:
These could be combined e.g. by allowing restart of services as root plus allow root shell.
The root shell would be intended for use only when needed (situations other than restarting the
services) and a log entry that it had been used would be made. The organisation could follow
that up by asking what the shell was needed for.
A stricter policy would be that no root shells (or arbitrary commands) are allowed. There is the
approved set of commands and no more. If you have this aim you need to take care over what
is included in the approved commands.
The following commands would be unsafe choices because they change security state after which
the user may have access to do anything.
- allow a root shell (simplest and least restrictive policy)
- allow specific commands as root (without root shell)
- allow commands run as non-root (less capacity for causing damage)
- passwd (reset root password, run su)
- useradd usermod (create alternate root account)
- chown chmod (allow edits to files such as /etc/shadow)
- debugfs fsdb (similar to chown chmod)
ways to a shell
There are plenty of ways to get from a specific chosen command to any other command (such as a shell).
There are commands that run other commands - for some commands that is their main purpose
but for others it is just a small (and perhaps little-known) feature of the program.
There are programs that write files - and with nearly everything in unix being a file
there's a lot of scope for overcoming security that way.
Obvious commands that run other commands include:
Obvious commands that write files include:
- shells and interpreters
- time nice nohup
(subject to terminal avoidance in that last case but still commands as root)
- strace truss
- programs with shell escapes more less mail
- tar and similar
This brings me to the discussion that started me writing this. Someone had suggested
Cmnd_Alias NSHELLS = /bin/sh,/bin/bash
The above configuration attempts to allow all commands except for some exclusions.
In fact it allows all commands.
The exclusions expressed above are for program names - not the programs themselves.
Since a copy of any program file is a file with the same content but a different name it follows
that anyone making a copy (or only a link) gets a program of the same content but at a name that
is not one of the set banned by the sudoers configuration.
Cmnd_Alias NSU = /bin/su
Cmnd_Alias NVIS = /usr/sbin/visudo
Cmnd_Alias NSDO = /usr/bin/sudo
UserA ALL = NOPASSWD: ALL, !NSHELLS, !NSU, !NVIS, !NSDO
UserA can't execute commands like sudo su - , sudo bash , sudo sudo bash etc
cp /bin/bash /tmp/harmless
Also the vast number of ways to arbitrary commands includes the programs with shell escapes and the other
categories listed above.
sudo /tmp/harmless # oops
sudo more /etc/services # followed by !sh, oops
In an article I'm trying to keep simple I won't go into the NOEXEC tag available
in sudoers except to say that it would prevent
sudo man ls # followed by !sh, oops (gets root on Fedora, not on SuSE)
sudo man ls
completely which is different from allowing it to be run and preventing shell escapes from it.
The above examples show that there are many commands that will need to be banned if
you want to prevent root shells - and a list of what to ban doesn't work. The way
forward is to start with everything banned and allow only specific things you want
(after ensuring they don't breach your policy). Of course what a program does depends
not only on the program but also on the input such as the command line.
john ALL=/usr/bin/crontab -u * -l
The above configuration is a real example I've encountered - it allows john to run crontab
as root using the -u option to make crontab act for a particular user. Also
the '-l' at the end of the line is supposed to mean list the cron file for that user.
That looks a bit like read-only access to the cron files for all users with no
ability to change them.
In fact it allows creating or changing cron files for any user.
A manual for crontab (there are different versions) shows that you can supply a filename
at the end of a command to be used as input - importing that file as the cron settings.
The alert reader will notice that the configuration above ends the line with '-l' so
to import a file with that sudo rule we'd better put our desired commands
in a file called '-l' (which is perfectly possible).
One more detail is needed to import the file as root's cron.
sudo crontab -u root -- -l
The "--" is not in the manual for crontab but it comes from the getopt library function; and the
"*" in the rule allows it by matching "root --" as explained in the manual
The special argument "--" forces an end of option-scanning regardless of the scanning mode.
A better rule would be this where there is no variation allowed in the parameters but the
username is supplied with '-u' to sudo rather than crontab.
john ALL=(ALL) /usr/bin/crontab -l
This is another suggested entry I have seen - I don't think there was a strong reason for it.
If the 'evil' user wants to take over the account 'victim' on the same host it
will be useful to write/overwrite ~victim/.ssh/authorized_keys.
with ssh-keygen run via sudo.
Probably the maintainers haven't used O_EXCL or O_NOFOLLOW in opening the key files because they
can't believe anyone would enable ordinary users to run it via sudo.
ln -s ~victim/.ssh/authorized_keys id_rsa.pub
# Now you are ready to generate a key - the two output files overwrite what you made already.
sudo ssh-keygen -t rsa -f `pwd`/id_rsa
chmod go= id_rsa # you own this file
ssh victim@localhost # ~victim/.ssh/authorized_keys contains your public key
The list of dangerous commands is almost unlimited - some more examples:
sendmail can be told what to use as a configuration file
(and when run as root will do so) - the file contains commands.
Here is a demo I did on Fedora 22. The sudoers file contains this:
The 'evil' user first copies /var/mail/sendmail.cf to /tmp/sendmail.cf
and edits it to use an alternative port number (1025) and to run different versions of
procmail and smrsh
which he also provides as scripts in /tmp/ .
O DaemonPortOptions=Port=1025,Addr=127.0.0.1, Name=MTA
This demo /tmp/procmail script creates a logfile to show it has been run as root.
Mprocmail, P=/tmp/procmail, F=DFMSPhnu9, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP/HdrFromSMTP,
Mlocal, P=/tmp/procmail, F=lsDFMAw5:/|@qSPfhn9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
Mprog, P=/tmp/smrsh, F=lsDFMoqeu9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=$z:/,
Next comes the command run by 'evil'
date > /root/SUDO_WARNING_PROCMAIL
root 1392 0.0 0.1 233440 7852 pts/0 S+ 00:22 0:00 sudo /usr/sbin/sendmail -C /tmp/sendmail.cf -bD
And another session is used to send mail to that sendmail listener causing it to make a mail delivery
with the nobbled procmail and the log shows it worked.
-rw-r--r--. 1 root root 29 Jul 18 00:25 SUDO_WARNING_PROCMAIL
SElinux was enabled in enforcing mode but failed to prevent this security lapse.
The above may remind readers of Olaf Kirch's report of a bug in vixie-cron in 1999
where a user's cron settings caused sendmail to be run as root.
All I've done here is demonstrate the same thing but called from sudo.
What could be wrong with allowing merely the tvf option that won't make or extract a tarfile?
evil ALL=/bin/tar tvf *
How about this which despite encountering an error has first
run the command supplied as a replacement for rsh.
tar tvf localhost:/wibble --rsh-command=/tmp/something-evil
The -w option to tcpdump causes it to write a file (that will follow symbolic links).
That is enough to overwrite files but it's hard to get complete control of what's in the file you'd write.
In some cases though that's unimportant. If you wrote to .rhosts a line with a + by itself
can be made with three characters "\n+\n" which is ascii 10,43,10 - easy to slip into some network data
(such as an IP address). It's probably not much used these days but where it is that one line is
the configuration to allow access from any host that resolves - and it won't matter that the rest
of the file is junk.
More ominously there is an option to run external commands for handling output files.
sudo tcpdump -w OUT -Z root -G 5 -z /tmp/do_evil
I saw this mentioned on the web but I can't remember where so I'll leave a link to
an article  someone else wrote about the -z post-rotate option.
SElinux was enabled in enforcing mode but failed to prevent this security lapse. I don't know
how to extend an SElinux policy to prevent this but using Apparmor is easy.
Extracts from the manual deal with attempting to exclude commands with !
Note, however, that using a '!' in conjunction with the built-in ALL alias to allow a user to run 'all but a few' commands rarely works as intended (see SECURITY NOTES below).
Beside knowing the tools you are working with, it is also good to know something
about the subject of security when working toward security goals. It has been
known for decades that you should explicitly define access rather than permit
everything minus some exceptions.
That is true in relation to sudo as in many other situations.
Here is some work by other people summarising the most famous statement on this.
Smith writes about principles
It is generally not effective to 'subtract' commands from ALL using the '!' operator. A user can trivially circumvent this by copying the desired command to a different name and then executing that. For example:
bill ALL = ALL, !SU, !SHELLS
Doesn't really prevent bill from running the commands listed in SU or SHELLS since he can simply copy those commands to a different name, or use a shell escape from an editor or other program. Therefore, these kind of restrictions should be considered advisory at best (and reinforced by policy).
In general, if a user has sudo ALL there is nothing to prevent them from creating their own program that gives them a root shell (or making their own copy of a shell) regardless of any '!' elements in the user specification.
Only a handful of Saltzer and Schroeder's original 1975 design principles have stood the test of time.
I would put that as only a handful have made it into widespread use. It it true some of them are not
easy to do in current systems and it can be easy to find excuses not to do them. The rule on failsafe
defaults is one that I think normally can be applied.
Perhaps lists of principles belong primarily in the classroom and not
in the workplace. The short phrases are easy to remember, but they may
promote a simplistic view of technical problems. Students need simplicity
to help them build an understanding of a more complex reality.
As someone whose attitude was developed more in the workplace than the classroom
I think people are not aiming for simple correctness as much as they can and should.
The original 1975 paper  is not an easy read.
There is some overlap between the above and the writing of Marcus Ranum (not at all hard to read).
Commands that take input or use files writable by users (for input or output) make it harder
to tell what was done when reviewing logs. There is some capacity for logging input and output
but that's a significant burden that might be reserved for actual root shells provided you can
avoid the commands capable of giving root shells when misused.
I have only shown commands used as intended (by the programmers - not by the
people behind the sudoers rule in the examples).
This leaves untouched the whole subject of memory corruption which could make many more
programs execute unintended code.
I have not found any large or representative collections of real sudoers
files published - without that I have more anecdote than data on the prevalence of the
problems I have described. If someone can publish such a thing (perhaps with some
obscuring of the origin) I think that would make interesting reading.
- Soft Skills
- A P Lawrence
- sudo manual
- sudoers manual
- 1999 cron bug using sendmail
- why sudo tcpdump is dangerous
Even if you had been satisfied with a previous version of the program you
would need to be alert to new features.
git bisect at https://github.com/the-tcpdump-group/tcpdump tells me
Date: Thu Mar 23 17:33:01 2006 +0000
add support for the the post-rotate -z flag (to be used in
- Saltzer & Schroeder commentary by Shostack
from the series
The Security Principles of Saltzer and Schroeder
- Saltzer & Schroeder commentary by Wagner
- Security Design Principles
- Saltzer and Schroeder
- Ranum Six Dumbest
Written by Peter M Allan. 2016
back to articles