The Good: Fairly Robust Blocking of Abused DLLs

Following along with the documentation to build a rule set to block scrobj.dll from loading into regsvr32.exe is pretty straightforward and can be accomplished in three lines of code:

For reference, those commands will produce the following XML WDAC policy:

This XML policy will allow all user and kernel mode code to run regardless of signer with the exception of scrobj.dll when the loader attempts to load it into regsvr32.exe.

After rebooting, the policy will take effect and scrobj.dll will be prevented from being loaded into regsvr32.exe and a Microsoft-Windows-CodeIntegrity/Operational 3077 event will be generated. For example, running the following command will generate a code integrity event accordingly:

regsvr32 /s /n /u /i:Backdoor.sct scrobj.dll

Code integrity event ID 3077 indicating that scrobj.dll was blocked from being loaded

A stealthy attacker may attempt to evade the detection by performing the following actions:

Copying regsvr32.exe to an attacker-controlled location and renaming it to something benign sounding — e.g. notepad.exe Renaming Backdoor.sct to something more benign sounding and removing the sct extension Copying scrobj.dll to an attacker-controlled location and renaming it to blah.txt

Such evasive tactics would be very likely to evade command-line logging designed to detect malicious regsvr32 usage. An example evasive invocation might look like the following:

notepad /s /n /u /i:foo blah.txt

Much to an attacker’s surprise, this evasion attempt would have been blocked as well.

The reason this successfully blocks the attack despite renaming all the binaries is because the block rule is based on the OriginalFileName property embedded in the PE resource. The rule does not take the filename on disk into account.

So what we now have is a way to effectively block DLLs we specify from loading into the processes of our choosing.