Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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 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 operating on a file determined by the attacker. This exploit is particularly dangerous when the vulnerable program is running with elevated privileges. However, on multiuser systems a user can be tricked by an attacker into unintentionally operating on their own files.

Mitigation strategies include use of:

...

Code Block
bgColor#FFcccc
class TempFile {
  public static void main(String[] args) {
    // POSIX file permissions for exclusive read/write
    Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
    FileAttribute att = PosixFilePermissions.asFileAttribute( perms);
    Path tempFile = null;
    try {
      tempFile = Files.createTempFile( "file", ".myapp", att);
      try (BufferedWriter writer = Files.newBufferedWriter(tempFile, Charset.forName("UTF8"),
                                                           StandardOpenOption.DELETE_ON_CLOSE)) {
          // write to file
      }
      System.out.println("Temporary file write done, file erased");
    } catch (FileAlreadyExistsException x) {
      System.err.println("File exists: " + tempFile);
    } catch (IOException x) {
      // Some other sort of failure, such as permissions.
      System.err.println("Error creating temporary file: " + x);
    }
  }
}

...

The file name passed to this function is first verified to be a directory, and rendered absolute if necessary. If the path contains any symbolic links, this routine will recursively invoke itself on the linked-to directory and ensure it is also secure. A symlinked directory may be secure if both its source and linked-to directory are secure. The function checks every directory in the path, ensuring that every directory is owned by the current user or the superuser and that all directories in the path forbid other users from deleting or renaming files.

POSIX maintains that a directory can prevent modifications to its files either by On POSIX systems, disabling group and other write access to a directory prevents modification by anyone other than the directory or by turning on the sticky bit. However, Java 1.7 provides no mechanism for accessing the sticky bit.owner of the directory and the system administrator.

Most home directories are secure by default on standard POSIX installations, and only shared directories such as /tmp are insecure. However, since because any user can create an insecure directory, a program should verify that a particular directory is actually secure, as it may not have the permissions required to create a secure directory.

...

Code Block
bgColor#ccccff
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;
}

...

Code Block
bgColor#ccccff
class TempFile {
  public static boolean isSecureDir(Path file) {
    // ...
  }

  public static void main(String[] args) {
    Path tempDir = new File(args[0]).toPath();
    if (!isSecureDir( tempDir)) {
      System.out.println("Temporary Directory not secure");
      return;
    }

    // POSIX file permissions for exclusive read/write
    Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
    FileAttribute att = PosixFilePermissions.asFileAttribute( perms);
    Path tempFile = null;
    try {
      tempFile = Files.createTempFile( tempDir, "file", ".myapp", att);
      try (BufferedWriter writer = Files.newBufferedWriter(tempFile, Charset.forName("UTF8"),
                                                           StandardOpenOption.DELETE_ON_CLOSE)) {
          // write to file
        }
      System.out.println("Temporary file write done, file erased");

    } catch (FileAlreadyExistsException x) {
      System.err.println("File exists: " + tempFile);
    } catch (IOException x) {
      // Some other sort of failure, such as permissions.
      System.err.println("Error creating temporary file: " + x);
    }
  }
}

...

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1d319d327c91043e-6fcf41a2-4c4149fd-b0f3a701-804628019c639c78ed37ba63"><ac:plain-text-body><![CDATA[

[[MITRE 2009API 2006

AA. Bibliography#MITRE 09Bibliography#API 06]]

[CWE ID 459

http://cwe.mitre.org/data/definitions/459.html] "Incomplete Cleanup"

]]></ac:plain-text-body></ac:structured-macro>

Bibliography

Class File, methods createTempFile, delete, deleteOnExit

]]

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2b966559-9f65-4764-83af-4d6d8a338de8"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

Class File, methods createTempFile, delete, deleteOnExit

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="154196f6e5bb19ce-ec6278f0-413347f2-acdf8b7b-a7160ee08d70f5b0c6c52430"><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="ef58af1f969948f4-79435524-41bf4e7d-ab77af7b-6ba541ee7a72fe1b71b881ae"><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="2d50a37567149b72-2dcc2aa6-4fe847e4-a90c9d76-7a7bf706099d80ab1b7cfc4a"><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="69dcbc6ab7384dbd-b423932b-42304dae-8ea0811a-0244f02970de478a30ad1120"><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="dddae1b4bc401652-b28db570-460446ab-a49a83a7-cbfbca4a3973bc73997cb9f0"><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>

...