Weaponize Your Word – Malicious Template Injection
Historically, files sent via email have been a common initial access technique employed by threat actors. Personally, I have seen emails containing malware prove effective, and in the case of an IR (Incident Response) involving a malware infection, it would be one of the first places I would look to identify the source of compromise.
There are many techniques for bypassing an email solution to deploy malware on an endpoint, however an old technique that is worth taking note of is that of malicious template injection. This technique allows for a document that is almost entirely non-malicious to be received by a user before an actual malicious loader is pulled via the Microsoft Word remote template functionality. This technique was observed being used by the LockBit Ransomware Gang (1) early in the year.
Malicious templates and exploitation.
It’s a lot easier to start this backwards, for reasons that will become apparent in the next section. Firstly, I recommend downloading a template from the internet, you can simply get it from Word by clicking create new document and scrolling down to the search from templates section.
Personally I went with “Blue Curve meeting agenda” but it doesn’t matter too much. Once you’ve selected your template, save the file and save it as a “Word Macro-Enabled Template” file.
Now that your file is prepped, go to the “Developer” tab and click on “Visual Basic”.
The Visual Basic built in IDE window will open up, you’ll want to select “ThisDocument” under the “TemplateProject” which shares the same name as your “.dotm” file.
Next, You’ll want to go to the top and click on “Tools” and then “Macros”.
The macro will have to be named “ThisDocument.Document_Open” as this is the VBA function name that will cause the macro to execute when the file is opened. So name the macro this then click create, at which point the VBA editor will open up.
VBA is a pretty simple scripting language, and works by having pre-defined function names that allow for Visual Basic Script to execute under different pre-defined circumstances. One of these pre-defined function names is DocumentOpen(), which you can probably guess from the name, causes any code within the function to execute at the point of the document opening. Obviously this is very useful for hackers, and Microsoft generally by default have a lot of settings to prevent autoexec functions like DocumentOpen(). However misconfigurations do happen, and clearly happen enough that LockBit was still able to use this technique in 2024.
Now onto the actual payload, I initially decided to go for something simple, the classic calc popping.
Prepping your loader file.
Before going into how this technique works, it is important to understand a pretty key aspect of the docx file type. Docx files, while they may appear to be one file, they are actually more akin to an archive file. This means that with most file archivers, such as 7zip, and simply renaming the file, you can unzip the archive and access the files inside it.
For example, if we take this demo document I’ve created, we can simply rename the file extension. I personally prefer doing this via PowerShell, but you can simply change the file extension by renaming the file in Explorer.
Once the file extension has been changed, you can open the file in 7zip and unzip it.
Once the zip file’s contents have been extracted, you can navigate into the new zip archive and then to /word/_rels.
Open the file “settings.xml.rels”.
Inside this file, you’ll see the section under “Target”. This is the location of the template file related to your document, which is saved as a “.dotm” file (also called a macro enabled document template file.) Now Microsoft in it’s infinite wisdom decided that this target should be able to contact remote template files over the internet, rather than just downloading the template and using it as a local file. Great for someone who likes all the company reports to be standardised, but terrible for security. So as a result you can actually easily change the target to just an IP address or domain and pull your malicious file.
In this case, I hosted my malicious file on a virtual machine called “BOB-PC” however you are not always required to use a domain and could use an IP address depending on how badly configured the target environment is. Once you’ve modified your “settings.xml.rels” file to point to your C2 server and malicious ”.dotm” file, save the file. You can then simply use something like 7zip to zip up the directory and then change the file extension from “.zip” back to “.docx” and your loader file is ready.
You could send this via a number of different avenues, a big benefit for attackers leveraging this technique is that due to the actual file sent over email does not contain actual malicious code/indicators, as a result plenty of email solutions would not have any issues with it. Any email solution that does sandboxing and detonates the loader beforehand however will absolutely catch this.
Further developments
There’s a few things you could do if you are encountering issues with this being blocked by defensive measures on a machine, to say that you have to seriously misconfigure your device to make this work is kind of an understatement. By default, Windows won’t even let you pull .dotm files from “untrusted” remote sources or run macro-enabled documents anyway, and those defensive measures stop this technique in its tracks.
First of all, you could modify your payload. Most anti-viruses and defensive solutions are pretty savvy to macros in Word documents these days, so if you aren’t obfuscating your payload you are going to have a real challenge getting this technique to work. I’m not going to go too far into the details of doing this, because this isn’t a blog post about obfuscation but rest assured ChatGPT is very good at writing VBS and getting it to make a simple dictionary to match letters to other letters and to decrypt a string at run time is trivial. In fact I very heavily based my own obfuscation development on how Lockbit was seen to be doing it.
Now unfortunately I didn’t have a chance to try this out, but a small theory that I’ve got is that were you to have access to a mature Microsoft 365 Tenant, and were able to create a new subscription, you could potentially spin up a virtual machine and host your “.dotm” file on it. Then when your loader file pulls the “.dotm” file it would appear to be pulling it from a Microsoft owned IP address, which happens when you get legitimate remote templates anyway. As I said, I didn’t get a chance to try it, so it may or may not work. And at the end of the day, you’d still have to end up on a victim machine which has macros enabled.
This attack does fundamentally rely on generating an instance of cmd.exe as a child process of WINWORD.EXE due to the generation of a shell, which means as a result a simple KQL query to detect execution of powershell in cmd.exe with command line arguments for remote file download can detect this usage.
DeviceProcessEvents | where FileName == "cmd.exe" | where InitiatingProcessFileName == "WINWORD.EXE" | where ProcessCommandLine has_any ("DownloadFile", "WebClient", "Base64", "Invoke-Expression") | extend SuspiciousCommand = case( ProcessCommandLine has "new-object System.Net.WebClient", "WebClient creation", ProcessCommandLine has "DownloadFile", "File download", ProcessCommandLine has "Base64", "Base64 encoding/decoding", ProcessCommandLine has "Invoke-Expression", "Execution of expression", "Other") | project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, SuspiciousCommand
Another method for detection is leveraging local device file creation logging to identify the downloading of remote templates. In my experience, this can be encountered from internal sources, think network shares with a custom template that is being pulled by users. I would recommend against it’s usage as a detection rule due to false positives, and rather a script for detection of this technique in incident response investigations.
DeviceFileEvents | where InitiatingProcessFileName endswith "WINWORD.EXE" //Word executable. | where FileName endswith ".dotm" //File extension for macro-enabled document templates. | where ActionType == "FileCreated" //Shows only file creation events. | where RequestProtocol != "Local" //Ignores any cases where the file was already present on the device. | where not( (ipv4_is_private(FileOriginIP)) or (FileOriginIP startswith "10.") or (FileOriginIP startswith "192.168.") or (FileOriginIP startswith "172." and toint(split(FileOriginIP, ".")[1]) between (16..31)) //Remote source for the dotm file is not a local network share. ) | project Timestamp, DeviceName, InitiatingProcessAccountName, FileName, FileOriginIP, FileOriginUrl, FileOriginReferrerUrl
References
1) https://www.youtube.com/watch?v=5PR15ithJek
2) https://tho-le.medium.com/remote-ms-office-template-injection-ffbe0d81512d