The window of time between when a file property is checked and when the file is used can be exploited to launch a privilege escalation attack.
File access race conditions, known as time-of-check, time-of-use (TOCTOU) race conditions, occur when:
1. The program checks a property of a file, referencing the file by name.
2. The program later performs a filesystem operation using the same filename and assumes that the previously-checked property still holds.
Example 1: The following code is from a program installed setuid root
. The program performs certain file operations on behalf of non-privileged users, and uses access checks to ensure that it does not use its root privileges to perform operations that should otherwise be unavailable the current user. The program uses the access()
system call to check if the person running the program has permission to access the specified file before it opens the file and performs the necessary operations.
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
behaves as expected, and returns 0
if the user running the program has the necessary permissions to write to the file, and -1 otherwise. However, because both access()
and fopen()
operate on filenames rather than on file handles, there is no guarantee that the file
variable still refers to the same file on disk when it is passed to fopen()
that it did when it was passed to access()
. If an attacker replaces file
after the call to access()
with a symbolic link to a different file, the program will use its root privileges to operate on the file even if it is a file that the attacker would otherwise be unable to modify. By tricking the program into performing an operation that would otherwise be impermissible, the attacker has gained elevated privileges. root
privileges. If the application is capable of performing any operation that the attacker would not otherwise be allowed perform, then it is a possible target.
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
is the same as the file created by the call to creat()
, but that is not necessarily the case. Because chown()
operates on a file name and not on a file handle, an attacker might be able to replace the file with a link to file the attacker does not own. The call to chown()
would then give the attacker ownership of the linked file.[1] Standards Mapping - Security Technical Implementation Guide Version 3 - (STIG 3) APP3630.1 CAT II
[2] J. Viega, G. McGraw Building Secure Software Addison-Wesley
[3] Standards Mapping - Common Weakness Enumeration - (CWE) CWE ID 362, CWE ID 367
[4] Standards Mapping - SANS Top 25 2009 - (SANS 2009) Insecure Interaction - CWE ID 362
[5] Standards Mapping - SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 362