How to mitigate the risk of a TOCTTOU attack
Are TOCTTOU attacks, exploiting time-of-check-to-time-of-use race conditions, a threat to your enterprise file systems? Expert Michael Cobb discusses the dangers and how to mitigate them.
Can you explain the security effects time-of-check-to-time-of-use issues can have on applications and what security pros need to know about mitigating them?
Time-of-check-to-time-of-use (TOCTTOU - pronounced TOCK-too) is a file-based race condition that occurs when a resource is checked for a particular value, such as whether a file exists or not, and that value then changes before the resource is used, invalidating the results of the check.
Errors can occur when the status changes unexpectedly, either maliciously or unintentionally, between a check and a subsequent operation. A TOCTTOU attack exploiting such conditions can lead to privilege escalation, allowing unauthorized access to resources, such as read and write access, as well as avoiding log and audit controls. This sort of attack is difficult to detect. It requires not only looking for evidence, but also determining whether it could be caused by TOCTOU.
TOCTTOU race conditions are most common in Unix file systems, but all systems are vulnerable. In Java for example, you can verify a file exists and a program can access it using the checkAccess() method, but there is no guarantee the file can still be accessed once the check has been completed. Most attacks require precise timing to execute system calls so they interleave properly with the victim and modify the established file condition in between the check and file operation steps. There are simpler forms of TOCTTOU though, such as a Web administrator locking a page to prevent editing after a user has already begun editing it. The edits will be accepted unless the application rechecks the status of the page.
The root cause of many TOCTTOU vulnerabilities lies in the lack of concurrency control in an operating system's file-system API and so it's not a problem that's easy to resolve. Most OSes change the order that instructions and processes are actually executed to improve efficiency. A programmer has to achieve atomicity of two operations using an API that isn't designed for such a purpose. The challenge therefore is ensuring the file system state, managed by the operating system, cannot change between two system calls.
Most UNIX systems have adopted variants of common file system calls that operate on file handles rather than file names. These calls end in “at”, such as openat and statat. Because file handles are a private mapping to a file, they cannot be changed by another program and so are not subject to race conditions with other applications. Another preventative measure when working with a single file is to lock it before the check, as opposed to afterwards so the resource, as checked, is the same as it is when in use. However, file locking can't automatically roll back a failed operation, which requires transaction support by the OS.
Beginning with Windows Vista, Microsoft added transaction support (TxF) to their NTFS file system. Within a transaction, all updates are kept isolated until committed, when they are atomically published to the rest of the system. Programmers should be aware of the dangers of TOCTTOU vulnerabilities and make use of these recent features to prevent TOCTTOU race conditions or reduce their potential impact.