Alas, despite this issue being one of the most common plague of win32 applications, and Microsoft having had all the time in the world to make it go away, through the simple use of an application manifest that would tell the Windows loader to just disable looking for DLLs in the current application directory ever (because, believe it or not, some people do design self-contained executables that do not require loading anything else but system DLLs), application developers like yours truly still have to go through the utter annoyance of having to check whether their executable is potentially subject to DLL side-loading exploitation.
So, let's say you want to find out if Rufus is subject to side-loading. To do that, just download an run ProcMon and apply the following filters:
- Process Name contains
rufus
- Operation is
CreateFile
- Result contains
NAME NOT FOUND
Oh and since ProcMon is rather heavy on the system (since it monitors everything in real-time), you probably want to pause it until you are actually ready to run the app.
Then, while ProcMon is running, launch the Rufus executable and look for any request (CreateFile) for a DLL to be loaded in the current application directory.
With Rufus 4.6, it turns out that we have one for cfgmgr32.dll
:
![]() |
Ouch! |
What this means is that, if someone somehow managed to take control of your unprivileged user account or the location where the executable resides, they could drop a malicious cfgmgr32.dll
that could run whatever elevated code they wish.
Granted, if someone already has that level of access to a Windows machine, then they probably don't need to wait for the user to run Rufus to be able to execute elevated code, because, well, if you do have user level access on Windows, it's pretty much game over already. But still, Rufus should not allow an untrusted DLL to be loaded from the application directory.
Now, I'll spare you the details on how MinGW delay-loading, which we previously used to avoid this exact issue with other DLLs, somehow just won't work with cfgmgr32 (and yes, that is after making sure we use __attribute__((visibility("hidden")))
for DECLSPEC_IMPORT
since MinGW/binutils still have not sorted proper delay loading for gcc despite repeated pleas for them to do so on account that this leads to widespread security issues), but suffice to say that, this issue has been fixed in Rufus 4.7:
![]() |
Much better! |
Still, this stupid issue of DLL side-loading could easily have been fixed by Microsoft ages ago by providing applications developers with the ability to indicate that an executable should never ever load DLLs from the current/application directory. Yet it seems that, not happy to leave a glaring easily exploitable vulnerability in Windows, Microsoft actually backpedalled on an option they had originally added to SetDllDirectory()
, where passing ""
as a parameter was designed to remove the loading of DLLs from current user directories. If you look at the SetDllDirectory
documentation now, you will see that this mode of operation, which I did quote verbatim in Rufus at the time (If the parameter is an empty string (""), the call removes the current directory from the default DLL search order) is mysteriously absent, though it is still somehow currently mentioned in Microsoft's doc for Dynamic-Link Library Security.
And people wonder why Windows apps have a bad reputation when it comes to security issues...
With thanks to EmperialX, assisted by Shauryae1337, for reporting the issue with Rufus 4.6, as well as pointing to ProcMon as a means to highlight these kind of vulnerabilities.