DLL Hijacking is a nice tool we can count on when pentesting Windows systems. It is a very common mechanism mainly used for privilege escalation and to avoid Windows' User Account Control. It can be performed easier than you might think if software isn't appropriately secured and user privileges aren't well defined. In this post we will try to clarify how DLL Hijacking works and how potentially exposed you can be if vulnerable to this kind of attack. You will also find some tips on how to prevent this kind of attacks.
What is Dynamic Library Linking?
If you are reading this post, you might already be familiar with how code usually has dependencies on other third party code to provide certain functionalities. If not, you might be interested in reading this piece of information before continuing with this reading.
There are basically two ways we can load libraries into our code:
- Static linking: Our program is linked with the external libraries at compile time. This means that any external library becomes part of our compiled executable in a "self-contained" manner, making our executable self-sufficient, but also heavier.
- Dynamic linking: External libraries are loaded at runtime. This difference is pretty important, as these external libraries are stored separately and our code only has the references to them. When running programs that rely on them, the operating system will load these libraries into memory for processes to be able to access them. You can now think about all the implications of how this mechanism works but it makes it possible for many different programs to rely on the same piece of code, which needs to be previously installed in the system.
What is DLL Hijacking?
Taking into account how dynamic linking works, what happens if a DLL (dynamic link library) that is located in your system is maliciously replaced? The answer is simple: the malicious code contained in the compromised DLL will be run as soon as the legitimate app loads it when trying to load de authentic DLL.
This technique is very interesting for attackers for two reasons:
- More applications than we think are vulnerable to this attack.
- The malicious code is embedded into the legitimate application. This means the attack is harder to detect because it isn't running on its own process but as part of a trusted process instead. You will never know it is there unless you notice the infected program is doing weird stuff or analyze the loaded modules.
The problem itself isn't only the application loading code it shouldn't be loading, but all the things the malicious code could be able to do when loaded. Once the DLL is running as part of the legitimate software, it is allowed to perform any action the legitimate software is allowed to. This means if the application is running as root, the malicious code will have complete access to the system and basically do whatever the attacker wants (open a command & control connection, download or unpack malware, change security settings and permissions, manipulate files, steal information, etc.). This is how privilege escalation is performed with DLL hijacking.
What can we do to protect against it?
There are effective measures against DLL hijacking that can be implemented from two perspectives: secure software development and secure system configuration.
From the software development perspective:
- Use complete paths when loading DLLs into an application.
- Validate the integrity of loaded libraries. This can be done by signing DLLs or comparing the hash of the loaded DLL against the hash of the known legitimate one.
From the configuration perspective:
- In Windows, enable Safe DLL Search Mode, which gives less priority to unsafe paths where DLLs are searched by the system. You can read more here.
- Give minimum privilege to applications. Don't run software as administrator or root unless it is extremely necessary. In general, running services and applications as root is a pretty bad practice and rarely necessary.
- Keep the principle of least privilege when configuring user rights in the system. Don't allow users to read or write where they shouldn't or needn't. This will help to prevent any possible malicious user from overwriting DLLs or placing them where they can be loaded by applications.
- Don't keep unnecessary directories in the system path. Any directory in the system path is susceptible to being searched by Windows when loading DLLs.
I hope you now have a better understanding of how this attack mechanism works. For software developers it is important to understand this kind of vulnerabilities and how they could affect their code. Best security is achieved by design.
I hope this post has been helpful. Thank you for reading!
Feel free to share your thoughts in the comments.
Comments
Post a Comment