Most of us know that macros in Office documents are one of the most common ways to get malware into an organization. Unfortunately, all to many organizations depend on their AV products to detect these macros and the associated malware. It's sad fact that macro's are easy to write, and it's not too tough to evade AV by being smart about how you write a malicious macro. Even worse, there is continued push-back from managment that simply blocking macro's entirely is something that "can't possibly be done", because some critical doc or other might get dropped in the process - usually without any real examples of said critical files. (Even though from what I typically see, the more critical a document is, the less likely it is to have a macro in it) So that leaves us with potential malware on the inside of our organization. If our AV product won't detect it, how can we find it? As always, my first go-to is "could we write a PowerShell script to help with that?", and it turns out that yes, you can! What we are looking for is:
Let's start from the bottom of that short list and work up. A "zero byte" file of any kind is a great indicator in itself - often these are files that your AV product actually detected, and prevented from being saved on disk. Why are we interested in these? First of all, you might / should want to contact the person involved with that file and discuss with them what they might have been doing at that date/time, and suggest that receiving random office files from strangers is a really bad idea. If you run these scans frequently, you're likely asking them to think back an hour or two, you're not asking them about last week. Secondly, just because the file is zero bytes doesn't mean that the macro and associated malware didn't detonate. You might still want to look at that person's workstation and the other files in their profile directory and other 4data locations. Next up - "it came from the internet". This uses a pretty neat feature in Windows called "Alternate Data Streams". This is actually a pointer to a whole other possible set of file content, which can contain different data (including malware). Back in the day, this was used to support multiple filesystems (NFS, HFS and so on), however, a main use of alternate datastreams these days is to add various flags to each file - the one we're looking at is called "ZoneID", which stores some indication of where the file came from with the file itself. You can explore Alternate Data Streams using "dir /R" or the "streams" command in Microsoft Sysinternals ( https://docs.microsoft.com/en-us/sysinternals/downloads/streams ) Enumerating the ZoneID for a single file is pretty simple in PowerShell - first do a "get-content" on the file, which includes the various datastreams of the file, then look for the ZoneID Stream. The ZoneId can be one of the following values: 0 = "Local machine"
Narrowing our code down to just collect the value of the zoneid:
If that is 3, then the file is marked as "from the internet"
The code for word is slightly different, but the "HasVBProject" variable name stays the same.
All this being said, where should we look for these files? If you redirect the various "my documents" folders in a group policy, then look there! If you have a share that is the "store your stuff here" share in your organization, then look there! If you are looking for inadvertant "oops, I clicked a link" events, then look in users' temp directories. If the actual user is running the "hunting" script, maybe as part of the login script, the location of that user's temp directory can be read in PowerShell from the environment variable: $env:temp or $env:tmp (by default these have the same value - if they differ then check both) Anyway, with all that said, we can start collecting data. In some organizations, any macros at all might be cause for concern. In other organizations, the "macros from the internet" will be the red flag to look for. If we collect everything discussed so far, we can slice and dice the collected data any way required once we have it.
or, if we're trying to just locate office files with macros:
Zero sized files?
You get the idea, with everything in hand, slice and dice as needed. Or export to a CSV and use Excel as your "slicer and dicer" if you are more comfortable there. Alternatively, if this is in a login script (so is run by each user, against their files as they log in), and your target is "$env:temp" then you might want to dump these to a CSV file, maybe based on userid and workstation name. We're only interested if something is found, so there's a check for that in the "if" statement.
You'll want to modify the example script above to collect temp files and output any findings to a central location:
I did not collect the HostURL or ReferrerURL link variables for any files - that should be easy enough to add if you need that information. If you've used this approach and found something interesting, please let us all know via the comment form! (NDA's permitting of course).
=============== |
Rob VandenBrink 556 Posts ISC Handler Apr 15th 2020 |
||||||||||
Thread locked Subscribe |
Apr 15th 2020 9 months ago |
||||||||||
Hi,
before opening an Excel-file it needs to disable Makros, even when using Powershell: (and "update links) $Excel = New-Object -ComObject Excel.Application $Pfad = 'C:\Users\xxxxx\Desktop\' $file = 'Test.xlsm' $Excel.AutomationSecurity = 3 # msoAutomationSecurityForceDisable $WB = $Excel.Workbooks.Open($Pfad + $file, 0, 1) write-host ('vbaProject: ' + $WB.HasVBProject) $WB.close(0) $Excel.quit() regards |
Anonymous |
||||||||||
Quote |
Apr 15th 2020 9 months ago |
||||||||||
Good catch, thanks very much! I'll update the code in the post.
|
Rob VandenBrink 556 Posts ISC Handler |
||||||||||
Quote |
Apr 15th 2020 9 months ago |
||||||||||
I'll also disable alerts ( $application.DisplayAlerts = "wdAlertsNone" )
|
Rob VandenBrink 556 Posts ISC Handler |
||||||||||
Quote |
Apr 15th 2020 9 months ago |
||||||||||
Great work, but actually I continue to receive this error:
(Exeption HRESULT: 0x80010108 (RPC_E_DISCONNECTED)) Any ideas? Thanks. |
Nick 3 Posts |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
This seems to be a popular issue (just googled it). It's a communications error, and like most RPC communications errors, either it's an obvious one (firewall up at the far end for instance), or it seems to be occurring for no good reason ...
![]() Anyway, I've seen a few forums where adding a simple 1 or 2 second wait worked this out - in some cases the scripting approach can be too fast for the application to keep up. Try adding "sleep(1)" after the "$resultslist += $tempobj" line. If that doesn't work, this is not an issue that I've seen, and I've run this in a few live environments. Can you be more specific on which line is generating the error? |
Rob VandenBrink 556 Posts ISC Handler |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
Thanks a lot for your answer.
The sleep command didn't help unfortunately. Here is the output (in German): Das aufgerufene Objekt wurde von den Clients getrennt. (Ausnahme von HRESULT: 0x80010108 (RPC_E_DISCONNECTED)) In FindOfficeMacros.ps1:139 Zeichen:9 + $WorkBook.close($false) + ~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (:) [], COMException + FullyQualifiedErrorId : System.Runtime.InteropServices.COMException This error occurs many many times after processing a few files. |
Nick 3 Posts |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
Can we take this offline to email? - I'm at rob@coherentsecurity.com
Drop me a line and we'll take things from there? |
Rob VandenBrink 556 Posts ISC Handler |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
Actually, shoot me the OS version and patch levels at both ends in your email? If this works a number of times then starts to consistently fail, this might be an issue of RPC port exhaustion. See this MS doc: support.microsoft.com/en-us/help/935677/…
|
Rob VandenBrink 556 Posts ISC Handler |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
Thanks. E-Mail sent
|
Nick 3 Posts |
||||||||||
Quote |
Apr 16th 2020 9 months ago |
||||||||||
Nice post Rob, thank you for sharing. I think it should also be possible to translate your hunting techniques into a YARA rule, maybe extending the publicly available ones (https://github.com/Yara-Rules/rules/blob/master/maldocs/). There are some (thanks to Didier Stevens, Florian Roth and others) that are already available for detecting VBA macros in office documents, and could be possible to extend them with filesize condition and dotnet module (capable to dial with file streams, event if I've never tested it before).
Of course, the use of YARA needs the engine to be installed, instead of using a builtin tool such as powershell, but can improve performance in detection and avoid the risk of inadvertently run an autopen macro while initializing the office object in case of a security setup error. This is only my private opinion. |
PaoloLuise 2 Posts |
||||||||||
Quote |
Apr 20th 2020 9 months ago |
Sign Up for Free or Log In to start participating in the conversation!