The Sin Explained

As we mentioned, there are three distinct errors. The core of the first issue, a race condition, is that on most modern operating systems (Windows, Linux, Unix, Mac OS X, and others), applications do not operate in an isolated manner, even though it may seem they do. Other processes can interrupt a running application at anytime , and an application may not be prepared for such an event to occur. In other words, some file operation may appear to be atomic, but they are not. Such conditions could lead to privilege escalation or denial of service through crashes and deadlocks.

The classic scenario is checking if a file exists or not, and then accessing the file as if the file does or does not exist. Take a look at the sinful code samples for more of an explanation.

The next sin variation is taking the name of a file and opening the file without regard for the nature of the file. On operating systems like Linux, Unix, and Mac OS X, this kind of vulnerability is commonly seen through the misuse of symbolic links. The program opens a file, thinking its a file, but in fact its a symlink placed there by the attacker. This could be a serious issue if the process is running as root, because a root process can delete all files.

The final scenario is letting attackers have some control over what files a program accesses . If theres sensitive information that the application can see (such as other users data, or the system password database), we generally dont want attackers to see it. One common attempt to thwart this problem is to hardcode a path prefix to any filename taken from an untrusted source, such as /var/myapp/ on a Unix machine. However, if the API call will resolve relative paths, attackers might specify their part of the file as, for example, ../../etc/passwd, which can be bad if the application has read access to system files, and very bad if it has write access. This methodology is often called a directory traversal attack.

Sinful C/C++ on Windows

In this code, the developer anticipated only valid filenames would come from the normal user population, but he had not factored in the abnormal population. This is not good if the code is in server code, because if attackers provide a device name (such as a printer port, lpt1), the server will stop responding until the device times out.

 void AccessFile(char *szFileNameFromUser) {  HANDLE hFile =   CreateFile(szFileNameFromUser,  0,0,  NULL,  OPEN_EXISTING,  0,  NULL);  ... 

Sinful C/C++

The following code is the poster child for the file-access race condition defect. In between the call to access(2) and open (2), the operating system could switch away from your running process and give another process a time slice. In the intervening time, the file /tmp/ splat could be deleted, and then the application crashes.

 #include "sys/types.h" #include "sys/stat.h" #include "unistd.h" #include "fcntl.h" const char *filename = "/tmp/splat"; if (access(filename, R_OK) == 0){  int fd=open(filename, O_RDONLY);  handle_file_contents(fd);  close(fd); } else {  // handle error } 

Sinful Perl

Again, this code is accessing the file using a filename. The code determines if the file is readable by the effective user of the Perl script and if it is, reads it. This sinful code is similar to the C/C++ code: between the file check and read the file may have disappeared.

 #!/usr/bin/perl my $file = "$ENV{HOME}/.config"; read_config($file) if r $file; 

Sinful Python

Heres a non-obvious error:

 import os def safe_open_file(fname, base="/var/myapp"):  # Remove '..' and '.'  fname = fname.replace('../', '')  fname = fname.replace('./', '')  return open(os.path.join(base, fname)) 

The code attempts to strip out attempts at directory traversal attacks. However, there are two problems. First, stripping out invalid characters seems like the wrong strategy here. Any time a double dot is seen, why not fail, since it isnt valid?

Second, the replace method doesnt do exactly what the programmer of the previous code thought it did. For example, what if the attacker used the string ..././//? Heres what will happen:

  • The first replace() will make two replacements in its single pass, resulting in "//"

  • The second replace() will make a single replacement, resulting in "../"

Whoops!!

Related Sins

This sin is linked at the hip through race conditions to Sin 16, but theres more to file access than simply race conditions. You should read Sin 16 as soon as you have read about this sin.



19 Deadly Sins of Software Security. Programming Flaws and How to Fix Them
Writing Secure Code
ISBN: 71626751
EAN: 2147483647
Year: 2003
Pages: 239

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net