It rather involved being on the other side of this airtight hatchway: Open access to the application directory


A security vulnerability report arrived claiming that the Program X installer was insecure because it loaded a DLL (let's call it HAHA.DLL) from the current directory, thereby being susceptible to a current directory attack. (Other terms for this type of attack are DLL planting and DLL side-loading.)

The vendors who were responsible for Program X forwarded the report to Microsoft because their program never loaded HAHA.DLL directly; it was being loaded by a system component.

The first order of business was to verify that it was actually a DLL planting vulnerability. And it wasn't. It was an application directory attack, not a current directory attack. It turns out that a lot of purported DLL planting vulnerability reports are actually application directory attacks. DLLs in the application directory take priority over system DLLs because the directory is the Windows equivalent of what on the Mac is called an application bundle.¹ Which only serves to highlight the importance of securing your application directory.

In the original report, Program X was in a directory called something like \\server\software\install, which was filled with setup programs for various applications. As a result, all of the programs were soaking in the same hot-tub.

When this issue was pointed out to the vendors of Program X, they responded, "No, this is still a bug. You need to add HAHA.DLL to the KnownDlls list so that it cannot be overridden by the application directory."

The KnownDlls list is not a security feature. It is a performance feature. The fact that KnownDlls overrides the application directory is a side-effect of its implementation (namely, to avoid directory searching for popular DLLs), and it is arguably a bug, since it breaks contractual behavior: The application directory no longer takes precedence over the system directory. The Application Compatibility folks spend a lot of time studying the KnownDlls list to make sure that the DLLs in there are ones that no properly-functioning application should be trying to override with a local copy.

Even if HAHA.DLL were added to the KnownDlls list, that does not guarantee that it will always be loaded from the system directory. If somebody can attack your application directory, then they can drop a DLL redirection manifest into the directory or use DotLocal DLL redirection, both of which also override KnownDlls. (Observe that both of these attacks require write access to the application directory.)

The application directory is your safety bubble. If you let anybody into your safety bubble, then it isn't very safe any more.

In the parlance of airtight hatchways: Granting open write access to your application directory is equivalent to leaving open the door to your airtight hatchway.

¹ I used to say simply "The directory is the application bundle", but I'm now forced to use the much more awkward formulation because at least one person thought I was talking about Windows Store application bundles.

Comments (24)
  1. Joshua says:

    The true number of irreplaceable DLLs is four.

    So, since KnownDLLs is not a security feature, is it safe to remove a troublesome entry? I've seen a few threads of "but X is known DLL" where X was the name of some local DLL in some very old program but has the same name as some Windows DLL.

  2. kinokijuf says:

    @Joshua Two of them would be ntdll and kernel32 i guess, but what are the others?

  3. Nick says:

    @Joshua: Add it to the list of ExcludeFromKnownDlls that Larry Osterman described in his blog on the subject, blogs.msdn.com/…/187752.aspx

  4. Joshua says:

    @kinokijuf: kernelbase.dll and advapi.dll

  5. jader3rd says:

    "Granting open write access to your application directory is equivalent to leaving open the door to your airtight hatchway."

    That's one of the reasons why I don't like Steam. They turn off the security of their folder in Program Files

  6. Anon says:

    @jader3rd

    One thing I dream of is for Microsoft to place hard-locks on permissions for system folders when in the OS (i.e. not in WinPE or WinRE) for accounts which aren't builtins.

    It would break lots of poorly-written programs which should have been broken a decade or more ago.

  7. Kevin says:

    @Anon: Then people will just install things to C:Games instead.

  8. Random User 92747901 says:

    @jader3rd

    Sadly, while they could probably be a tad more selective and open up the security on a few of the sub-folders instead, they have to cope with the fact that game developers are particularly notorious for ignoring "the right way" of doing things, in favor of "it works", "it meets my performance goals", and "it just means the user has to be an 'admin'. Who isn't these days?". Before Steam added the change themselves, they were being screamed at in their forums because "game X won't run" or "every time I start game Y, it runs the 'first time' setup", etc.

    On the up-side, this is actually slightly better from a system standpoint, because before the change everyone's solution was to run Steam "as Administrator". Now they can stay normal users with the normal limitations. On the down-side, http://xkcd.com/1200/

    There's no fixing the old games; their devs are gone or don't care. There's a slim chance that new games could start doing things "the right way"…

    Well I did say "slim".

  9. Ondra says:

    After reading quite a few Old New Thing posts on this subject, I find it hard to shake the feeling that I'm more or less permanently on the insecure side of the airtight hatchway.

  10. Anon says:

    @Ondra

    Unless you answer "yes" to UAC prompts that randomly appear, you are not.

  11. Anon says:

    @Kevin

    And that's exactly where they should be installed. NOTHING in %ProgramFiles% should be modified by a non-Admin user.

    @Random User

    That's not true. You can fix plenty of things using redirection and file-level permissions.

    But until MS makes breaking changes to security or starts outing bad developers, nothing will change.

  12. Cesar says:

    This worries me. What if, instead of some \serversoftwareinstall, it was the "downloaded files" directory of the user's browser? The place where random downloaded files go to?

    I can imagine an attacker tricking the user into downloading HAHA.DLL and then downloading the installer from its legitimate website. The user feels safe, since the installer was downloaded from a legitimate place and has a legitimate signature… But it runs untrusted code which just happened to be in the same directory.

    I hope at least .msi installers are immune to this. Do they run in separate (or trusted) directories?

    [Yup, the downloads folder is another hot tub filled with yucky water. This is related to the "carpet bombing" attack. -Raymond]
  13. Falcon says:

    I actually got hit by a virus last year which used the application directory attack – it dumped an installer for a popular browser plugin, along with a rogue DLL, into the TEMP directory. It executed the installer, which ran elevated (after confirmation, if required), so the code in the DLL could do its thing.

  14. Silly says:

    As the owner of this computer I demand to see the dancing bunnies! (thank you for allowing it. I'd have cracked the sh**ts otherwise)

  15. Anonymous Coward says:

    @Joshua: Presuming those DLLs are "irreplaceable" because they call into kernel-mode, couldn't you statically link the same code and have zero DLLs?

    Not sure why you'd want to though, and you'd probably be featured in Raymond's nightmares.

  16. Anonymous Coward says:

    Brain fart. I meant you could statically link the code that does the syscalls, not the kernel mode itself.

  17. Joshua says:

    @Anonymous Coward: No. The system call numbers change between service packs. There's rumor of even a hotfix changing them.

    [Even if the syscalls don't change, and no undocumented structures change, you still can't do it. For example, kernel has "memorized" various function addresses inside ntdll, and if the function isn't there, you jump into space. -Raymond]
  18. poizan42 says:

    I'm pretty sure ntdll.dll, user32.dll and wow64.dll are the only dlls with syscall numbers hardcoded inside them. kernel32, kernelbase and advapi just calls into ntdll or user32 and wow64 needs the syscall numbers to marshal structures to their 64-bit versions for 64-bit system calls from WoW64 code. None of them are essentially irreplaceable, however you would need to have a replacement for every kernel revision. You would have a problem removing ntdll from the system though, as the kernel loads that into every process and starts the user space side of the execution of every process at a function inside ntdll.

  19. @poizan42:

    For an executable marked as Win32 application, the loader also loads kernel32.dll (and because of dependencies, kernelbase on newer versions of Windows). This is because kernel32 is an integral part of the Win32 API.

  20. ender says:

    > I hope at least .msi installers are immune to this. Do they run in separate (or trusted) directories?

    Place an executable named msiexec.exe to your Downloads folder and observe what happens.

  21. Marc K says:

    I already install games into "C:Games".  This should be relatively safe as I wouldn't allow a game to run elevated after the initial install.

    [Is your C:Games directory world-writable? -Raymond]
  22. Random User 92747901 says:

    @Anon

    I think we agree. My point was not that there was no other fix. Only that the common "wisdom" out on the Net was "Run as Administrator" to fix the Steam issues.

    Me, personally: There are defiantly games out there that completely fail without significant tweaking or "admin". On my machines, I figured out what dumb thing each games was doing that the automatic redirection wasn't fixing, and either granted that specific access, or found a way to force the redirect.

    I expect most of the game-playing public lacks either the knowledge or patience for such an exercise. If the developers cared, they would have designed the dumb thing not to need such overreaching access. Historically, they don't care; I do not have high hopes for them to start caring.

  23. RE: installer says:

    I hate installers that insist admin privileges. Those that not only get elevated automatically because UAC thinks they are setup programs, but also want to be elevated by use of manifest, and even explicitly check for admin rights in the code and halt with message box if invoker isn't one.

    The application compatibility toolkit can only fix so much with RunAsInvoker, VirtualRegistry, and ForceAdminAccess, and eventually run into what's apparently redirection issues on x64 systems.

    Nowadays I give up on those installers and just install them in a VM, then copy the program files and registry entries out.

  24. Joshua says:

    @RE: installer

    I hate the consequence of trying to clean up after somebody got past the manifest checks (who knows how) and managed to get half-way through the install w/o admin rights and now it's wedged because fix permissions routine in the installer revoked permissions on the directory they installed to. At some of these shops, it's really hard for them to hunt down somebody who is admin to fix the thing.

Comments are closed.

Skip to main content