Initially identified fifteen years ago, and clearly articulated by a Microsoft Security Advisory, DLL hijacking is the practice of having a vulnerable application load a malicious library (allowing for the execution of arbitrary code), rather than the legitimate library by placing it at a preferential location as dictated by the Dynamic-Link Library Search Order which is a pre-defined standard on how Microsoft Windows searches for a DLL when the path has not been specified by the developer.
Despite published advice on secure development practices to mitigate this threat, being available for several years, this still remains a problem today and is an ideal place for malicious code to hide and persist, as well as taking advantage of the security context of the loading program.
How can DLL hijacking be detected?
Okay - so it's up to the developers to be more secure in the way they load their libraries, but in the meanwhile how can we detect whether our systems have been compromised in this way? To achieve this I have been experimenting with a new methodology (well, at least it's new to me!) for detecting active attacks of this nature on vulnerable systems, and have written a program which does the following:
- Iterate through each running process on the system, identifying all the DLLs which they have loaded
- For each DLL, inspect all the locations where a malicious DLL could be placed
- If a DLL with the same name appears in multiple locations in the search order, perform an analysis based on which location is currently loaded and highlight the possibility of a hijack to the user
- Additionally: Check each DLL to see whether it has been digitally signed, and give the user the option to ignore all signed DLLs
During testing I have found that DLL hijacking isn't always malicious, infact there are a whole bunch of digitally signed libraries which sit in the base directory of an application (perhaps they act differently to their generic counterparts?).
Accordingly, in order to reduce the amount of noise returned by the tool, I implemented the '/unsigned' parameter, which I would recommend you use the first time you run it. This ignores cases where both the DLL which has actually been loaded, and others found in the search order are all signed (and therefore, more likely to be legit) - if you want to dig deep, feel free to leave this off!
By default, the tool will only display the results where the library being examined was loaded from one of the 'DLL search order' paths, as otherwise it implies it was safely loaded from an alternative location. Unfortunately, this excludes the 'Current Working Directory' (due to a lack of an API to retrieve this data and undocumented internal memory structure changes between versions). If you want to override this you can, with the /verbose option (realistically, in conjunction with /unsigned to reduce the noise). This would be useful if you are looking for 'remote system, current working directory' style attacks as this displays entries with multiple potential DLLs irrespective of where it was loaded from.
Demonstration of tool in action
To test the tool, I created a vulnerable executable which does a single action:
This sits alongside the associated DLL which, on being loaded, writes a message to the screen and sleeps forever to keep the program running.
I put the DLL in two locations on the system:
- The path to the executable
- The Windows System directory (C:\Windows\System32)
The image above shows the demo running and the properties page from Process Hacker, which shows the DLL as being loaded. At this point we run dll_hijack_detect.exe, which produces the following result:
As we can see, it has successfully identified the hijack and informed the user!
Sound great! Where can I download a copy?
I have release the source code and binaries, all of which are available from my github. In addition you will find a copy of the dll_hijack_test executable and DLL, so you can try it out for yourself!
Feedback would be greatly appreciated!
Follow me on Twitter: @CyberKramer