3

I'm writing a simple HTTP server in Lua and while I can easily find resources on how to secure against Unix directory traversal, I already found some caveats in the Windows version. While I'm already looking for C:\ at the beginning (C being "any letter" here), ../ and /.. (with backslash as the directory delimiter as well) and \\ at the beginning. The code will be passed to ANSI C fopen(), compiled under Microsoft Visual C++ v10 (no idea what's the system call this call compiles to). Are there any other traps I should look out for in this case?

I'm only interested in solutions involving the modification of my code, most preferably by checking the filename against patterns.

d33tah
  • 6,524
  • 8
  • 38
  • 60
  • I *really* hope this is just a project for the sake of learning. –  Sep 12 '13 at 13:27
  • It is. Here's the code: https://svn.nmap.org/nmap/ncat/scripts/httpd.lua – d33tah Sep 12 '13 at 13:27
  • Ah, you mean the HTTP server I wrote? More of a demo, with a big warning "don't use it on production". Yet I'd rather make it secure. Its main use scenario is simple file (or directory) sharing over a trusted network. – d33tah Sep 12 '13 at 13:28

1 Answers1

7

Paths in Windows are relatively complex. In particular, Microsoft has a habit of inventing new features, so even if your HTTP server is really protected against path traversal today, it may become vulnerable under next version of Windows, possibly even a small update.

Right now, your are using "blacklist-thinking": you are trying to enumerate all the "bad" constructions, and specifically detect them. Blacklists are known to be fragile because it is very hard to be exhaustive, and then to remain exhaustive. You should use whitelist-thinking, i.e. define a syntax for allowed paths and exclude everything else.

For instance, define that an allowed path consists in a sequence of components separated by slash characters ("/", not "\"), with the following rules:

  • A component contains only letters, digits, dashes ("-"), underscores ("_") or dots (".").
  • A dot may not appear as first or last character in a component.
  • There shall not be any two consecutive dots in a component.
  • A component contains at least one character, and at most 64 characters (arbitrary limit).
  • No two consecutive slashes may appear in a path.
  • A path does not begin with a slash.
  • A path is not empty.
  • The total length of a path shall not exceed 250 characters.

All these rules are easy to enforce programmatically. And they guarantee a "clean local path" that you can send to fopen(). Note that most Windows functions are perfectly happy with the "/" as separator, but you may still want to replace all slashes by backslashes (after checking all the rules above, of course).

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • Is 'component' just the word you are using for a directory? Because it is valid (but perhaps misguided) for a filename to be `test......txt`, for example, which would violate the two-dot rule. – Gray Sep 12 '13 at 13:56
  • 1
    Yes, I am using "component" as meaning "directory or file". The point is that, for a HTTP server, I don't actually need to support every possible path name; I just have to support paths which "make sense". I can declare that `test......txt` will not be allowed, even if the underlying Windows would have accepted it. (Similarly, IIS, the HTTP server from Microsoft, will reject file names which contain a "+", even though Windows itself has no problem whatsoever with such names -- and rejecting names with a "+" is very rarely an issue.) – Tom Leek Sep 12 '13 at 14:02
  • Thank you for the clarification. I can see your point now. – Gray Sep 12 '13 at 16:34