Research and Development

By default, Windows systems will allow low privileged users to create directories (but not files) in the root of the `C:’ drive. In this post we ask if that’s really a security problem and ultimately conclude that, yes sometimes it can be.

Default permissions

Depending on the version of Windows, various low privileged users are allowed to create directories in `C:\’. On Windows 7, for example, “Authenticated Users” are:

"Authenticated Users" can create directories under `c:\'
image-1251

“Authenticated Users” can create directories under `c:\’

Or if you prefer the output of `cacls’, you can see this as the special permission `FILE_APPEND_DATA’:

`cacls' showing `FILE_APPEND_DATA'

`cacls’ showing `FILE_APPEND_DATA’

On Windows 2003, you see something similar, but for the `Users’ group:

`cacls' showing `FILE_APPEND_DATA' on Windows 2003

`cacls’ showing `FILE_APPEND_DATA’ on Windows 2003

(Don’t let the `FILE_WRITE_DATA’ confuse you – that’s an “Inherit Only” permission).

Potential security problems

If we apply the principle of least privilege here, we’d probably conclude that normal users don’t really need to create directories in the root of the `C:’ drive, so should not be allowed permissions to do so.

But, in terms of specific security concerns, what’s the worst that could happen?

  • Malicious users could stash their hacking tools or data they’ve stolen in a place other than their home directory. `C:\backup’ probably wouldn’t raise suspicions. This is certainly possible, but perhaps not the most compelling security concern
  • What if the malicious user knew an automated installer would eventually install an application into `C:\foo’? Would the installer just fail?  Or would it succeed, but leave the malicious user as the owner of the software directory? That’s not the subject of this post, but it sounds like a more concrete concern – but depends on predicting that a specific application will be installed
  • What if an application on the system searched for its support files in non-existent locations that the malicious user could create, e.g. `C:\my-dev-dlls’?  This is the possibility that I want to explore in this post

Identifying programs accessing non-existent files

I used procmon to show me all the processes where file access resulted in a “NOT FOUND” error. The green ticks show the simple filter I used:

Process Monitor filter

Process Monitor filter

I opened up a few different programs to observe the various failed file access attempts and saw this one for `C:\lib’:

`c:\lib' not found

`c:\lib’ not found

(I’ve blacked out the name of the process – partly because it’s not relevant, and partly because I haven’t mentioned this to the vendor yet).

So a malicious user on the system could create `C:\lib’. Then if the program attempts to read a file from there, the user could create that too. In this way, the malicious user could influence the execution of the program.

The best case for an attacker is that program will load some sort of code (e.g. DLL or EXE) from the directory.  Next best case is some sort of configuration file that could cause the application to misbehave.

To determine what the program was searching for, I created `C:\lib’, then re-ran it. This time the program looked for `C:\lib\SITE.PYC’, `C:\lib\OS.PY’ and `C:\lib\OS.PY’:

Loading libraries from `c:\lib'

Loading libraries from `c:\lib’

So the program is looking for some python libraries!

After some experimentation, I found I needed to create `os.py’ and `site.py’, then the program would execute those files when it loaded.  I create a simple PoC along the lines of:

f = open('c:\lib\evil.txt', 'w')
f.write('evil os.py was run')
f.close()

So just before we attempt to exploit the program with our evil Python scripts, the directory and permission look like this:

An exploitable set of permissions

An exploitable set of permissions

After we launch the program, we can see it has run our evil payload:

Our evil Python library has been executed

Our evil Python library has been executed

No PoC is really complete without running some actual OS commands. However, I found this slightly problematic. Normally I’d do the following:

import os
os.system("calc")

But in this case, we’ve replaced `os.py’, rendering “import os” somewhat useless. I considered a few workarounds including calling out to WinExec() in `kernel32.dll’ via ctypes – but I didn’t have ctypes available in this environment. Eventually I found the simplest route was to load the real `os.py’ (which lives in `C:\python27\lib; on my system):

import sys
sys.path.insert(1, 'c:\python27\lib') #prepend
import os
os.system("whoami >> c:\lib\whoami-site.txt")

Note that we prepend to the `PYTHONPATH’ in order to look for `os.py’ in the correct location first.

This correctly runs `whoami.exe’ and logs the output of who ran the program to a file. In this way our evil payload records all the unwitting users we could have run OS commands in the context of.

Conclusion

We’ve shown how a pretty low-tech approach to bug hunting could uncover a vulnerability that is made exploitable by the default file permissions on `C:\’. This could allow a malicious user on a terminal server (say) to cause other users to run code of their choosing. A simple privilege escalation attack – at the very least a horizontal privilege escalation.

The vulnerability could be caused by the way the application is coded or by a locally configured search path in the application’s environment.

In this case, the principle of least privilege would have saved the day.


Request to be added to the Portcullis Labs newsletter

We will email you whenever a new tool, or post is added to the site.

Your Name (required)

Your Email (required)