A security vulnerability report came in that claimed that Windows had a remote code execution vulnerability because it allows malicious characters in file names.
Specifically, they noted that if you created a Web server with an image upload page, and if an uploaded file contained a special character like an ampersand, then you could obtain remote code execution.
They included a complicated server-side script, but here’s the gist:
void OnFileUploaded(string path)
{
system("dosomething.exe " + path);
}
A user could upload files with odd names like
x & logoff &.jpg x & certutil -installcert -f badcert.jpg x & sc stop server &.jpg
The resulting commands passed to the system function are
dosomething.exe x & logoff &.jpg dosomething.exe x & certutil -installcert -f badcert.jpg dosomething.exe x & sc stop server &.jpg
The ampersand is a CMD.EXE metacharacter for combining multiple commands into a single line, so each of the above lines is treated as multiple commands. The first is dosomething.exe x, which presumably fails because there is no file named x. The second is something dangerous. And sometimes there’s a third command .jpg which is probably going to fail with '.jpg' is not recognized as an internal or external command, operable program or batch file.
The finders claimed that this proves that ampersands in file names are a remote code execution vulnerability in Windows.
What we have here is a case of creating an insecure system and then being surprised that the system is insecure. The OnÂFileÂUploaded function passes untrusted data directly to the system function without any attempt to sanitize it first. This is a classic injection attack (obXKCD), and it is the responsibility of code that builds commands out of strings to be alert to issues like this.
You’d be best advised to avoid things that do their own level of nontrivial parsing over the generated command line. SQL commands and command lines are examples of this. In the above example, it would be better to run the dosomething.exe program directly and pass the file name (suitably quoted), to avoid any funny business with CMD.EXE command line parsing.¹
When we informed the finders that there was no Windows vulnerability here, they insisted that the issue they found is a critical remote code execution vulnerability, shared a paper they planned on presenting, and warned that publication could likely result in widespread attacks within hours of disclosure, resulting in compromised Windows systems around the globe.
I reviewed the paper and verified that it didn’t do anything beyond what they had described in their original report. We advised them that the vulnerability was in their Web server, not in Windows, and gave them permission to disclose.
As far as I can tell, they never did publish that paper anywhere.
Bonus chatter: They claimed that the issue could be fixed by simply adding the ampersand to the list of illegal file name characters. They forgot about the percent sign (for injecting environment variables), the caret (for escaping), and possibly even the apostrophe. They may also want to file vulnerabilty reports against unix since it is vulnerable to the exact same problem: If somebody takes an untrusted file name and injects into into a command passed to the system function, bad things can happen. It’s even worse on unix, because unix has almost no forbidden file name characters. Even a newline is a legal filename character! So go ahead, put a bitcoin miner in your file name, let the server do some real work for you.
¹ If you don’t trust yourself to quote potentially-malicious file names safely (and I don’t blame you), you could pass the file name some other way entirely, like via stdin or by putting the dangerous file name in a file, and passing that file as an indirect parameter: something.exe @indirect.
This is a classic injection attack (obXKCD), and it is the responsibility of code that builds commands out of strings to be alert to issues like this.
Amen!
What we have here is a case of creating an insecure system and then being surprised that the system is insecure.
JFTR: I’m not surprised, I know who I’m talking to!
It reminds me of the hysteria a few years ago, when everyone was convinced that Chrome was storing passwords in plaintext, because you could go into the password manager and view the saved password.
They can see the plaintext password with their eyes, so their mental model can only conclude that the passwords themselves must be stored in plaintext. No amount of explaining Cryptography, showing them the source code, showing them the CryptProtectData function documentation, dumping the internal sqlite database showing that the password is indeed encrypted.
They've had something they've seen with their eyes, and their mental model is now...
I can see where it’s going, as there are lots of people passing the uploaded images to imagemagick for resizing because they don’t bother to write their own, and I’ve seen some of the imagemagick wrappers do what is described above. (The similar thing goes to ghostscript and some other situation that uses command line utility to process file without sanitizing the input)
So this is possibly a real world problem, and yes, the problem is in the code of website, or possibly on a library they choose to use, but not on the operating system itself.