Potential bypass of tty_tickets constraints
When a user successfully authenticates with sudo, a time stamp file is updated to allow that user to continue running sudo without requiring a password for a preset time period (five minutes by default).
This time stamp file can either be common to all of a user’s terminals, or it can be specific to the particular terminal the user authenticated themselves on. The terminal-specific time stamp file behavior can be controlled using the tty_tickets option in the sudoers file. This option has been enabled by default since sudo 1.7.4. Prior to sudo 1.7.4, the default was to use a single time stamp for all the user’s sessions.
A vulnerability exists because the user can control which terminal the standard input, output and error file descriptors (0-2) refer to. A malicious user could use this to run commands via sudo without authenticating, so long as there exists a terminal the user has access to where a sudo command was successfully run by that same user within the password timeout period (usually five minutes).
The vulnerability does not permit a user to run commands other than those allowed by the sudoers policy.
Sudo 1.3.5 through 1.7.10p5 and sudo 1.8.0 through 1.8.6p6 inclusive when the “tty_tickets” option is enabled. This option is enabled by default in sudo 1.7.4 and above.
This vulnerability has been assigned CVE-2013-1776 in the Common Vulnerabilities and Exposures database.
The vulnerability can be triggered when the standard input, output
and error file descriptors (0-2) of a process are closed and a
different terminal device is opened and connected to those descriptors.
When sudo tries to determine the terminal device via the ttyname()
function, it will get the name of the other terminal instead. The
core problem is that while ttyname()
can be used to determine the
name of the terminal device connected to a specific file descriptor,
there is no portable way to determine the name of the terminal
associated with the session the process belongs to. However, on
many systems it is possible to determine this by using the /proc
file
system or the sysctl()
function.
Most operating systems that have the /proc
file system provide a
way to determine the controlling terminal device number for a process;
this information is used by the ps command for example. On Linux, this
is the tty_nr
field in /proc/self/stat
(the seventh entry). On
systems with an SVR4-style /proc
, this is the pr_ttydev
member of
struct psinfo
, which comes from /proc/self/psinfo
. Most BSD systems
that support the sysctl()
function also provide a way to get the
terminal device number via the KERN_PROC_PID
sysctl. By mapping
this device number to a file name, it is possible to get the name
of the terminal file without resorting to ttyname()
. Sudo began
using this method to determine the process’s terminal starting
with version 1.8.5 and 1.7.10.
However, sudo still used the ttyname()
function as a fall back when
no controlling terminal was found via /proc
or sysctl()
. This
allowed a malicious process to cause sudo to use ttyname()
simply
by creating a new session without a controlling tty before executing
sudo. In sudo 1.8.6p6 and 1.7.10p5, this fall back behavior was
removed. This fixed the vulnerability for systems where the process’s
controlling terminal could be determined via /proc
or sysctl()
.
Sudo 1.8.6p7 and 1.7.10p6 contain an additional fix for systems
without /proc
or sysctl()
that stores the POSIX session ID in the
time stamp file itself. The controlling terminal is specific to
the POSIX session it is associated with. It is not possible for
two processes in different sessions to have the same controlling
terminal. Sudo will now compare the current session ID with the
one in the time stamp file and ignore the time stamp file if the
session ID does not match. This has the additional benefit of
making it much less likely that a user will be able to reuse the
time stamp file after logging out and back in again on the same
terminal.
A (potentially malicious) program run by a user with sudo access may be able to bypass the tty_tickets constraints. In order for this to succeed there must exist on the machine a terminal device that the user has previously authenticated themselves on via sudo within the last time stamp timeout (5 minutes by default).
This program may use sudo’s -n
flag to “probe” the terminals in
question to see if there is an active time stamp file for the user.
Prior to sudo 1.8.6 and 1.7.10, if a password was required when the
-n flag was specified the failure would not be logged, allowing
the program to perform such probes without being detected. The
successful command (if any), would still be logged.
The bug is fixed in sudo 1.8.6p7 and 1.7.10p6.
Ryan Castellucci brought the initial ttyname()
issue to my attention.
Subsequently, James Ogden discovered that using setsid()
to create
a new session would cause sudo to fall back to using ttyname()
.
Other shortcomings in sudo’s tty_tickets functionality have been known and discussed openly for some time. There is a long discussion about them at Ubuntu.