...
Programmers frequently create temporary files in directories that are writable by everyone; examples include /tmp
and /var/tmp
on UNIX and C:\TEMP
on Windows. Files in such directories may be purged regularly, for example, every night or during reboot. However, an adversary attacker who has access to the local file system can misuse files held in world-writable directories when those files are created insecurely or remain accessible after use. For instance, an attacker who can both predict the name of a temporary file and can change or replace that file, can exploit a time-of-check time-of-use (TOCTOU) condition to cause either a failure in creating the temporary file from within program code or reading of file whose contents are operating on a file determined by the attacker.
...
Shared access to a directory entails greater vulnerability is riskier than does shared access to a limited number of files. Consequently, temporary files in shared directories must be
...
Secure creation of temporary files is error prone and relies on platform dependent behavior; the Operating System, and the file system are the determining factors. Code that works for a locally mounted file system, for example, may be vulnerable when used with a remotely mounted file system. Moreover, most relevant APIs are problematic. The only secure comprehensive solution is to refrain from creating temporary files in shared directories.
Unique and Unpredictable
...
File Names
Wiki Markup |
---|
A recently identified bug in JRE and JDK version 6.0 and earlier permits an attacker who can predict the names of temporary files to write malicious JAR files via unknown vectors \[[CVE 2008|AA. Bibliography#CVE 08]\]. Failure to reclaim temporary resources can cause rapid disk space exhaustion duebecause toof unreclaimed files \[[Secunia Advisory 20132|http://secunia.com/advisories/20132/]\]. |
...
Removing temporary files when they are no longer required allows file names and other resources (such as secondary storage) to be recycled. Each program is responsible for ensuring that temporary files are removed during normal operation. There is no surefire method that can guarantee the removal of orphaned files in the case of abnormal termination, even in the presence of a finally
block, because the finally
block may fail to execute. For this reason, many systems employ temporary file cleaner utilities to sweep temporary directories and remove old files. Such utilities can be invoked manually by a system administrator or can be periodically invoked by a system daemon. However, these utilities are themselves vulnerable to file-based exploits and often require the use of shared directories.
Noncompliant Code Example (
...
Predictable File Names)
This noncompliant code example hardcodes the name of a temporary file; consequently, the file's name is predictable. Even though there is a built-in check to detect whether a file still exists after its creation, this check creates a TOCTOU race condition that an attacker can exploit, by altering or deleting the file between the check and the read.
...
Deletion will be attempted only for normal termination of the virtual machine, as defined by the Java Language Specification. Once deletion has been requested, it is not possible to cancel the request. This method should consequently be used with care.
Note: this method should not be used for file-locking, as the resulting protocol cannot be made to work reliably.
Wiki Markup |
---|
ThusConsequently, the file is not deleted if the JVM terminates unexpectedly. A longstanding bug on Windows based systems --- \[[reported as [Bug ID: 4171239|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4171239] \[[SDN 2008|AA. Bibliography#SDN 08]\] --- causes JVMs to fail to delete a file when {{deleteOnExit()}} is invoked before the associated stream or {{RandomAccessFile}} is closed. |
Code Block | ||
---|---|---|
| ||
class TempFile {
public static void main(String[] args) throws IOException{
File f = File.createTempFile("tempnam",".tmp");
FileOutputStream fop = new FileOutputStream(f);
String str = "Data";
try {
fop.write(str.getBytes());
fop.flush();
} finally {
// Stream/file still open; file will
// not be deleted on Windows systems
f.deleteOnExit(); // Delete the file when the JVM terminates
}
}
}
|
...
Wiki Markup |
---|
To work around the file/stream termination issue, always attempt to terminate the resource normally before invoking {{deleteOnExit()}}. Using {{File.io.delete()}} to immediately delete the file is good practice, when possible; this avoids improper JVM termination related issues. Moreover, although unreliable, {{System.gc()}} may be invoked to free up related resources. Sometimes, the resources to be deleted cannot be closed first; see, for example, \[[Bug ID: 4635827|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4635827] \[[SDN 2008|AA. Bibliography#SDN 08]\]. There is no known workaround for this case. |
...
Because of the potential for race conditions, and the inherent accessability of a temporary fileshared directories, temporary files must only be created in secure directories. This compliant solution depends on an isSecureDir()
method. This method ensures that file and all directories above it are owned by either the user or the superuser, that each directory does not have write access for any other users, and that directories above path may not be deleted or renamed by any other users. When checking directories, it is important to traverse from the root to the leaf to avoid a dangerous race condition whereby an attacker who has privileges to at least one of the directories can rename and recreate a directory after the privilege verification.
...
Code Block | ||
---|---|---|
| ||
public static boolean isSecureDir(Path file) { if (!Files.isDirectory( file)) { return false; } if (!file.isAbsolute()) { file = file.toAbsolutePath(); } // If any parent dirs (from root on down) are not secure, dir is not secure for (int i = 1; i <= file.getNameCount(); i++) { Path partialPath = Paths.get(file.getRoot().toString(), file.subpath( 0, i).toString()); try { if (Files.isSymbolicLink( partialPath)) { if (!isSecureDir( Files.readSymbolicLink(partialPath))) { // Symbolic link, linked-to dir not secure return false; } } else { FileSystem fileSystem = partialPath.getFileSystem(); UserPrincipalLookupService upls = fileSystem.getUserPrincipalLookupService(); UserPrincipal root = upls.lookupPrincipalByName("root"); UserPrincipal user = upls.lookupPrincipalByName(System.getProperty("user.name")); UserPrincipal owner = Files.getOwner(partialPath); if (!owner.equals(user) && !owner.equals(root)) { // dir owned by someone else, not secure return false; } PosixFileAttributes attr = Files.readAttributes( partialPath, PosixFileAttributes.class); Set<PosixFilePermission> perms = attr.permissions(); if (perms.contains( PosixFilePermission.GROUP_WRITE) || perms.contains( PosixFilePermission.OTHERS_WRITE)) { // someone else can write files, not secure return false; } } } catch (IOException x) { return false; } } return true; } |
...
FIO43-C. Do not create temporary files in shared directories | |||||
FIO43-CPP. Do not create temporary files in shared directories | |||||
| CWE ID 377 "Insecure Temporary File" | ||||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="01bf03203bcb4c90-cad9382a-496f47bd-8b4e9387-7a5a87107cfce6898ef728b4"><ac:plain-text-body><![CDATA[ | [[MITRE 2009 | AA. Bibliography#MITRE 09]] | [CWE ID 459 | http://cwe.mitre.org/data/definitions/459.html] "Incomplete Cleanup" | ]]></ac:plain-text-body></ac:structured-macro> |
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="f9317297fffe5002-50f2c060-462e4b1b-9d129877-f128f6b2f2fc322f87edffd6"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] | Class File, methods | ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="6c6c5712efdfccd0-010c7c5e-41604b39-99f286cd-28d8bcf028a0b2bf3525b678"><ac:plain-text-body><![CDATA[ | [[CVE 2008 | AA. Bibliography#CVE 08]] | [CVE-2008-5354 | http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5354] | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="86cd66cef8a4355b-fff61c8c-43c24218-8fea9b4a-df62566eb7fe190d846b8fc5"><ac:plain-text-body><![CDATA[ | [[Darwin 2004 | AA. Bibliography#Darwin 04]] | 11.5 Creating a Transient File | ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="df7e5a7fe5eff566-f4835fef-486249f6-8ad49e7b-d83797f906e6ba9b363158bc"><ac:plain-text-body><![CDATA[ | [[J2SE 2011 | AA. Bibliography#J2SE 11]] |
| ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="c23c333ded7ecde9-121d94ea-46f04cbb-9b33af8a-d80bb243bb7ed31d4130c04e"><ac:plain-text-body><![CDATA[ | [[SDN 2008 | AA. Bibliography#SDN 08]] | Bug IDs: 4171239, 4405521, 4635827, 4631820 | ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4ceaff81363b406d-dabb31f7-4a2d4013-b51593e2-f5e100f58ea056c254fb1a89"><ac:plain-text-body><![CDATA[ | [[Secunia 2008 | AA. Bibliography#Secunia 08]] | [Secunia Advisory 20132 | http://secunia.com/advisories/20132/] | ]]></ac:plain-text-body></ac:structured-macro> |
...