...
Temporary files are commonly used for auxiliary storage for data that does not need to, or otherwise cannot, reside in memory and also as a means of communicating with other processes by transferring data through the file system. For example, one process will create a temporary file in a shared directory with a well-known name , or a temporary name that is communicated to collaborating processes. The file then can be used to share information among these collaborating processes.
This is a dangerous practice because a well-known file in a shared directory can be easily hijacked or manipulated by an attacker. Mitigation strategies include the following:
- Use other low-level IPC mechanisms (interprocess communication) mechanisms such as sockets or shared memory.
- Use higher level IPC mechanisms such as remote procedure calls.
- Use a secure directory or a jail that can only be accessed by application instances (making sure that multiple instances of the application running on the same platform do not compete).
There are many different interprocess communication mechanisms (IPC)different IPC mechanisms, some of which require the use of temporary files, while and others of which do not. An example of an IPC mechanism that uses temporary files is the POSIX mmap()
function. Berkeley Sockets, POSIX Local IPC Sockets, and System V Shared Memory do not require temporary files. Because the multiuser nature of shared directories poses an inherent security risk, the use of shared temporary files for IPC is discouraged.
When two or more users , or a group of users , have write permission to a directory, the potential for deception is far greater than it is for shared access to a few files. Consequently, temporary files in shared directories must be
...
The following table lists common temporary file functions and their respective conformance to these criteria:
Conformance of
...
File Functions to
...
Criteria for
...
Temporary Files
|
|
|
|
|
|
|
---|---|---|---|---|---|---|
Unpredictable Name | Not not portably | Yes yes | Not not portably | Yes yes | Not not portably Not | not portably |
Unique Name | Yes yes Yes | yes | Yes yes Yes | yes | Yes yes Yes | yes |
Atomic | No no No | no | Yes yes Yes | yes | No no | Yes yes |
Exclusive Access | Possible possible Possible | possible | No no | If if supported by OS | Possible possible | If if supported by OS |
Appropriate Permissions | Possible possible Possible | possible | No no | If if supported by OS | Possible possible | Not not portably |
File Removed | No no No | no | Yesyes* Yes | yes* | No no No | no |
* If the program terminates abnormally, this behavior is implementation-defined.
...
Exclusive access grants unrestricted file access to the locking process while denying access to all other processes and eliminates the potential for a race condition on the locked region. (See the locked region. (See Secure Coding in C and C++, Chapter 7 [Seacord 2005a] Chapter 7.)
Files, or regions of files, can be locked to prevent two processes from concurrent access. Windows supports two types of file locks:
- shared Shared locks, provided by
LockFile()
, prohibit all write access to the locked file region while allowing concurrent read access to all processes. - exclusive Exclusive locks, provided by
LockFileEx()
, grant unrestricted file access to the locking process while denying access to all other processes.
...
- Mandatory locking works only on local file systems and does not extend to network file systems (such as NFS or AFS).
- File systems must be mounted with support for mandatory locking, and this is disabled by default.
- Locking relies on the group ID bit that can be turned off by another process (thereby defeating the lock).
Removal
...
before Termination
Removing temporary files when they are no longer required allows file names and other resources (such as secondary storage) to be recycled. In the case of abnormal termination, there is no sure method that can guarantee the removal of orphaned files. For this reason, temporary file cleaner utilities, which are invoked manually by a system administrator or periodically run by a daemon to sweep temporary directories and remove old files, are widely used. However, these utilities are themselves vulnerable to file-based exploits and often require the use of shared directories. During normal operation, it is the responsibility of the program to ensure that temporary files are removed either explicitly or through the use of library routines, such as tmpfile_s
, which guarantee temporary file deletion upon program termination.
...
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[] = /* hard coded string */;
FILE *fp = fopen(file_name, "wb+");
if (fp == NULL) {
/* Handle error */
}
|
...
The following noncompliant code example attempts to remedy the problem by generating the file name at runtime using tmpnam()
. The C99 C tmpnam()
function generates a string that is a valid file name , and that is not the same as the name of an existing file [ISO/IEC 9899:19992011]. Files created using strings generated by the tmpnam()
function are temporary in that their names should not collide with those generated by conventional naming rules for the implementation. The function is potentially capable of generating TMP_MAX
different strings, but any or all of them may already be in use by existing files.
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[L_tmpnam];
FILE* fp;
if (!tmpnam(file_name)) {
/* Handle error */
}
/* A TOCTOU race condition exists here */
fp = fopen(file_name, "wb+");
if (fp == NULL) {
/* Handle error */
}
|
Because tmpnam()
does not guarantee a unique name and fopen()
does not provide a facility for an exclusive open, this code is still vulnerable.
This The next noncompliant code example attempts to remedy the problem by using the POSIX open()
function and providing a mechanism to indicate whether an existing file has been opened for writing or a new file has been created [Open Group 2004]. If the O_CREAT
and O_EXCL
flags are used together, the open()
function fails when the file specified by file_name
already exists. To prevent an existing file from being opened and truncated, include the flags O_CREAT
and O_EXCL
when calling open()
.
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[L_tmpnam];
int fd;
if (!(tmpnam(file_name))) {
/* Handle error */
}
/* A TOCTOU race condition exists here */
fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);
if (fd < 0) {
/* Handle error */
}
|
...
Moreover, the open()
function, as specified by the Open Group Base Specifications Issue 6 [Open Group 2004], does not include support for shared or exclusive locks. However, BSD systems support two additional flags that allow you to obtain these locks:
O_SHLOCK
: Atomically obtain a shared lock.O_EXLOCK
: Atomically obtain an exclusive lock.
...
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[L_tmpnam_s];
int fd;
if (tmpnam_s(file_name, L_tmpnam_s) != 0) {
/* Handle error */
}
/* A TOCTOU race condition exists here */
fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);
if (fd < 0) {
/* Handle error */
}
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[] = "tmp-XXXXXX";
int fd;
if (!mktemp(file_name)) {
/* Handle error */
}
/* A TOCTOU race condition exists here */
fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);
if (fd < 0) {
/* Handle error */
}
|
The mktemp()
function has been marked "LEGACY" in the Open Group Base Specifications Issue 6 [Open Group 2004]. The manual page for mktemp()
gives more detail:
...
Noncompliant Code Example (tmpfile()
)
The C99 C tmpfile()
function creates a temporary binary file that is different from any other existing file and that is automatically removed when it is closed or at program termination.
It should be possible to open at least TMP_MAX
temporary files during the lifetime of the program. (This limit may be shared with tmpnam()
.) C99, Section 7.1921.4.4 , of the C standard [ISO/IEC 9899:2011] allows for the value of the macro TMP_MAX
to be as small as 25 [ISO/IEC 9899:1999].
Most historic implementations provide only a limited number of possible temporary file names (usually 26) before file names are recycled.
Code Block | ||||
---|---|---|---|---|
| ||||
FILE* fp = tmpfile();
if (fp == NULL) {
/* Handle error */
}
|
...
The ISO/IEC TR 24731-1 function tmpfile_s()
creates a temporary binary file that is different from any other existing file , and that is automatically removed when it is closed or at program termination. If the program terminates abnormally, whether an open temporary file is removed is implementation-defined.
...
Code Block | ||||
---|---|---|---|---|
| ||||
if (tmpfile_s(&fp)) {
/* Handle error */
}
|
...
The mkstemp()
algorithm for selecting file names has shown to be immune to attacks. The mkstemp()
function is available on systems that support the Open Group Base Specifications Issue 4, Version version 2 or later.
A call to mkstemp()
replaces the six X
's in the template string with six randomly selected characters and returns a file descriptor for the file (opened for reading and writing), as in this compliant solution.
Code Block | ||||
---|---|---|---|---|
| ||||
const char *sdn = "/home/usr1/";
char sfn[] = "/home/usr1/temp-XXXXXX";
FILE *sfp;
if (!secure_dir(sdn)) {
/* Handle error */
}
int fd = mkstemp(sfn);
if (fd == -1) {
/* Handle error */
}
/*
* Unlink immediately to hide the file name.
* The race condition here is inconsequential if the file
* is created with exclusive permissions (glibc >= 2.0.7)
*/
if (unlink(sfn) == -1) {
/* Handle error */
}
sfp = fdopen(fd, "w+");
if (sfp == NULL) {
close(fd);
/* Handle error */
}
/* Use temporary file */
fclose(sfp); /* also closes fd */
|
This solution is not serially reusable; , however, because the mkstemp()
function replaces the "XXXXXX"
in template
the first time it is invoked. This is not a problem as long as template
is reinitialized before calling mkstemp()
again. If template
is not reinitialized, the mkstemp()
function will return -1
and leave template
unmodified because template
did not contain six X
's.
...
This compliant solution invokes the user-defined function secure_dir()
} (such as the one defined in recommendation FIO15-C. Ensure that file operations are performed in a secure directory) to ensure the temporary file resides in a secure directory.
Implementation Details
For GLIBC, Versions versions 2.0.6 and earlier, the file is created with permissions 0666; for GLIBC, Versions versions 2.0.7 and later, the file is created with permissions 0600. On NetBSD, the file is created with permissions 0600. This creates a security risk in that an attacker will have write access to the file immediately after creation. Consequently, programs need a private version of the mkstemp()
function in which this issue is known to be fixed.
In many older implementations, the name is a function of process ID and time, so it is possible for the attacker to predict the name and create a decoy in advance. FreeBSD changed the mk*temp()
family to eliminate the PID component of the file name and replace the entire field with base-62 encoded randomness. This raises the number of possible temporary files for the typical use of six X
's significantly, meaning that even mktemp()
with six X
's is reasonably (probabilistically) secure against guessing , except under frequent usage [Kennaway 2000].
...
The
unlink()
function doesn't follow symlinks , and doesn't really have much of an affect on hard links. So, I guess your options for attacking something like that would be:
*SIGSTOP
orSIGTSTP
it before the unlink, maybe unlink it yourself and wait (a while) until something created something with the same name, or try to use that name somehow. Probably not that useful, but maybe in a specific attack it could work with a lot of effort.
*You could sorta do a symlink attack with an intermediate path component, for example, if it was/tmp/tmp2/ed.XXXXXX
, you couldrm tmp2
and then symlink it to/etc
or something. It would thenrm /etc/ed.XXXXXX
, but that probably wouldn't buy you much.John McDonald
...
Tool | Version | Checker | Description | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Section | Compass/ROSE |
|
| Section | Can detect violations of this recommendation. Specifically, Rose reports use of | ||||||
Section | |
| Section | 489 S section | Partially Implementedimplemented. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
The CERT Oracle Secure Coding Standard for Java: FIO03-J. Remove temporary files before termination
ISO/IEC 9899:1999 Section 2011 Section 7.1921.4.4, "The tmpnam
function," 7.1921.4.3, "The tmpfile
function," and Section 7.1921.5.3, "The fopen
function"
ISO/IEC PDTR 24772 "EWR Path Traversaltraversal"
ISO/IEC TR 24731-1:2007 Section 6.5.1.2, "The tmpnam_s
function," Section 6.5.1.1, "The tmpfile_s
function," and Section 6.5.2.1, "The fopen_s
function"
MITRE CWE: CWE ID 379, "Creation of Temporary File temporary file in Directory directory with Insecure Permissionsinsecure permissions"
Bibliography
[Austin Group 2008]
[HP 2003]
[Kennaway 2000]
[Open Group 2004] mktemp()
, mkstemp()
, open()
[Seacord 2005a] Chapter 3, "Pointer Subterfuge," and Chapter 7, "File I/O", Chapter 7
[Viega 2003] Section 2.1, "Creating Files files for Temporary Usetemporary use"
[Wheeler 2003] Chapter 7, "Structure Program Internals and Approach"
...