I usually write my blog-posts in german. This one is in english, because Sami Laiho asked me to do a short write-up, to make this problem available to a broader audience.
Who is affected and what’s the problem?
If you are using AppLocker Application-Whitelisting using Path-Rules with Exceptions you are probably affected. See the following example to understand, what type of problem we have to fight against.
Short-Summary – Typical Situation: How to “Design” an AppLocker Path-Rule:
Your unsigned but business-critical application is located in following directory, and writes logs to a subfolder:
C:\Program Files (x86)\DemoApplication\C:\Program Files (x86)\DemoApplication\logs
As this application is not authenticode-signed, you create an AppLocker path-rule: Allow to execute everything in DemoApplication, but exclude the logs-directory (as this is user-writeable, so otherwise a user or a malicious process could put a binary there and execute it).
Testing the Rule
The rule works as expected. A regular user can copy a binary (like for example SysInternals Tcpview.exe, which I use for demonstration purposes in this example) into the logs-directory, but cannot execute it. AppLocker-eventlog shows, that tcpview.exe (located in the logs-directory) was prevented from running – thats correct behavior:
Bypassing AppLocker by using Alternate Data Streams
If you are not aware what Alternate Data Streams are, check out this blog-post. So, what’s the trick to bypass AppLocker: We copy the contents of an executable to an Alternate Data Stream of the logs-directory. To be clear: Not to a file in the logs-directory, but to an ADS of the logs-directory itself! The copy-job is done using the “type” command redirecting the output to an ADS. The execution of an ADS can be done by various ways, one way would be to use wmic to create a new process, but there are other ways too.
Looking into eventlog reveals: Yes, that was a straight-forward AppLocker bypass. Applocker saw this execution operation but decided it is “allowed to run”:
How to prevent
So – bad situation. How to prevent this? Why did AppLocker allow the execution, even if we excluded the logs-directory?
In fact: We did not exclude the logs-directory! We excluded everything below the logs-directory! We have to add a second exclude-rule “logs:*” to prevent this:
After inserting this second exception-rule, which excludes all Alternate Data Streams of the logs-Directory from executing, the start of the “Evil-ADS-Binary” is prevented by AppLocker:
Which Versions of Windows are affected?
All versions I tested so far, at least I can say: Every Windows 10 Version – including the newest v1803 Release (final Insider preview, tested on 08. April 2018) are affected.
Why doesn’t Microsoft prevent this?
I don’t know. I reported this behaviour twice. I cannot see any useful or legit case, where executing an Alternate Data Stream is needed. In my opinion there should be a single checkbox “prevent all ADS from being executed” which should be on by default – but AppLocker doesn’t handle ADS this way I would like to see.
Is this behaviour a problem? Yes – I really think it is. And I’m not the one who originally “found” this bug / bad behaviour. If you do a google-search, you can find other sources explaining this problem – not exactly in detail like I did here, but I’m quite sure this is a very well known and commonly used AppLocker-Bypass trick. I think almost nobody of the SysAdmins out there is aware of the fact, that you have to set ACLs on the writeable directories in a way you cannot add ADS, or have to configure two Exclude-Rules for every writeable path. As Microsoft seems not to change AppLocker behaviour, you should be aware of this and maybe double-check your Path-Exclusion-Rules soon!
- Check this blog post for detailed Information about Alternate Data Streams, hiding Executables in ADS etc…
- Have a look at the Ultimate AppLocker ByPass List and follow Oddvar Moe on Twitter
- I informed Aaron Margosis, his popular script AaronLocker can handle this correct now and provides mitigation too (released on 10th October 2018)