Blog: Vulnerabilities that aren't

Vulnerabilities that aren’t. Unquoted Spaces

David Lodge 14 Feb 2022

I’ve covered a couple of web vulnerabilities that (mostly) aren’t, and now it’s time for a Windows specific one. A common finding from build reviews and CIS comparisons: unquoted spaces in service or run paths.

What is it?

Windows has always been inconsistent in how its API handles uncommon characters in paths. Unlike *ix it doesn’t use a shell to properly handle expansions before being passed to the program. This can be demonstrated by how spaces in paths are handled.

When long file names were allowed by Windows, handling spaces in paths was decided to follow a flexible model rather than a consistent one. Spaces are allowed in path or filenames when they make (some form) of sense, and aren’t when they don’t. This can be overridden if the path starts with a quote (“); it doesn’t have to end with one, which fails to make sense in any meaningful way.

To demonstrate how confusing this is:

It gets much more interesting when spawning a process using the CreateProcess family of function calls, as referenced in their documentation and explained below.

Why could this be a vulnerability?

CreateProcess takes a number of parameters, the first of which is referred to as lpApplicationName. This should contain the name of the module to be executed. Herein lieth the problem – Windows tries to be nice and will accept a number of values.

If a short name (such as runstuff.exe) is given it will use the %PATH variable to search, if an absolute name is used it will use that. If it is a NULL then it will use the string in the second parameter, lpCommandLine.

lpCommandLine contains the full command line to be called, including all arguments. In this case it will assume a space to be end of the command and the start of the parameters, unless a long pathname with a space is used, in that case it will try to match each space as a command first, unless a quote is used. So, as an example, we could have lpCommandLine as:

jim – it will run jim.exe

jim fred – it will try to run:

  • exe with a parameter of fred
  • if jim.exe doesn’t exist it will try to run “jim fred.exe”

c:\jim fred\shelia arabella bob – it will try to run the following:

  • c:\jim.exe with parameters of fred\shelia, arabella, bob
  • c:\jim fred\shelia.exe with parameters of arabella, bob
  • c:\jim fred\shelia arabella.exe with a parameter of bob
  • c:\jim fred\shelia arabella bob.exe with no parameters

So? What’s the problem; well, most Windows services and start up programs live in the directory “C:\Program Files\Company Name\Product Name”, so let’s say that we have a start up program set up which doesn’t bother using quotes, like this example, taken from HKLM\software\microsoft\windows\currentversion\run on my laptop:

So, every time I start up, Windows will attempt to run

C:\Program.exe Files\OpenVPN\bin\openvpn-gui.exe

Which will fail, then it will try and run:

C:\Program Files\OpenVPN\bin\openvpn-gui.exe

So what happens if a file exists called c:\program.exe exists? It will be called every time Windows boots and, well, shall we say “escalation vector”?

Why is this not a vulnerability?

This is one of them vulnerabilities that sounds good on paper, but less so in the real world. It’s closer to say that it could be a vulnerability but is really unlikely to ever be one.

The last paragraph in my explanation about says it all – to exploit it, I need to put an executable file in the root of the C drive. Quite frankly if I can do that I don’t really need to escalate my privileges by abusing badly formatted paths.

Let’s look at the default permissions for c:\ for Windows 10:

Breaking that down, for a normal non-admin user then they will have the following permissions:

  • (AD) – append data or creating subdirectories
  • (M) – modify existing files or subdirectories
  • (RX) – read and execute access to files or subdirectories

So, by default there are no permissions for a user to create a file (in this case c:\program.exe) that could be used to exploit the vulnerability.

At this point I should note that this covers most real world identified variants of this vulnerability. It is still possible to find a case where this is exploitable and therefore this should always be checked (either manually or automatically) to see whether it is exploitable.

Historical exploits

There are a lot of examples of this documented in the CVE records, far too many to easily document. The earliest I can find is CVE-2000-1128, posted on ntbugtraq back in November 2000, with a BID of 1920.

There is even a CWE for this; CWE-428.

Spending a while reading through the CVE reports – most of them have no real-world exploits, as most of them would need write access to c:\ or c:\program files.

There are 261 entries on exploit-db, all of the ones I looked at are just describing the finding, not providing a valid exploit.

Reports from tools

Nessus returns this if it finds a service which isn’t quoted and has a space anywhere in the path:

The remote Windows host has at least one service installed that uses an unquoted service path, which contains at least one whitespace. A local attacker can gain elevated privileges by inserting an executable file in the path of the affected service.

Although it has the capability to check file permissions it doesn’t, so this will produce lots of false positives in a real-world situation. It will only check services and not other methods of starting up binaries.

It provides a totally unrealistic score of 7.0.


Here we have a vulnerability that could allow an escalation path, but in virtually all situations will never provide a situation where it can be exploited. If this is discovered further action should take place to ensure that it can actually be exploited. The resultant score in the report should be based on the real-world risk – not a generic, badly scored one directly taken from an automatic tool.

Unlike some of the other situations, this one is easy to fix with the resolution having virtually no impact to the service. But this resolution should not redirect effort from fixing findings presenting a greater risk to the system.