So I debated for a while what the first blog post would be. Ryan and I have a reputation for being in the weeds and having pretty high competence, and also for speaking up early when we don’t know the answer. In that second situation, it also almost always results in a deep dive to figure it out. I ended up in a deep dive on this particular topic a couple months back, but after a spirited discussion on technet today, I decided to resurrect this issue and use it as the feeder for my first blog post.
The Unquoted Service Path Vulnerability
So about 6 months ago, the good folks over at Common Exploits documented a flaw in the way the Windows API treats file paths when launching services. Essentially it goes like this:
I have a service installed at C:\Program Files\Cool Service\service.exe
When Windows goes to launch this path, it will examine the path and try to find executables at each white-space delimiter. Any of the following could launch (and they are attempted in this order):
C:\Program.exe (if doesn’t exist then next)
C:\Program Files\Cool.Exe (if doesn’t exist then next)
C:\Program Files\Cool Service\service.exe (The one we want)
Update: I have posted a series of scripts designed to help identify and remediate this issue. Script one builds a collection of objects for each path found on any number of computers. Script two examines those objects for bad paths and recommends fixed paths. Script three fixes the paths. Pipe them together for completed automated fix, use just the first two for reporting. Objects can be pipelined and manipulated using standard PowerShell cmdlets (sort, format, where, etc) All remote interaction is via REG.exe, so non-powershell machines can be remediated as well.
To be fair, this is not a new problem. It has been talked about for years and in more than one place. There’s also a fairly good discussion of the issue and when it does and doesn’t apply over at SuperUser. There’s also this undated document that is at least pre-2009 based on other activity at the site. There’s also a really excellent article about how this happens here.
Here’s the problem. People are busy arguing the problem doesn’t exist. (Also see my technet convo from earlier today linked up top)
If that’s true, why did Nessus release a plugin to look for this vulnerability based on the writeup from CommonExploits so recently? Why are vendors now releasing patches to fix their service calls?
NVidia Vulnerabilities March 21,2013
McAffee Vulnerability March 20, 2013
Tennable makers of Nessus March 4, 2013 demonstrated this problem
Common Weakness Enumeration says this goes back all the way to Windows 2000
NIST is talking about it too, and for Symantec of all things
Seems legit right?
So what is an administrator to do? All the people on technet scream up and down the halls this is bogus, and all these vendors are releasing patches. Do I or do I not have a problem?
Well, guess we need to test for ourselves.
Validating the Unquoted Service Path Vulnerability
Fortunately, I’ve come up with a fairly easy set of instructions for you to do just that. The first thing we need to do is “create an installation” that smells like a traditional installation. Some of the details here are fairly important. You’ll find plenty of examples online of people attempting to validate this with notepad, and when notepad doesn’t open they claim the problem doesn’t exist. The problem with that approach is notepad cannot run as a service, so you get an error. The fact you got anything other than the service that’s supposed to be running should be cause for concern, but most people don’t seem to be following through. No notepad = no problem right?
Wrong
So, first we create an installation path to hold our “service” executable. Create the path “C:\Program Files (x86)\Space Service Test\Program Call”
Next we need to find an executable that will actually launch as a service so we can validate it launches when we expect and under the context we expect (system for a lot of services). It turns out that the powershell binary powershell.exe will open as a service and idle, for a short time before giving us an error anyway, giving us a convenient point of reference. Make a copy of powershell.exe and dump it at “C:\Program Files (x86)\Space Service Test\Program Call\CPS1.exe”
Now we need to create a service that runs as system and calls this executable (strangely, the same as legitimate software vendors do for their services!). On an administrative command prompt, punch in the following:
sc create "Test Path" binPath= "C:\Program Files (x86)\Space Service Test\Program Call\CPS1.exe"
Okay great, we’re ready to make sure our service launches. Open up the task manager and select for all users. Also open up Services.msc and find the “Test Path” service. When you double click on it, you will see that its configured to launch as a service and has the path we specified with no quotes around it.
Click start and find it as CPS1 running under system privileges. Working as intended right? (Yes this does crash out after about 30 seconds because PowerShell doesn’t respond the way windows expects of a service executable. But it shows it ran under system)
Now make another copy of powershell.exe and dump it at “C:\Program Files (x86)\Space Service Test\Program.exe” Go back to the service console and start it. Look for program.exe in the task manager.
When we created that Program.exe and placed it where we did, Windows interpreted the path to the point that it ran C:\Program Files (x86)\Space Service Test\Program.exe instead of the service path we configured! So this vulnerability DOES EXIST
Awesome, how do I fix it
Turns out the fix is relatively easy. When a new service is created, windows writes its path down in the registry in a known location. It then reads subsequent service calls from this location. This read action is actually a parse of the path. Open up regedit and navigate to “HKLM\System\CurrentControlSet\Services\Test Path” and you’ll find a value named ImagePath that points to our CPS1.exe
If you look at some of the keys around it, you’ll find others with ImagePath values that have the path in quotes, others that do not. If the path contains a space and has quotes, it’s configured correctly. If it doesn’t have a space, no issue. If it has a space in the path and no quotes, it’s vulnerable.
If you edit the value to put quotes around the path, you can then see this reflected in the service console when you close and reopen your service properties.
And when you try to start the service, CPS1.exe starts instead of the rogue program.exe
Conclusions
At the end of the day, this vulnerability DOES exist. For those folks who continue to insist it doesn’t, Spoiler Alert: You’re Wrong. That said let’s examine this vulnerability for what it is.
A local or remote user (who has either obtained access or is allowed access) can exploit this vulnerability to escalate their privileges if they can find a vulnerable service. The end result is running code under the service’s assigned permissions. When this permission is SYSTEM, you’ve got a bad day.
If you’re following Microsoft’s best practices, your users cannot modify the program files directories (where most things install) or the root of C without admin rights.
That said, consider the following scenarios:
How many home users run as admin? How many run with UAC turned off?
How many enterprises have legacy software from XP that has to run as admin? Or is shimmed to allow admin for that program? (If it uses the common file dialogues, it can modify the file system, so a user can still get a program loaded in the right place)
The truth is, this vulnerability is real, and its simple to fix. So Fix It
The absolute answer would be for Microsoft to change the way these service calls are handled and force the paths to be quoted or not run at all, but that’s likely to break a lot of programs in the process. Microsoft already gets a lot of heat for breaking third party applications, so I’m not surprised to find Microsoft services quoted correctly and vendors working to catch up.
That said, this vulnerability has been around FOR YEARS. Why are vendors just now patching it? Probably because Nessus was good enough to start telling people about it. I hadn’t heard of this vulnerability until Nessus brought it to our attention. I suspect a lot of others are in the same boat. Unfortunately, the Nessus plugin doesn’t tell you how to fix it. Turns out its really simple. Plus, I do not have to wait for vendors to patch the program and remain vulnerable in the mean time. This is something I could do now. Even better, this is something I could script the resolution of. (And I will, in a couple days stay tuned!)
The down side is this, I fix this repeatedly. When I deploy a new system, I have to go in and fix this. When I install an update from the vendor that updates the service but hasn’t fixed this problem, I have to go back behind them and fix it again. When I install new software, I have to look for and fix this vulnerability. I have to search for this problem if I don’t have a tool already to do that (like Nessus).
Sounds like another good excuse to write a script.
See you next time!
-Jeff
(You remembered to go delete that vulnerable service we just created right?)