Way back in the days of Windows for Workgroups, we knew it was a dumb idea.
Moving from being a Unix developer to being a Windows developer, I could tell it was a dumb idea.
People inside of Microsoft knew it was a dumb idea.
And yet, LoadLibrary still pulls DLLs in from the current working directory, allowing vulnerabilities such as those found by ACROS Security.
[It doesn’t load DLLs from the current working directory as a first resort, it will usually search first in the application’s install directory, then in a couple of Windows directories, but if those fail, it will load from the current directory – see this MSDN article for details]
This is a bad idea.
If you’re a developer, and you were aware that this is a bad idea, then you could take defensive measures – for example, setting the “current working directory” (CWD, for short) to be a safe location – such as the application’s own directory.
If you weren’t aware that this is a bad idea, however, you’d blithely ignore the issue and carry on calling LoadLibrary to open custom DLLs.
How could this happen?
There’s two parts to that question:
- How it originated, and/or stayed in Windows: The origin is probably lost in the mists of time, but the reason the problem still exists is because it’s assumed to be too dangerous to backwards compatibility to remove – “it might break too many applications”. Don’t buy that – any application that behaves this way deliberately is pretty much flawed, and any application that behaves this way accidentally is definitely flawed.
- How current applications are vulnerable: bad programming, basically.
What kind of Bad Programming?
Well, as a hypothetical scenario, imagine a media playing application.
Media players know how to handle several “packages” (media files, which often can contain different formats of media), and may also know how to handle several “codecs” (the format of the media inside the package). To support maximum flexibility, they may allow the use of codecs that are not supplied with the application.
These third-party codecs are provided in the form of DLLs with specific documented entry points. They aren’t all installed with the operating system, and they aren’t all installed with the media player.
So, a media player may know about a few dozen codec DLLs, but may not know whether or not those codecs are installed. So how would it find out?
Simple – it would try to load each DLL, and flag as successful those codecs whose DLLs load.
But where does it find those DLLs?
DLLs supplied with an application should be found in the application’s install directory – and that’s the first place LoadLibrary looks.
System DLLs should be found in the Windows or Windows\SYSTEM32 directory. Second and third places.
The fourth place LoadLibrary looks in is the CWD. If you load your media player by double-clicking a media file (or any number of similar methods), the CWD will be the same folder as the media file is in, so a poorly-written media player (such as iTunes) would thus load a codec DLL from the same folder as the media file.
Codec DLLs should be registered in the registry using MFTRegister. So you should know exactly where to search for them.
Is this restricted to media players?
By no means is this restricted to one type of application. The risk here is from having all of these present:
- Applications which load when a file with an associated type is opened
- Applications which load DLLs that they did not install and which are not system DLLs.
- Poorly written LoadLibrary calls (i.e. those which do not specify the full path to a registered library, and which do not change the CWD before calling LoadLibrary)
Is this a Windows problem?
I think this is where Microsoft suffers from being an interesting platform for developers who are somewhat hard of thinking.
Don’t get me wrong, there are many expert and experienced developers on the Windows platform – but there are apparently at least several hundred developers who are not very well versed in the operating system on which they develop, and as such, fall to this issue and its like.
Unix, and by extension, Linux, doesn’t have the same problem, because it doesn’t put “.” (the current working directory) into the executable path environment variable, or the dynamic library search order. Well, actually, that’s not really correct – Unix and Linux do have this problem, because application authors are just as dumb on those platforms, and have insisted that ‘to make this application work, “.” needs to be in the path and/or load order’.
Can Microsoft fix this?
Not completely – there will always be stupid developers, and there will, as I have pointed out before, always be developers who don’t like the platform they’re developing for, and who will therefore screw things up, deliberately or accidentally. When you view the OS platform as the enemy, you can’t write trustworthy code. This should be seen as a problem particularly by companies such as Apple and Google, who have expressed direct hostility towards Windows, and therefore may not be the best examples of good coding practices in writing applications for that system.
Even if Microsoft do change this behaviour, the story isn’t over, because removing support for loading DLLs from the current directory may kill the operation of a significant number of applications. Perhaps even one that your company relies on. That’s not a decision I want them making lightly.
I’d rather see an extension to SAFER / Software Restriction Policies / AppLocker (or whatever it’s called this week) that allows me to specify that DLLs can only be loaded from specific named paths. That, and/or the ability to specify which apps can load DLLs from CWD, and that all others should not. Then I can reduce my threat to only those applications I deem necessary.
Update: As if by magic, Microsoft released just such an extension – OK, maybe it’s not implemented in the place I suggested, but it should have the same effect. I would strongly advise enterprises to start testing this with your standard line-of-business apps, to see whether they break.
H D Moore’s post on Application DLL Load Hijacking. Note the quote from ACROS Security which suggests that they are in this job only to make money, rather than to enhance your security. Perhaps this is poorly worded, but it is indicative of a worrying trend.
Apple’s security bulletin on the poor programming in iTunes (right down at the bottom).
Microsoft releases an update to allow you to change LoadLibrary’s behaviour on a system-wide and application-specific level: MSRC blog entry, SRD blog entry, Knowledge Base Article (and update download).
Microsoft releases documentation on the right ways to call LoadLibrary to prevent this problem.
Don’t forget, if you’re using LoadLibrary to get at strings, images, sounds, or other resources stored in a DLL, you should be using LoadLibraryEx instead, and calling it with the flags appropriate to loading the DLL for resource / data access only, so that you don’t execute the code inside the DLL.
(*) The reference to “more” is because of the previous LoadLibrary issues, with a .LNK code execution flaw recently patched.