SANS Digital Forensics and Incident Response Blog

Detecting DLL Hijacking on Windows

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:

  1. Iterate through each running process on the system, identifying all the DLLs which they have loaded
  2. For each DLL, inspect all the locations where a malicious DLL could be placed
  3. 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
  4. 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:
LoadLibrary(L"dll_hijack_test_dll.dll");.

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)

This now represents a common DLL hijacking attack in which the attacker would place the malicious DLL in the directory the program is launched from, which would be searched before the Windows System directory (where in this case, the legitimate DLL would be).
dll_hijack_demo1_smaller
Image 1. The demo program running with the DLL loaded

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:

dll_hijack_demo2
Image 2. Output from dll_hijack_detect.exe on demo system

Video demonstration

If you click the image below, you can see a video demonstration of the tool in action against the test files.
dll_hijack_demo_video
Video 1. Live demonstration of the tool in action

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

5 Comments

Posted March 26, 2015 at 12:08 PM | Permalink | Reply

Matt McGuyver

Great tool. To further reduce noise, you might consider hashing the colliding dlls and suppressing results for those that are identical.

Posted April 1, 2015 at 7:44 AM | Permalink | Reply

sheepray

Good post. But I am wondering how do u make sure that the signed DLL is not malicious which could be faked by malware itself.

Posted April 2, 2015 at 9:50 AM | Permalink | Reply

Adam Kramer

Thanks for the comments!
Matt:
Thanks! That's a great idea ''" I'll look to implement that in the next version
Sheepray:
A signed DLL could be malicious, but it's less likely due to the effort required to get a code signing certificate (which would be revoked pretty quickly if they saw you were releasing malware with it).
If you want to be extra sure, you can include signed DLLs, but it will increase the number of false positives to review.

Posted April 5, 2015 at 6:37 AM | Permalink | Reply

Mayank

Good article

Posted May 3, 2015 at 9:14 PM | Permalink | Reply

Jakob Heidelberg

One the same subject. Have you looked at ''MSS: (SafeDllSearchMode) Enable Safe DLL Search Mode'? This setting ensures that system DLL's will be used before local DLL's, which may be located in directories with less restrictive privilege levels. Enabling Safe DLL Search Mode helps prevent DLL preloading attacks.
See: https://technet.microsoft.com/en-us/library/cc264462.aspx