Appearance
Runbook: FIM Coverage Verification
Purpose
File Integrity Monitoring (FIM) is a mandatory control under:
- HIPAA §164.312(c)(1) — Integrity controls: protect ePHI from improper alteration or destruction
- SOC2 CC6.8 — Implement controls to prevent or detect unauthorized changes to infrastructure
This runbook answers "do we have FIM coverage?" with a clear yes/no per system and tells a new engineer exactly how to verify each layer is functioning, find gaps, and produce evidence for an auditor.
LAW workspace: cirius-logging-law-central (ID: 5d76d1f2, RG: rg-logging-logs)
Portal (LAW Logs): Azure Portal → Log Analytics Workspaces → cirius-logging-law-central → Logs
CLI pattern:
bash
az monitor log-analytics query --workspace 5d76d1f2 \
--analytics-query "<KQL here>" --output tableFIM Layer Overview
Cirius Group uses four overlapping FIM layers. No single layer covers everything — together they provide defense-in-depth across Windows endpoints, Azure VMs, and Linux hosts.
| Layer | Mechanism | Primary Coverage | Alert Destination |
|---|---|---|---|
| L1 — MDE (Windows) | DeviceFileEvents / DeviceRegistryEvents | Windows endpoints, Azure Windows VMs | M365 Defender portal → Sentinel / LAW |
| L2 — AMA + Sysmon | EventID 11/13 via DCR to LAW | Windows endpoints (if Sysmon deployed) | SecurityEvent / Event table in LAW |
| L3 — Velociraptor | VQL hash-check artifacts on schedule | Any enrolled client | Velociraptor GUI, exportable to SecOps |
| L4 — Defender for Cloud | FIM feature (Defender for Servers P2) | Azure VMs (Windows + Linux) | Defender for Cloud portal → LAW |
Linux VMs additionally use auditd (-w watch rules) forwarded via AMA.
Coverage Matrix
| System Type | L1 MDE | L2 AMA+Sysmon | L3 Velociraptor | L4 DfC FIM | auditd | Net Coverage |
|---|---|---|---|---|---|---|
| Windows workstation (Intune-managed) | YES | Conditional (Sysmon deployed?) | YES (if enrolled) | N/A | N/A | L1 guaranteed; L2 confirm Sysmon |
| Windows Azure VM (PROD) | YES | YES (SecurityEvent DCR) | YES | YES (if DfC P2 active) | N/A | Full |
| Windows Azure VM (DDE) | YES | YES | YES | YES | N/A | Full |
| Linux Azure VM | N/A | YES (auditd via AMA) | YES | YES | Required | L4 + auditd |
| On-prem server (AD-joined) | YES (ARC or direct enroll) | YES (if AMA installed) | YES | Partial (ARC required) | N/A | Verify ARC enrollment |
| Unmanaged / non-enrolled device | NONE | NONE | NONE | NONE | N/A | GAP — escalate |
Monitored Paths Reference
These are the paths Cirius Group is required to monitor. Verification steps in later sections check that events for these paths are actually flowing.
Windows — Registry (Required)
| Key | Risk | Expected Event |
|---|---|---|
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run | Persistence | DeviceRegistryEvents / Sysmon 13 |
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce | Persistence | DeviceRegistryEvents / Sysmon 13 |
HKLM\SYSTEM\CurrentControlSet\Services | Service install / malware driver | DeviceRegistryEvents / Sysmon 13 |
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment | PATH hijack | DeviceRegistryEvents / Sysmon 13 |
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run | Per-user persistence | DeviceRegistryEvents (per user session) |
Windows — File System (Required)
| Path | Risk | Expected Event |
|---|---|---|
C:\Windows\System32\ | Binary replacement, DLL hijack | DeviceFileEvents / Sysmon 11 |
C:\Windows\System32\drivers\ | Malicious kernel driver | DeviceFileEvents |
C:\Windows\System32\config\ | SAM / SYSTEM hive tampering | DeviceFileEvents |
C:\Windows\System32\Tasks\ | Scheduled task XML modification | DeviceFileEvents / EventID 4698 |
C:\Program Files\ | Application binary replacement | DeviceFileEvents |
| Service executable paths (variable) | Service binary swap | DeviceFileEvents + EventID 7045 |
| Application config dirs with DB credentials | Credential exposure | Site-specific — verify per app |
Linux — File System and System Config (Required)
| Path | auditd Rule | Risk |
|---|---|---|
/etc/passwd | -w /etc/passwd -p wa -k identity | Account creation / UID 0 escalation |
/etc/shadow | -w /etc/shadow -p wa -k identity | Password hash theft |
/etc/sudoers | -w /etc/sudoers -p wa -k privilege | Privilege escalation |
/etc/sudoers.d/ | -w /etc/sudoers.d/ -p wa -k privilege | Privilege escalation |
/etc/cron.d/ | -w /etc/cron.d/ -p wa -k persistence | Cron-based persistence |
/etc/cron.daily/ | -w /etc/cron.daily/ -p wa -k persistence | Cron-based persistence |
/etc/cron.hourly/ | -w /etc/cron.hourly/ -p wa -k persistence | Cron-based persistence |
/var/spool/cron/ | -w /var/spool/cron/ -p wa -k persistence | User crontab modification |
/etc/ssh/sshd_config | -w /etc/ssh/sshd_config -p wa -k ssh | SSH backdoor |
/etc/systemd/system/ | -w /etc/systemd/system/ -p wa -k persistence | Malicious systemd unit |
/usr/bin/ | -w /usr/bin/ -p wa -k binaries | Binary replacement |
/usr/sbin/ | -w /usr/sbin/ -p wa -k binaries | Binary replacement |
/sbin/ | -w /sbin/ -p wa -k binaries | Binary replacement |
Part 1 — Layer 1: MDE File and Registry Events
1.1 — Verify MDE is Onboarded and Sending Telemetry
M365 Defender Portal: https://security.microsoft.com
Path: Endpoints → Device inventory
All Windows devices should show status Active with a recent Last Seen timestamp. Any device showing Inactive or No sensor data has a gap.
KQL — Confirm DeviceFileEvents are flowing (LAW via Sentinel connector or M365 Defender Advanced Hunting):
In M365 Defender Advanced Hunting (security.microsoft.com → Hunting → Advanced Hunting):
kql
// Confirm file events are being received from all enrolled devices
DeviceFileEvents
| where Timestamp > ago(24h)
| summarize EventCount = count(), LastSeen = max(Timestamp) by DeviceName
| sort by LastSeen asc
// Devices missing from this list have a telemetry gapkql
// Confirm registry events are flowing
DeviceRegistryEvents
| where Timestamp > ago(24h)
| summarize EventCount = count(), LastSeen = max(Timestamp) by DeviceName
| sort by LastSeen ascKQL — Check for changes to persistence registry keys (last 7 days):
kql
DeviceRegistryEvents
| where Timestamp > ago(7d)
| where RegistryKey has_any (
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
@"SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
@"SYSTEM\CurrentControlSet\Services",
@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
)
| where ActionType in ("RegistryValueSet", "RegistryKeyCreated", "RegistryValueDeleted")
| project Timestamp, DeviceName, ActionType, RegistryKey, RegistryValueName,
RegistryValueData, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp descKQL — Check for changes to critical system binaries (last 7 days):
kql
DeviceFileEvents
| where Timestamp > ago(7d)
| where FolderPath has_any (
@"C:\Windows\System32\",
@"C:\Windows\System32\drivers\",
@"C:\Windows\System32\config\",
@"C:\Windows\System32\Tasks\"
)
| where ActionType in ("FileCreated", "FileModified", "FileRenamed", "FileDeleted")
| project Timestamp, DeviceName, ActionType, FolderPath, FileName,
SHA256, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc1.2 — Verify MDE is in Passive Mode (Required with Cortex XDR)
MDE must run in Passive Mode on all Cirius Windows devices — Active Mode with Cortex XDR active causes CPU saturation. See mde-passive-mode.md for full passive mode operations.
KQL — Confirm passive mode is not broken (no MDE-initiated quarantine actions):
kql
// In M365 Defender Advanced Hunting
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "AntivirusDetection"
| where AdditionalFields has "Quarantine"
// Any quarantine actions suggest Passive Mode has drifted to ActiveRegistry check (run on a sample endpoint):
HKLM\SOFTWARE\Microsoft\Windows Advanced Threat Protection\Status
ForceDefenderPassiveMode = 1 (REG_DWORD)Part 2 — Layer 2: AMA + Sysmon (Windows Event Log Path)
This layer captures FIM events through the Windows Event Log pipeline: Endpoint → Sysmon → Windows Event Log → AMA → DCR → LAW (SecurityEvent or Event table)
2.1 — Verify AMA is Installed and Healthy
Azure Portal → Monitor → Data Collection Rules
The DCR named for Windows event collection should target cirius-logging-law-central. Check that the DCR's Data Sources include:
- Windows Event Logs:
Security,System, andMicrosoft-Windows-Sysmon/Operational(if Sysmon is deployed) - XPath filters should include at minimum:
- Security:
*[System[(EventID=4688 or EventID=4624 or EventID=4625 or EventID=4648 or EventID=4698 or EventID=1102 or EventID=5140 or EventID=7045)]] - Sysmon:
*[System[(EventID=11 or EventID=13 or EventID=2)]]
- Security:
KQL — Confirm AMA heartbeats from all Windows VMs:
kql
Heartbeat
| where TimeGenerated > ago(24h)
| where OSType == "Windows"
| summarize LastHeartbeat = max(TimeGenerated) by Computer
| where LastHeartbeat < ago(4h)
// Any machine here has an AMA connectivity problemKQL — Confirm Sysmon FIM events are landing in LAW:
kql
// Sysmon EventID 11 = FileCreate, 13 = RegistryValueSet
Event
| where TimeGenerated > ago(24h)
| where Source == "Microsoft-Windows-Sysmon"
| where EventID in (11, 13)
| summarize EventCount = count() by Computer, EventID
| sort by EventCount desc
// Zero results = Sysmon not deployed or DCR not including Sysmon logkql
// Alternative: check if Sysmon events landed in SecurityEvent table (they won't —
// Sysmon goes to Event table. If zero results above, check Event table specifically)
Event
| where TimeGenerated > ago(1h)
| where Source == "Microsoft-Windows-Sysmon"
| take 5
// If this returns nothing, Sysmon events are not flowing. Check DCR XPath config.2.2 — Verify Sysmon FIM Coverage for Critical Paths
If Sysmon is deployed, verify it is configured to watch the required paths. Sysmon config should include FileCreate (EventID 11) rules for System32, drivers, Tasks, and RegistryEvent (EventID 13) rules for Run keys and Services.
Check current Sysmon config on a test endpoint (run as admin):
powershell
# Dump the running Sysmon configuration
& "C:\Windows\sysmon64.exe" -cLook for FileCreate and RegistryEvent sections covering the paths from the monitored paths table in this runbook. If paths are missing, update the Sysmon config XML and redeploy via Intune or GPO.
Part 3 — Layer 3: Velociraptor FIM Artifacts
Velociraptor provides scheduled file hash verification — a true integrity check against known-good baselines, not just event-stream monitoring.
Console: https://velociraptor.ciriusgroup.com
Auth: Entra PROD OIDC, group SecOps DFIR
3.1 — Verify Scheduled FIM Hunts Are Running
- Log into the Velociraptor console
- Navigate to Server Events → Artifacts → search for
FIMorHash - Confirm a scheduled artifact is running for each of the following (or confirm the artifact covers all):
Windows.Detection.FIMFiles(if deployed as a custom artifact) — hashes System32 critical binaries against a baselineGeneric.Detection.HashCheck— generic hash verificationWindows.System.Services— detects new or modified services
Check artifact schedule:
- In Velociraptor GUI → Server Artifacts → find the FIM artifact → Schedule tab
- Should show a recurring schedule (daily minimum for SOC2; weekly for HIPAA minimum)
3.2 — Run an Ad-Hoc FIM Collection (Verification or Incident)
Single host:
Velociraptor → Search (find the host) → New Collection →
Artifact: Windows.Detection.FIMFiles (or custom FIM artifact) → LaunchFleet-wide hunt:
Velociraptor → Hunt Manager → New Hunt →
Artifact: Windows.Detection.FIMFiles →
Condition: OS = Windows →
LaunchVQL — Ad-hoc hash check for System32 binaries via Notebook:
vql
-- Collect SHA256 hashes of all EXEs in System32 and compare to baseline
LET baseline <= SELECT FullPath, Hash.SHA256 AS GoodHash
FROM parse_csv(filename="/path/to/system32-baseline.csv")
SELECT FullPath, Hash.SHA256 AS CurrentHash, GoodHash,
if(condition=Hash.SHA256 = GoodHash, then="OK", else="CHANGED") AS Status
FROM glob(globs="C:\\Windows\\System32\\*.exe")
JOIN baseline ON FullPath
WHERE Status = "CHANGED"VQL — Check for new service executables (persistence check):
vql
SELECT Name, DisplayName, PathName, StartType, State
FROM wmi(
query="SELECT * FROM Win32_Service WHERE PathName LIKE 'C:\\%' AND State='Running'",
namespace="root/cimv2"
)
WHERE NOT PathName =~ "C:\\Windows\\\\" AND NOT PathName =~ "C:\\Program Files\\\\"3.3 — Export Velociraptor FIM Results to SecOps Evidence
After any scheduled or ad-hoc FIM hunt:
- Hunt → Download Results → CSV
- Upload to SecOps via
POST /api/evidencewithevidence_type: "fim_audit" - Note the collection timestamp — this is the evidence timestamp for compliance purposes
Part 4 — Layer 4: Defender for Cloud FIM (Azure VMs)
Defender for Cloud's FIM feature requires Defender for Servers Plan 2 on the subscription. It monitors critical OS paths and registry keys on Azure VMs directly.
4.1 — Verify Defender for Cloud FIM is Active
Azure Portal path:
Defender for Cloud → Environment Settings → [subscription] →
Defender Plans → Servers → Plan 2 → Settings → File Integrity MonitoringFIM should show On for both PROD and DDE subscriptions.
CLI check:
bash
# Check Defender for Servers plan per subscription
az security pricing list --subscription <subscription-id> \
--query "[?name=='VirtualMachines'].{Name:name, PricingTier:pricingTier}" \
--output table
# PricingTier should be "Standard" (P2) not "Free"4.2 — Verify FIM Events Are Flowing to LAW
Defender for Cloud FIM events land in the ConfigurationChange table in LAW.
KQL — Verify FIM events are being received:
kql
ConfigurationChange
| where TimeGenerated > ago(24h)
| where ConfigChangeType in ("Files", "Registry", "WindowsServices")
| summarize EventCount = count() by Computer, ConfigChangeType
| sort by EventCount desc
// Zero results = DfC FIM is not enabled or not forwarding to this workspaceKQL — File changes on Azure VMs (last 7 days):
kql
ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "Files"
| where FileSystemPath has_any (
"\\Windows\\System32",
"\\Windows\\System32\\drivers",
"\\Program Files"
)
| project TimeGenerated, Computer, FileSystemPath, ChangeCategory,
PreviousSize, CurrentSize, PreviousMd5, CurrentMd5
| sort by TimeGenerated descKQL — Registry changes on Azure VMs (last 7 days):
kql
ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "Registry"
| where RegistryKey has_any (
"CurrentVersion\\Run",
"CurrentVersion\\RunOnce",
"CurrentControlSet\\Services",
"Session Manager\\Environment"
)
| project TimeGenerated, Computer, RegistryKey, RegistryValueName,
PreviousContent, NewContent, ChangeCategory
| sort by TimeGenerated descKQL — Windows service changes on Azure VMs (last 7 days):
kql
ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "WindowsServices"
| project TimeGenerated, Computer, SvcName, SvcDisplayName, SvcState,
SvcStartupType, SvcPath, ChangeCategory
| sort by TimeGenerated desc4.3 — Verify DfC FIM Monitored Paths Are Configured
Azure Portal → Defender for Cloud → Workload Protections → File Integrity Monitoring
Default monitored paths should include:
- Windows Files:
C:\Windows\System32\*,C:\Windows\SysWOW64\* - Windows Registry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Runand related keys - Linux Files:
/etc/,/bin/,/usr/bin/
If any required paths from the monitored paths table in this runbook are missing, add them via Edit → Windows Files or Linux Files → Add.
Part 5 — Linux VM auditd Verification
All Linux Azure VMs must have auditd installed and running with the Cirius standard ruleset. Rules are forwarded to LAW via AMA.
5.1 — Required auditd Ruleset
Deploy this ruleset to /etc/audit/rules.d/cirius-fim.rules on all Linux VMs. The file must exist and be loaded by auditd.
bash
# /etc/audit/rules.d/cirius-fim.rules
# Cirius Group — Standard FIM auditd Rules
# HIPAA §164.312(c)(1) | SOC2 CC6.8
# Deploy via Ansible or Azure VM Extension. Do not edit manually on hosts.
# === Identity and Authentication ===
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity
# === Privilege Escalation ===
-w /etc/sudoers -p wa -k privilege
-w /etc/sudoers.d/ -p wa -k privilege
# === Scheduled Tasks / Persistence ===
-w /etc/cron.allow -p wa -k cron
-w /etc/cron.deny -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /etc/cron.daily/ -p wa -k cron
-w /etc/cron.hourly/ -p wa -k cron
-w /etc/cron.monthly/ -p wa -k cron
-w /etc/cron.weekly/ -p wa -k cron
-w /etc/crontab -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
# === SSH Configuration ===
-w /etc/ssh/sshd_config -p wa -k ssh
-w /etc/ssh/ -p wa -k ssh
# === systemd (Service Persistence) ===
-w /etc/systemd/system/ -p wa -k persistence
-w /usr/lib/systemd/system/ -p wa -k persistence
-w /lib/systemd/system/ -p wa -k persistence
# === System Binaries ===
-w /usr/bin/ -p wa -k binaries
-w /usr/sbin/ -p wa -k binaries
-w /bin/ -p wa -k binaries
-w /sbin/ -p wa -k binaries
# === Kernel Modules ===
-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules
-a always,exit -F arch=b64 -S init_module -S delete_module -k modules
# === Logging System Integrity ===
-w /var/log/auth.log -p wa -k logs
-w /var/log/syslog -p wa -k logs
-w /etc/rsyslog.conf -p wa -k logs
-w /etc/rsyslog.d/ -p wa -k logs
# === Network Configuration ===
-w /etc/hosts -p wa -k network
-w /etc/resolv.conf -p wa -k network
-w /etc/network/ -p wa -k network
-w /etc/NetworkManager/ -p wa -k network
# === PAM ===
-w /etc/pam.d/ -p wa -k pam
-w /lib/security/ -p wa -k pam
-w /lib64/security/ -p wa -k pam
# === Immutable flag (must be last line) ===
# Uncomment after confirming rules are correct — prevents runtime rule changes
# -e 25.2 — Verify auditd is Running and Rules Are Loaded
Run on each Linux VM or via Velociraptor artifact:
bash
# Is auditd running?
systemctl is-active auditd
# Are the Cirius FIM rules loaded?
auditctl -l | grep -E "identity|privilege|persistence|ssh|binaries|cron"
# How many rules are active? (expect 30+ for full Cirius ruleset)
auditctl -l | wc -l
# Confirm the rules file is present and not empty
ls -la /etc/audit/rules.d/cirius-fim.rules
wc -l /etc/audit/rules.d/cirius-fim.rules5.3 — Verify auditd Events Are Flowing to LAW
AMA must be configured with a DCR that collects Syslog (facility daemon and auth) or the auditd syslog output. Auditd events land in the Syslog table in LAW.
KQL — Verify auditd FIM events are arriving:
kql
Syslog
| where TimeGenerated > ago(24h)
| where ProcessName == "audispd" or SyslogMessage has "type=SYSCALL" or SyslogMessage has "key=\"identity\""
| summarize EventCount = count(), LastSeen = max(TimeGenerated) by Computer
| sort by LastSeen asc
// Missing computers = auditd not forwarding or AMA Syslog DCR not configuredKQL — Show identity-related auditd events (last 24 hours):
kql
Syslog
| where TimeGenerated > ago(24h)
| where SyslogMessage has "key=\"identity\"" or SyslogMessage has "key=\"privilege\""
| project TimeGenerated, Computer, SyslogMessage
| sort by TimeGenerated descKQL — Show persistence-related auditd events (last 24 hours):
kql
Syslog
| where TimeGenerated > ago(24h)
| where SyslogMessage has "key=\"persistence\"" or SyslogMessage has "key=\"cron\""
| project TimeGenerated, Computer, SyslogMessage
| sort by TimeGenerated descPart 6 — Gap Analysis
Run these checks after any system change, new VM deployment, or quarterly.
6.1 — Machines with AMA but No MDE Enrollment
KQL — AMA-reporting machines not in MDE device inventory:
kql
// Step 1: Get all AMA-reporting machines from LAW
let AMAMachines = Heartbeat
| where TimeGenerated > ago(24h)
| where OSType == "Windows"
| distinct Computer;
// Step 2: Get all MDE-enrolled machines
// (run in M365 Defender Advanced Hunting)
// DeviceInfo | where Timestamp > ago(24h) | distinct DeviceName
// Step 3: Manually cross-reference — machines in AMAMachines not in MDE = gap
AMAMachines
| extend NormName = toupper(tostring(split(Computer, ".")[0]))6.2 — Linux VMs Missing auditd
KQL — Linux VMs reporting Heartbeat but no auditd events:
kql
let LinuxVMs = Heartbeat
| where TimeGenerated > ago(24h)
| where OSType == "Linux"
| distinct Computer;
let AuditdReporting = Syslog
| where TimeGenerated > ago(24h)
| where ProcessName == "audispd" or SyslogMessage has "key=\"identity\""
| distinct Computer;
LinuxVMs
| where Computer !in (AuditdReporting)
// These Linux VMs are NOT sending auditd events6.3 — Azure VMs Not Covered by Defender for Cloud FIM
KQL — VMs missing ConfigurationChange data:
kql
let AllVMs = Heartbeat
| where TimeGenerated > ago(24h)
| distinct Computer;
let FIMReporting = ConfigurationChange
| where TimeGenerated > ago(7d)
| distinct Computer;
AllVMs
| where Computer !in (FIMReporting)
// These VMs are not sending ConfigurationChange events
// Cause: DfC FIM not enabled, Plan 2 not active, or AMA not installed6.4 — Paths Not Covered by Any FIM Layer
Use the monitored paths table in this runbook as the authority. For each path category, run the corresponding KQL and verify events are present. If a path returns zero events across all layers for a 7-day window, that is a coverage gap. Document it as:
- Confirmed gap (no FIM layer watches this path)
- Silent path (FIM watches but no changes have occurred — expected)
To distinguish: create a test file or registry key in the monitored path, then query for it within 15 minutes. If no event appears, the coverage is missing.
Part 7 — Alert Configuration
FIM events are not all equal. This table defines which events trigger SecOps incidents vs. which are logged and reviewed at a cadence.
| Event | Severity | Trigger | Response |
|---|---|---|---|
| Registry Run key addition outside CM window | HIGH | Auto-incident via SecurityAgent | Investigate source process; escalate to CRITICAL if unexpected |
| New service binary installed | HIGH | Auto-incident via SecurityAgent | Cross-reference with CM ticket; if no CM = treat as CRITICAL |
/etc/passwd modification | CRITICAL | Auto-incident, immediate | Assume account compromise; investigate within 15 minutes |
/etc/shadow modification | CRITICAL | Auto-incident, immediate | Assume credential theft; reset all passwords, isolate host |
/etc/sudoers or sudoers.d/ modification | CRITICAL | Auto-incident, immediate | Privilege escalation attempt; isolate host |
| System binary replacement (hash change) | CRITICAL | Auto-incident, immediate | Assume supply chain / rootkit; isolate host, forensic analysis |
C:\Windows\System32\ file created or replaced | HIGH | Auto-incident via SecurityAgent | Check SHA256 against known-good; escalate if hash unknown |
Driver file added to System32\drivers\ | CRITICAL | Auto-incident, immediate | Kernel rootkit risk; isolate and forensic analysis |
| Log cleared (EventID 1102) | CRITICAL | Auto-incident, immediate | Defense evasion in progress; treat as active incident |
| Scheduled task XML modified | HIGH | Auto-incident | Persistence mechanism — verify against CM |
| Service binary path changed | HIGH | Auto-incident | Service hijack risk — verify against CM |
| SSH config modification | HIGH | Auto-incident | Backdoor risk — verify change is authorized |
/etc/hosts modification | MEDIUM | Log + monthly review | DNS hijack risk — review at monthly security review |
| Kernel module load/unload | MEDIUM | Log + weekly review | Routine on patch cycles; investigate if outside patch window |
HKCU\Run change (user context) | MEDIUM | Log + weekly review | Per-user persistence — less critical than HKLM |
Program Files modification | LOW | Log + monthly review | Application updates — correlate with patch logs |
SecOps Integration
The persistence agent (Kill Chain Phase 2) is the primary automated responder. It watches EventID 7045 (new service), 4698 (new scheduled task), and DeviceRegistryEvents for Run key changes. When a FIM event fires outside a CM window, SecurityAgent creates a HIGH or CRITICAL incident.
CM window check: Any FIM alert that fires should be cross-referenced with the CM ticket API:
GET /api/changes/recentIf a CM ticket exists and was approved within the prior 2-hour window, the alert is suppressed. Otherwise, the incident is created.
Part 8 — HIPAA Auditor Evidence Package
When an auditor asks "how do you satisfy HIPAA §164.312(c)(1)?", pull this package.
8.1 — Evidence to Produce
| Evidence Item | Source | How to Pull |
|---|---|---|
| MDE enrollment roster | M365 Defender → Endpoints → Device Inventory | Export CSV |
| DeviceFileEvents sample (last 30 days) | M365 Defender Advanced Hunting | Run query from Part 1.1, export CSV |
| DeviceRegistryEvents sample (last 30 days) | M365 Defender Advanced Hunting | Run Run-key query from Part 1.1, export CSV |
| ConfigurationChange events (last 30 days) | LAW → KQL | Run Part 4.2 queries, export CSV |
| Velociraptor FIM hunt schedule screenshot | Velociraptor GUI → Hunt Manager | Screenshot + export results CSV |
| auditd ruleset per Linux VM | VM or Velociraptor collection | auditctl -l output per host |
| auditd events in LAW (last 30 days) | LAW → Syslog KQL | Run Part 5.3 queries, export CSV |
| Defender for Cloud FIM configuration screenshot | Azure Portal → Defender for Cloud | Screenshot showing FIM enabled, monitored paths |
| DfC FIM plan status | Azure Portal or CLI output | az security pricing list output |
| SecOps FIM incident history | SecOps platform → Incidents, filter tag=fim | Export incidents with RESOLVED status |
8.2 — Control Narrative (Include in Evidence Package)
HIPAA §164.312(c)(1) — Integrity: Implement policies and procedures to protect
electronic protected health information from improper alteration or destruction.
Cirius Group satisfies this control through four complementary FIM layers:
1. Microsoft Defender for Endpoint (MDE) monitors file and registry changes across
all Windows endpoints via DeviceFileEvents and DeviceRegistryEvents, forwarded to
the central Log Analytics workspace cirius-logging-law-central.
2. Azure Monitor Agent with Sysmon (where deployed) captures granular file creation
and registry change events (EventID 11, 13) forwarding to LAW SecurityEvent / Event
tables via Data Collection Rules.
3. Velociraptor DFIR platform runs scheduled FIM artifacts performing SHA256 hash
verification of critical system binaries against a known-good baseline, with results
retained in the Velociraptor server and exportable on demand.
4. Microsoft Defender for Cloud (Servers Plan 2) monitors Azure VM file system,
registry, and service changes via the ConfigurationChange table in LAW.
All Linux Azure VMs run auditd with the Cirius standard ruleset (-w watch rules for
/etc/passwd, /etc/shadow, /etc/sudoers, /etc/ssh/sshd_config, /etc/systemd/system/,
and critical system binaries), forwarded to LAW via AMA Syslog collection.
Alerts for high-severity FIM events (system binary replacement, passwd modification,
run-key addition outside change window) are automatically escalated to the SecOps
platform as HIGH or CRITICAL incidents with a 15-minute SLA for investigation.8.3 — Register Evidence in SecOps
After pulling the evidence package:
bash
curl -X POST https://soc.bedrockcybersecurity.org/api/evidence \
-H "X-API-Key: <key-from-keyvault>" \
-H "Content-Type: application/json" \
-d '{
"evidence_type": "fim_audit",
"control_reference": "HIPAA-164.312-c-1",
"description": "FIM coverage evidence — MDE, DfC, Velociraptor, auditd — 30-day window",
"s3_path": "s3://cirius-compliance-evidence/fim/<date>/",
"collected_at": "<ISO-8601-timestamp>"
}'Part 9 — Monthly FIM Coverage Verification Checklist
Run this on the first Monday of each month alongside the standard monthly security review (monthly-security-review.md).
Estimated time: 30 minutes
Layer 1 — MDE
- [ ] Open M365 Defender → Endpoints → Device Inventory
- Confirm zero devices show "No sensor data" or "Inactive" status
- Any inactive device: investigate and re-enroll or document as decommissioned
- [ ] Run the DeviceFileEvents and DeviceRegistryEvents queries from Part 1.1 in Advanced Hunting — confirm all enrolled devices have events in the last 24 hours
- [ ] Spot-check 5 random devices — confirm Last Seen within 4 hours
Layer 2 — AMA + Sysmon
- [ ] Run the Heartbeat query from Part 2.1 — confirm zero Windows VMs have missed heartbeat in last 4 hours
- [ ] Run the Sysmon event count query from Part 2.1 — confirm Sysmon events are flowing from all hosts where Sysmon is deployed
- [ ] Confirm DCR configuration has not drifted: Azure Portal → Monitor → Data Collection Rules → verify Sysmon XPath filter is present
Layer 3 — Velociraptor
- [ ] Log into
https://velociraptor.ciriusgroup.com - [ ] Hunt Manager → confirm last scheduled FIM hunt completed successfully (green status, no errors)
- [ ] Confirm the next hunt is scheduled within 7 days
- [ ] Review any CHANGED results from the most recent hash-verification hunt — document expected changes (patching) vs. unexpected changes (escalate)
Layer 4 — Defender for Cloud FIM
- [ ] Run the ConfigurationChange gap query from Part 6.3 — confirm zero VMs are missing from FIM reporting
- [ ] Portal: Defender for Cloud → Workload Protections → File Integrity Monitoring → confirm status is ON for both PROD and DDE subscriptions
- [ ] Review ConfigurationChange events from the past 30 days for any CRITICAL paths — run the file change query from Part 4.2
Linux auditd
- [ ] Run the Linux gap query from Part 6.2 — confirm zero Linux VMs are missing auditd events in LAW
- [ ] SSH to a sample Linux VM and run:bashConfirm auditd is active and rule count matches expected (30+ rules)
systemctl is-active auditd auditctl -l | wc -l
Alert Health
- [ ] SecOps platform → Incidents → filter by tag
fimor source containingfim→ review all FIM-triggered incidents from the past 30 days - [ ] Confirm all HIGH/CRITICAL FIM incidents were resolved within SLA
- [ ] Confirm no FIM coverage gap incidents remain OPEN
Documentation
- [ ] If any gap was found and resolved this month, update the coverage matrix at the top of this runbook
- [ ] Log the monthly verification date and outcome in SecOps as evidence:
POST /api/evidence with evidence_type: "fim_monthly_verification"
Appendix A — Quick Troubleshooting
No DeviceFileEvents in MDE Advanced Hunting
- Confirm the device appears in Endpoints → Device Inventory
- Check MDE sensor status: Endpoints → Device Inventory → select device → Device health
- If sensor is "Inactive": run the MDE onboarding script manually on the endpoint
- If sensor is "Active" but no events: check if file activity has actually occurred (idle machines may have sparse DeviceFileEvents — DeviceRegistryEvents are higher volume)
No events in ConfigurationChange table
- Confirm Defender for Servers Plan 2 is enabled:
az security pricing list - Confirm FIM is toggled ON in Defender for Cloud → Environment Settings → Servers → FIM
- Confirm AMA is installed on the VM: Azure Portal → VM → Extensions
- Wait up to 24 hours after enabling — FIM events are not real-time, they are collected on a periodic scan cycle (default: every 30 minutes)
auditd events not in LAW Syslog table
- Confirm AMA is installed and healthy: check Heartbeat table for the Linux host
- Confirm the AMA DCR includes Syslog with facility
daemonandauth(minimum) - Confirm auditd is configured to send to syslog: check
/etc/audisp/plugins.d/syslog.conf—active = yesmust be set - Restart auditd and the audit dispatcher:
systemctl restart auditd - Test:
touch /etc/hosts.test && rm /etc/hosts.testthen check Syslog in LAW
Sysmon events not in Event table
- Confirm Sysmon is installed:
sc query sysmon64on the endpoint - Confirm the AMA DCR includes the XPath for
Microsoft-Windows-Sysmon/Operational - Check if the DCR is using
Microsoft-Eventstream (correct for non-Sentinel LAW) vs.Microsoft-SecurityEvent— Sysmon goes throughMicrosoft-Event - Verify in LAW:
Event | where Source == "Microsoft-Windows-Sysmon" | take 1
Appendix B — Related Runbooks
| Runbook | Relevance |
|---|---|
| mde-passive-mode.md | MDE Passive Mode enforcement — required alongside Cortex XDR |
| cortex-xdr-operations.md | Primary EDR operations — behavioral detections complement FIM |
| kill-chain-phase1-enablement.md | Windows event collection (4688, 7045, 4698) — shares AMA pipeline |
| velociraptor-operations.md | Full Velociraptor operator guide — artifact authoring, hunt management |
| azure-policy-compliance.md | Defender for Cloud policy posture — FIM requires Plan 2 |
| log-retention-verification.md | 6-year log retention verification — FIM evidence must be archived |
| monthly-security-review.md | Monthly security checklist — FIM section references this runbook |
| kql-query-reference.md | Master KQL reference for LAW queries |