[UNIX] Security Problems Found with mkstemp()

From: support@securiteam.com
Date: 12/22/02

  • Next message: support@securiteam.com: "[UNIX] PHP-Nuke mail CRLF Injection Vulnerabilities"
    From: support@securiteam.com
    To: list@securiteam.com
    Date: 22 Dec 2002 13:15:05 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    Beyond Security would like to welcome Tiscali World Online
    to our service provider team.
    For more info on their service offering IP-Secure,
    please visit http://www.worldonline.co.za/services/work_ip.asp
    - - - - - - - - -

      Security Problems Found with mkstemp()
    ------------------------------------------------------------------------

    SUMMARY

    A common practice of installing 'tmpwatch' utility or similar software
    configured to sweep the /tmp directory on Linux and UNIX systems can
    compromise secure temporary file creation mechanisms in certain
    applications, creating a potential privilege escalation scenario. This
    document briefly discusses the exposure, providing some examples, and
    suggesting possible workarounds.

    It is believed that many UNIX operating systems using 'tmpwatch' or an
    equivalent are affected. Numerous Linux systems, such as Red Hat, that
    ship with cron daemon running and 'tmpwatch' configured to sweep /tmp are
    susceptible to the attack.

    DETAILS

    'Tmpwatch' is a handy utility that removes files which haven't been
    accessed for a period of time. It was developed by Erik Troan and Preston
    Brown of Red Hat Software, and, with time, has become a component of many
    Linux distributions, also ported to platforms such as Solaris, *BSD or
    HP/UX. By default, it is installed with a crontab entry that sweeps /tmp
    directory on a daily basis, deleting files that have not been accessed for
    the past few days.

    An alternative program, called 'stmpclean' and authored by Stanislav
    Shalunov, is shipped with *BSD systems and some Linux distributions to
    perform the same task, and some administrators deploy other tools or
    scripts for this purpose.

    Vulnerability details:
    Numerous applications rely either on mkstemp() or custom O_EXCL file
    creation mechanisms to store temporary data in the /tmp directory in a
    secure manner. Of those, certain programs run with elevated privileges, or
    simply at a different privilege level than the caller.

    The exposure is a result of a common misconception, promoted by almost all
    secure programming tutorials and manpages, that /tmp files created with
    mkstemp(), granted that umask() settings were proper, are safe against
    hijacking and common races. The file, since it is created in a sticky-bit
    directory, indeed cannot be removed or replaced by the attacker running
    with different non-root privileges, but since many operating systems
    feature 'tmpwatch'-alike solutions, the only thing that can and should be
    considered safe in /tmp is the descriptor returned by mkstemp() - the
    filename should not be relied upon. There are two major reasons for this:

    1) Unlink() races
    It is very difficult to remove a file without risking a potential race
    (see section 4). 'Tmpwatch' does not take any extra measures to prevent
    races, and probes file creation time using lstat(). Based on this data, it
    calls unlink() as root. Problem is, on a multitasking system, it is
    possible for the attacker to get some CPU time between those two system
    calls, remove the old "decoy" file that has been probed with lstat(), and
    let the application of his choice create its own temporary file under this
    name. While mkstemp() names are guaranteed to be unique, they shouldn't be
    expected to be unpredictable - in most implementations, the name is a
    function of process ID and time - so it is possible for the attacker to
    guess it and create a decoy in advance. Once the tmpwatch process is
    resumed, the file is immediately removed, based on the result of earlier
    lstat() on the old, no longer existing file.

    While this three-component race requires very precise timing, it is
    possible to try a number of times in a single 'tmpwatch' run if enough
    decoy files are created by the attacker. Additionally, since each step of
    the attack would result in a corresponding file system change, it is
    fairly easy to carefully measure timings and coordinate the attack.

    If the attacker cannot make the application run at the same time as
    'tmpwatch' - for example, if the application is executed by hand by the
    administrator, or is running from cron - 'tmpwatch' itself can be
    artificially delayed for almost an arbitrary amount of time by creating
    and continuously expending an elaborate directory structure in /tmp using
    hard links (to preserve access times of files) and running other processes
    that demand disk access and cache space to slow down the process.

    'Stmpclean' offers additional protection against races by not removing
    root-owned files and temporarily dropping privileges when removing the
    file to match the owner of lstat()ed resource. Unfortunately, not removing
    root files is a considerable drawback, and there is still a potential for
    a race using carefully crafted hard links to a file owned by the victim
    and two concurrent 'stmpclean' processes:

     - the attacker links /tmp/foo to ~victim/.bash_profile
     - tmpwatch #1 does lstat() on /tmp/foo and setuid victim
     - tmpwatch #2 does lstat() on /tmp/foo and setuid victim
     - tmpwatch #1 does unlink("/tmp/foo")
     - victim application creates /tmp/foo at uid==victim
     - tmpwatch #2 does unlink("/tmp/foo") and succeeds
     - the attacker creates /tmp/foo
     - victim application proceeds

    On certain systems such as Owl Linux, the attack will be not possible due
    to hard link limits imposed on sticky-bit directories.

    2) Suspended processes and 'legitimate' file removal
    Here, all conventional measures that could be exercised by /tmp cleaners
    fail miserably. A vulnerable application can be often delayed or suspended
    after mkstemp() / open() - for example, a setuid program can be stopped
    with SIGSTOP and resumed with SIGCONT. If the application is suspended for
    long enough, its temporary files are likely to be removed. This method
    requires much less precision, but is also more time-consuming and has a
    more limited scope (interactive applications only).

    Note that it is sometimes possible to delay the execution of a daemon -
    client wait, considerable I/O or CPU loads, and subsequent mkstemp() calls
    can be all used to achieve the effect. The feasibility and efficiency is
    low, but the potential issue exists. Some client applications that are
    often left unattended and create temporary files - such as mail/news
    clients, web browsers, irc clients, etc - can also be used to compromise
    other accounts on the machine.

    Not all applications are prone to the problem just because mkstemp() is
    used to create files in /tmp; if the file name is not used to perform any
    sensitive operations with some extra privileges afterward (read, write,
    chown, chmod, link/rename, etc), and only the descriptor is being used,
    the application is safe. This practice is often exercised by programmers
    who want to avoid leaving dangling temporary files in case the program is
    aborted or crashes. Similarly, if the application uses temporary files
    improperly, but does not rely on their contents and does not attempt to
    access them with higher privileges, the application is secure in that
    regard.

    Applications that run with higher privileges and reopen their /tmp
    temporary files for reading or writing, call chown(), chmod() on them,
    rename or link the file to replace some sensitive information, and so on,
    are exposed. It is worth mentioning that a popular 'mktemp' utility coming
    from OpenBSD passes only the filename to the caller shell script, thus
    rendering almost all scripts using it fundamentally flawed. If the script
    is being run as a cron job or other administrative task, and mktemp is
    used, the system can be likely compromised by replacing the file after
    mktemp and prior to any write to the file. In the example quoted in the
    documentation for mktemp(1):

        TMPFILE=`mktemp /tmp/$0.XXXXXX` || exit 1
        echo "program output" >> $TMPFILE

    ..the attacker would want to replace temporary file right before 'echo',
    causing the text "program output" to be appended to a target file of his
    choice using symlinks or hardlinks; or, if it is more desirable, he'd
    spoof file contents to cause the program to misbehave.

    Another example of the problem is a popular logrotate utility, coded -
    ironically - by Erik Troan, one of co-authors of 'tmpwatch' itself. The
    program suffered /tmp races in the past, but later switched to mkstemp().
    The following sequence is used to handle post-rotation shell commands
    specified in configuration files:

      open("/tmp/logrotate.wvpNmP", O_WRONLY|O_CREAT|O_EXCL, 0700) = 6
      ...
      write(6, "#!/bin/sh\n\n", 11) = 11
      write(6, "\n\t/bin/kill -HUP `cat /var/lock/"..., 79) = 79
      close(6) = 0
      ... fork, etc ...
      execve("/bin/sh", ["sh", "-c", "/bin/sh /tmp/logrotate.wvpNmP" ...

    Obviously, if the attacker can have /tmp/logrotate.* replaced in between
    mkstemp() (represented as open() syscall above) and the point where
    another process is spawned, a shell interpreter is invoked, then executes
    another copy of the shell interpreter (apparent programmer's mistake) and
    finally reads the input file - which is a considerable chunk of time - the
    shell will be called with attacker-supplied commands to be executed with
    root privileges.

    On Red Hat, logrotate is executed from crontab on a daily basis, in a
    sequence before 'tmpwatch', and the easiest option for the attacker is to
    maintain a still-running tmpwatch process from the previous day to exploit
    the condition. On systems where those programs are not executed
    sequentially - for example, when both programs are listed directly in
    /etc/crontab - the attack requires less precision.

    Workarounds and fixes:
    Recommended immediate workaround is to discontinue the use of 'tmpwatch'
    or equivalent to sweep /tmp directory if this service is not necessary.

    For applications that rely on TMPDIR or a similar environment variable,
    setting it to a separate, not publicly writable directory is often a
    viable solution. Note that not all applications honor this setting.

    In terms of a permanent solution, two different attack vectors have to be
    addressed, as discussed in section 3:

    1) unlink() race
    The proper way to remove files in sticky-bit directories while minimizing
    the risk is as follows:
           a) lstat() the file to be removed
           b) if owned by root, do not remove
           c) if st_nlink > 1, do not remove
           d) if owned by user, temporarily change privileges to this user
           e) attempt unlink()
           f) if failed, warn about a possible race condition
           g) switch privileges back to root

    With the exception of step c, this is implemented in 'stmpclean'.
    Unfortunately, step c is crucial on systems that do not have restricted
    /tmp kernel patches from Openwall ( <http://www.openwall.com>
    http://www.openwall.com), otherwise, there is a potential for fooling the
    algorithm by supplying a hard link to a file owned by the victim, as
    discussed in section 3.

    This approach has several drawbacks - such as the fact root-owned files
    will not be removed. Other solution is to modify applications that
    generate filenames on their own, and to modify mkstemp(), to generate
    names that are not only unique, but not feasible to predict.

    Another suggestion is to implement a funlink() capability in the kernel of
    the operating system in question, to allow race-free file removal, thus
    removing the non-root ownership requirement for the method described
    above, and simplifying the approach. A skeleton patch to implement
    funlink() semantics and make sure the file being removed is the file
    opened and fstat()ed previously is available at:
    <http://lcamtuf.coredump.cx/soft/linux-2.4-funlink.diff>
    http://lcamtuf.coredump.cx/soft/linux-2.4-funlink.diff (this and other
    patches are not endorsed by RAZOR in any way).

    2) suspended process and 'legitimate' file removal
    This issue is fairly difficult to address. The most basic idea is to use a
    special naming scheme for temporary files to avoid deletion -
    unfortunately, this seems to defeat the purpose of using tmpwatch-alike
    solutions in the first place.

    An alternative approach, which is to enforce separate temporary
    directories for certain applications, either process-, session- or uid-
    based, is generally fairly controversial, and raises some concerns.
    Advisory separation is generally acceptable, but there are a number of
    applications that do not accept TMPDIR setting, and a widespread practice
    of using /tmp in in-house applications. Mandatory separation (kernel
    modification) raises compatibility concerns and is generally approached
    with skepticism - no implementation has become particularly popular.

    Ideally, implementations should carefully audit their sources. It is
    recommended for privileged applications to use private temporary
    directories for sensitive files, if possible; if using /tmp is necessary,
    extra caution has to be exercised to avoid referencing the file by name.
    Note that comparing the descriptor and a reopened file to verify inode
    numbers, creation times or file ownership is not sufficient - please refer
    to "Symlinks and Cryogenic Sleep" by Olaf Kirch, available at
    <http://www.opennet.ru/base/audit/17.txt.html>
    http://www.opennet.ru/base/audit/17.txt.html.

    It's worth noticing that 'tmpwatch' offers a -s option, which causes the
    program to run the 'fuser' command to prevent removal of files that are
    currently open. At first sight, this could be an effective way to solve
    the problem. Unfortunately, this is not true, since many applications
    close the file for a period of time before reopening (including logrotate
    and mktemp(1)).

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:lcamtuf@razor.bindview.com>
    Michal Zalewski of Bindview.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



    Relevant Pages

    • [RAZOR] Problems with mkstemp()
      ... A common practice of installing 'tmpwatch' utility or similar software ... compromise secure temporary file creation mechanisms in certain applications, ... susceptible to the attack. ... safe against hijacking and common races. ...
      (Bugtraq)
    • [VulnWatch] [RAZOR] Problems with mkstemp()
      ... A common practice of installing 'tmpwatch' utility or similar software ... compromise secure temporary file creation mechanisms in certain applications, ... susceptible to the attack. ... safe against hijacking and common races. ...
      (VulnWatch)
    • [Full-Disclosure] [RAZOR] Problems with mkstemp()
      ... A common practice of installing 'tmpwatch' utility or similar software ... compromise secure temporary file creation mechanisms in certain applications, ... susceptible to the attack. ... safe against hijacking and common races. ...
      (Full-Disclosure)
    • [Full-Disclosure] [RAZOR] Problems with mkstemp()
      ... A common practice of installing 'tmpwatch' utility or similar software ... compromise secure temporary file creation mechanisms in certain applications, ... susceptible to the attack. ... safe against hijacking and common races. ...
      (Full-Disclosure)
    • [RAZOR] Problems with mkstemp()
      ... A common practice of installing 'tmpwatch' utility or similar software ... compromise secure temporary file creation mechanisms in certain applications, ... susceptible to the attack. ... safe against hijacking and common races. ...
      (SecProg)