by Paul Ducklin
A recently-patched bug in the widely-used sudocommand makes for interesting reading.
The patch reminds us of some important points in security-related programming.
The UNIX sudo command is usually translated to mean “do as superuser” – in other words, it lets you run administrative commands one at a time, without logging in as the superuser (root, in UNIX parlance).
More accurately, sudo stands for “substitute user identity and do“, so that you can use it to take on an identity other than root, such as a backup user or a database administrator.
Clearly, sudo is the sort of program in which a vulnerability will almost certainly lead to an escalation-of-privilege exploit. Since sudo’s main purpose is to let you enjoy root-like powers in a controlled way, anyone who can sneak past sudo’s permission checks can turn a minor intrusion into an effectively unlimited one.
So why use a potentially risky command like sudo at all? The answer is that sudo can improve security significantly:
* You don’t need to tell all your administrative users the root password.Sudo lets them authenticate individually, and keeps a log of each individual’s administrative activity.
* You don’t need to work at a root prompt. This avoids running every command with supreme power. You take on root privileges only when they are strictly necessary.
* You can authorise users to run some, but not all, administrative commands. You can let them start a backup, for example, but not add new users to the system.
In fact, some operating system distributions – the Ubuntu family, for example, and OS X – discourage root login altogether, and use sudo for all administrative tasks.
This isn’t perfect, so caution is still required.
Sudo lets you activate a root prompt if you want – for example, with the commands sudo su - or sudo -s.
And many users, confronted with aPermission denied error, fall into the bad habit of repeating their previous command with sudo in front. (If you have developed this habit, get rid of it. Use sudo because you ought to, not merely because it’s convenient.)
Anyway, sudo was recently found to have a single-line bug which affected its user authentication in rather specific circumstances.
Sudo is controlled by a configuration file called sudoers, or by similar configuration data managed by LDAP directory services.
Amongst other things, this file lets you regulate the power of users by the network they’re on. When sudo sets out to verify a user’s network mask – for example, 203.0.113.0/24 – it enters a C function calledaddr_matches_if_netmask().
The authorisation part of this function is split into two parts. One part checks IPv4 addresses; the other checks IPv6 addresses.
The function chooses which path to take using a switch statement. Switches are one of C’s decision-making instructions, and they look something like this:
switch (dayofweek) {
case SUNDAY:
do_sunday_stuff();
break;
case SATURDAY:
do_saturday_stuff();
break;
default:
do_weekday_stuff();
break;
}
Notice the break statements. These tell C, “That’s everything for this code path through this switch, thanks. Exit the switch right now.”
However, you can legally omit any break, if you want processing to fall through to the next case in the switch:
switch (dayofweek) {
case SUNDAY:
do_special_sunday_stuff();
break;
case SATURDAY:
do_saturday_stuff();
/* Break omitted - deliberate fall-through */
/* to do non-Sunday stuff on Saturday too. */
default:
do_nonsunday_stuff();
break;
}
And that’s what happened in sudo. The break statement between the IPv4 checking and the IPv6 checking was left out. So if the IPv4 checks failed, the IPv6 checks – inappropriate in the circumstances – were tried instead. With nothing to match against nothing, the checks succeeded, even though they had already failed in the IPv4 code above.
Result: users whose sudo access was regulated by network masks would be authenticated when they shouldn’t be. So an attacker could masquerade as an authorised internal user, even from outside the network.
And, as promised at the outset, this reminds us of some important points in security-related programming:
* Bugs can be arcane enough to escape notice for years. This can happen even in security software, and even if the source code is freely available.
* Bugs can be caused even (or especially!) by minuscule errors.
* Bugs are worth patching.
* Watch your breaks.
By the way, always put a break after the last case in a switch. It might not be necessary now, but it ensures that coders who add cases later don’t forget the now-necessary breaks above their new code.
Technically, if you don’t use IPv4 network masks in your sudo configuration, you aren’t affected by this bug. But since almost every Linux or UNIX has sudo installed, it’s worth upgrading.
The XKCD ‘Sandwich’ is comic #149 from http://xkcd.com/ – “a webcomic of romance,
sarcasm, math, and language.“
sarcasm, math, and language.“
Note to Windows users: your equivalent of sudo is runas. Try runas /? at a command prompt to find out more.“