Wednesday, September 7, 2011

Windows Security: Path Interpretation

I've come across this MSDN article, which talks about how Windows interprets paths:

Why is this a security concern?
Let's say you have an application that allows a user to write a file path as input, and to get the content of the file as output. You want to restrict access to a specific file, let's say:
c:\secret location\passwords.txt

This code is a possible way of writing such functionality:
string GetFile(string path)
	if (isok(path))
		return System.IO.File.ReadAllText(path);
		throw new Exception("Access denied");
Maybe the best option is limiting the permissions of the application so it can't access the file, but then what about a web server that needs to hide .htaccess from the user but must be able to read it?
So maybe you choose another option - examining the file path.
For example:

bool isok(string path)
	return path != @"c:\secret location\passwords.txt";
But then an attacker could use uppercase or mixed to represent the same file:
GetFile(@"C:\SeCrEt LoCaTiOn\PaSsWoRdS.TxT");
So maybe this might be a possible fix:
bool isok(string path)
	return path.ToLower() != @"c:\secret location\passwords.txt";
Unfortunately this code isn't sufficient either, what about:
GetFile(@"c:\aaaa\..\secret location\passwords.txt");
Note that it works even if aaaa doesn't exist.
This can go on and on. I tried to put some of those "path features" in the following list.

  1. Normal: @"c:\secret location\passwords.txt"
  2. Upper/lower case: @"C:\Secret Location\Passwords.TxT"
  3. Parent directory: @"c:\aaa\..\secret location\passwords.txt"
  4. Current directory: @"c:\.\secret location\passwords.txt"
  5. Current file: @"c:\secret location\passwords.txt\."
  6. Spaces: @"c:\secret location\passwords.txt   "
  7. Dots: @"c:\secret location\passwords.txt...."
  8. Network share: @"\\localhost\c$\secret location\passwords.txt"
    or <ip_address> or <computer_name> or
  9. Long path prefix: @"\\?\c:\secret location\passwords.txt"
  10. MS-DOS style: @"C:\SECRET~1\PASSWO~1.TXT"
  11. Relative path: @"c:secret location\passwords.txt"
    (Works if current directory is c:\, otherwise need to add ..)
  12. Win32 device: @"\\.\c:\secret location\passwords.txt"
  13. Long UNC: @"\\?\UNC\localhost\c$\secret location\passwords.txt"
  14. ADS: @"c:\secret location\passwords.txt::$DATA"
  15. Unix style: @"c:/secret location\passwords.txt"
Go on, try some of them!
There are probably many more ways that aren't on that list.
For conclusion, restricting access to a file simply by examining the input path is probably a bad idea. An alternative better solution should be chosen depending on the project requirements.