Defense Impairment
T1685 — Disable or Modify Tools
Adversaries may disable, degrade, or tamper with security tools -- EDR, antivirus, logging agents, sensors -- to impair or reduce visibility of defensive capabilities. This also includes blocking or manipulating the indicators and telemetry those tools rely on for detection, not just disabling the tool itself. Formerly tracked as "Impair Defenses" (T1562), renamed and moved to the Defense Impairment tactic.
Any tampering with security controls (EDR uninstall/exclusion, log clearing, firewall or Conditional Access policy change) should be treated as a high-confidence indicator of active, deliberate intrusion rather than routine administration, because legitimate reasons to disable these controls are rare and should already be tracked as changes.
Platforms
Windows, Linux, macOS, Azure AD, Office 365
Priority / status
high / complete
Evidence to collect
- Host or tenant affected
- Control disabled/modified
- Initiating process, user, or service principal
- Timestamp of change
- Prior and current configuration state
D3-EHB · detect
Endpoint Health Beacon
Detect when an EDR/monitoring agent stops reporting or heartbeats irregularly -- often the first visible sign a security tool was disabled or tampered with.
Tooling: Defender for Endpoint
D3-SICA · detect
System Init Config Analysis
Detect changes to startup/init configuration used to disable or block security agents from launching.
Tooling: Sentinel, Defender for Endpoint
D3-RC · restore
Restore Configuration
Re-enable or restore the security control's configuration once tampering is confirmed.
Tooling: Defender for Endpoint, Entra ID
D3-SCF · isolate
System Call Filtering
Apply tamper protection / system call filtering so security agents cannot be stopped or reconfigured by unauthorized processes.
Tooling: Defender for Endpoint
| ATT&CK Technique | D3FEND Technique | Practical SOC Action | Tooling |
|---|---|---|---|
| T1685 Disable or Modify Tools | Endpoint Health Beacon | Detect when an EDR/monitoring agent stops reporting or heartbeats irregularly -- often the first visible sign a security tool was disabled or tampered with. | Defender for Endpoint |
| T1685 Disable or Modify Tools | System Init Config Analysis | Detect changes to startup/init configuration used to disable or block security agents from launching. | Sentinel, Defender for Endpoint |
| T1685 Disable or Modify Tools | Restore Configuration | Re-enable or restore the security control's configuration once tampering is confirmed. | Defender for Endpoint, Entra ID |
| T1685 Disable or Modify Tools | System Call Filtering | Apply tamper protection / system call filtering so security agents cannot be stopped or reconfigured by unauthorized processes. | Defender for Endpoint |
T1685 Disable or Modify Tools → D3FEND → SOC action
Investigation steps — Microsoft
- If PowerShell ran Set-MpPreference: trace back to what ran the PowerShell (GEN-EX-001 pattern)
- If a registry modification by an unsigned process: the process is the malware dropper
Investigation steps — generic
- Identify exactly which control was disabled, weakened, or had logs cleared.
- Determine who or what process made the change and from where.
- Check whether other defense-impairment or execution activity occurred around the same time.
- Real detection reference: "Defender Sensor Disabled" -- Flags Windows Defender real-time protection, AMSI, or the MDE sensor being disabled via registry modification or Set-MpPreference. Attackers disable security tooling immediately before deploying malware. Zero tolerance - never suppress.
Response actions
| Action | Risk | Automation safe | Approval required |
|---|---|---|---|
| Re-enable Defender real-time protection via MDE portal | Low | No | Yes |
| If malicious binary detected during the blind window: isolat | Medium | No | Yes |
| Ensure Tamper Protection is enabled to prevent recurrence | Low | No | Yes |
| Enable Tamper Protection on ALL customer endpoints via MDE p | Low | No | Yes |
| Review all processes run during the Defender-disabled window | Medium | No | Yes |
| Submit unknown hashes to Microsoft Defender Threat Intellige | Low | Yes | No |
KQL
GEN-DE-001 — Defender Sensor Disabled
let DefenderRegistryMods = (
DeviceRegistryEvents
| where TimeGenerated >= ago(5m)
| where RegistryKey has_any (
"Windows Defender\\Real-Time Protection\\DisableRealtimeMonitoring",
"Windows Defender\\DisableAntiSpyware",
"Windows Defender\\DisableAntiVirus",
"Windows Defender\\Features\\TamperProtection",
"Windows Defender\\Real-Time Protection\\DisableBehaviorMonitoring",
"Windows Defender\\Real-Time Protection\\DisableIOAVProtection",
"Windows Defender\\Real-Time Protection\\DisableScriptScanning",
"SENSE\\Start"
)
| where RegistryValueData == "1" or RegistryValueData == "4"
| project TimeGenerated, DeviceName, AccountName, RegistryKey, RegistryValueName, RegistryValueData,
InitiatingProcessFileName, InitiatingProcessSHA256
);
let DefenderPSMods = (
DeviceProcessEvents
| where TimeGenerated >= ago(5m)
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has "Set-MpPreference"
| where ProcessCommandLine has_any (
"DisableRealtimeMonitoring", "DisableIOAVProtection",
"DisableBehaviorMonitoring", "DisableAntiSpyware",
"ExclusionPath", "ExclusionExtension", "ExclusionProcess"
)
| project TimeGenerated, DeviceName, AccountName, RegistryKey = "", RegistryValueName = ProcessCommandLine,
RegistryValueData = "", InitiatingProcessFileName, InitiatingProcessSHA256 = SHA256
);
DefenderRegistryMods
| union DefenderPSMods
| extend timestamp = TimeGenerated,
HostCustomEntity = DeviceName,
AccountCustomEntity = AccountName
| order by TimeGenerated desc 473d57e6-f787-435c-a16b-b38b51fa9a4b — Security Service Registry ACL Modification
let servicelist = dynamic(['Services\\HealthService', 'Services\\Sense', 'Services\\WinDefend', 'Services\\MsSecFlt', 'Services\\DiagTrack', 'Services\\SgrmBroker', 'Services\\SgrmAgent', 'Services\\AATPSensorUpdater' , 'Services\\AATPSensor', 'Services\\mpssvc']);
let filename = dynamic(["subinacl.exe",'SetACL.exe']);
let parameters = dynamic (['/deny=SYSTEM', '/deny=S-1-5-18', '/grant=SYSTEM=r', '/grant=S-1-5-18=r', 'n:SYSTEM;p:READ', 'n1:SYSTEM;ta:remtrst;w:dacl']);
let FullAccess = dynamic(['A;CI;KA;;;SY', 'A;ID;KA;;;SY', 'A;CIID;KA;;;SY']);
let ReadAccess = dynamic(['A;CI;KR;;;SY', 'A;ID;KR;;;SY', 'A;CIID;KR;;;SY']);
let DenyAccess = dynamic(['D;CI;KR;;;SY', 'D;ID;KR;;;SY', 'D;CIID;KR;;;SY']);
let timeframe = 1d;
(union isfuzzy=true
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4670
| where ObjectType == 'Key'
| where ObjectName has_any (servicelist)
| parse EventData with * 'OldSd">' OldSd "<" *
| parse EventData with * 'NewSd">' NewSd "<" *
| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')
| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason
),
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688
| extend ProcessName = tostring(split(NewProcessName, '\\')[-1])
| where ProcessName in~ (filename)
| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type
),
(
WindowsEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4670 and EventData has_any (servicelist) and EventData has 'Key'
| extend ObjectType = tostring(EventData.ObjectType)
| where ObjectType == 'Key'
| extend ObjectName = tostring(EventData.ObjectName)
| where ObjectName has_any (servicelist)
| extend OldSd = tostring(EventData.OldSd)
| extend NewSd = tostring(EventData.NewSd)
| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend ProcessName = tostring(EventData.ProcessName)
| extend ProcessId = tostring(EventData.ProcessId)
| extend Activity= "4670 - Permissions on an object were changed."
| extend HandleId = tostring(EventData.HandleId)
| extend SubjectLogonId = tostring(EventData.SubjectLogonId)
| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason
),
(
WindowsEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688 and EventData has_any (filename) and EventData has_any (servicelist) and EventData has_any (parameters)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend ProcessName = tostring(split(NewProcessName, '\\')[-1])
| where ProcessName in~ (filename)
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountDomain = tostring(EventData.AccountDomain)
| extend Activity="4688 - A new process has been created."
| extend EventSourceName=Provider
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type
),
(
DeviceProcessEvents
| where TimeGenerated >= ago(timeframe)
| where InitiatingProcessFileName in~ (filename)
| where InitiatingProcessCommandLine has_any(servicelist) and InitiatingProcessCommandLine has_any (parameters)
| extend Account = iff(isnotempty(InitiatingProcessAccountUpn), InitiatingProcessAccountUpn, InitiatingProcessAccountName), Computer = DeviceName
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName = InitiatingProcessFileName, ProcessNameFullPath = FolderPath, Activity = ActionType, CommandLine = InitiatingProcessCommandLine, Type, InitiatingProcessParentFileName
)
)
| extend AccountName = tostring(split(Account, "\\")[0]), AccountNTDomain = tostring(split(Account, "\\")[1])
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) 9da99021-d318-4711-a78a-6dea76129b3a — AWSCloudTrail - AWS GuardDuty detector disabled or suspended
AWSCloudTrail
| where (EventName == "DeleteDetector" and isempty(ErrorCode) and isempty( ErrorMessage)) or (EventName == "UpdateDetector" and tostring(parse_json(RequestParameters).enable) == "false" and isempty(ErrorCode) and isempty( ErrorMessage))
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "") Escalation criteria
- EDR/antivirus tamper protection was bypassed successfully.
- Security event logs were cleared.
- Conditional Access or tenant security policy was weakened.
- Change occurred on a server holding sensitive data or privileged access.
False positive considerations
- Approved maintenance window disabling AV for a software deployment.
- Legitimate security tooling migration/replacement project.
- Scheduled log rotation misidentified as log clearing.
# T1685 - Disable or Modify Tools
## SOC Recommendation
Any tampering with security controls (EDR uninstall/exclusion, log clearing, firewall or Conditional Access policy change) should be treated as a high-confidence indicator of active, deliberate intrusion rather than routine administration, because legitimate reasons to disable these controls are rare and should already be tracked as changes.
## D3FEND Mappings
| D3FEND Technique | Relationship | Practical SOC Action |
|---|---|---|
| Endpoint Health Beacon | Detect | Detect when an EDR/monitoring agent stops reporting or heartbeats irregularly -- often the first visible sign a security tool was disabled or tampered with. |
| System Init Config Analysis | Detect | Detect changes to startup/init configuration used to disable or block security agents from launching. |
| Restore Configuration | Restore | Re-enable or restore the security control's configuration once tampering is confirmed. |
| System Call Filtering | Isolate | Apply tamper protection / system call filtering so security agents cannot be stopped or reconfigured by unauthorized processes. |
## Investigation Steps
1. If PowerShell ran Set-MpPreference: trace back to what ran the PowerShell (GEN-EX-001 pattern)
2. If a registry modification by an unsigned process: the process is the malware dropper
## Evidence to Collect
- Host or tenant affected
- Control disabled/modified
- Initiating process, user, or service principal
- Timestamp of change
- Prior and current configuration state
## Response Actions
| Action | Risk | Automation Safe | Approval Required |
|---|---|---|---|
| Re-enable Defender real-time protection via MDE portal | Low | No | Yes |
| If malicious binary detected during the blind window: isolat | Medium | No | Yes |
| Ensure Tamper Protection is enabled to prevent recurrence | Low | No | Yes |
| Enable Tamper Protection on ALL customer endpoints via MDE p | Low | No | Yes |
| Review all processes run during the Defender-disabled window | Medium | No | Yes |
| Submit unknown hashes to Microsoft Defender Threat Intellige | Low | Yes | No |
## KQL
```kql
let DefenderRegistryMods = (
DeviceRegistryEvents
| where TimeGenerated >= ago(5m)
| where RegistryKey has_any (
"Windows Defender\\Real-Time Protection\\DisableRealtimeMonitoring",
"Windows Defender\\DisableAntiSpyware",
"Windows Defender\\DisableAntiVirus",
"Windows Defender\\Features\\TamperProtection",
"Windows Defender\\Real-Time Protection\\DisableBehaviorMonitoring",
"Windows Defender\\Real-Time Protection\\DisableIOAVProtection",
"Windows Defender\\Real-Time Protection\\DisableScriptScanning",
"SENSE\\Start"
)
| where RegistryValueData == "1" or RegistryValueData == "4"
| project TimeGenerated, DeviceName, AccountName, RegistryKey, RegistryValueName, RegistryValueData,
InitiatingProcessFileName, InitiatingProcessSHA256
);
let DefenderPSMods = (
DeviceProcessEvents
| where TimeGenerated >= ago(5m)
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has "Set-MpPreference"
| where ProcessCommandLine has_any (
"DisableRealtimeMonitoring", "DisableIOAVProtection",
"DisableBehaviorMonitoring", "DisableAntiSpyware",
"ExclusionPath", "ExclusionExtension", "ExclusionProcess"
)
| project TimeGenerated, DeviceName, AccountName, RegistryKey = "", RegistryValueName = ProcessCommandLine,
RegistryValueData = "", InitiatingProcessFileName, InitiatingProcessSHA256 = SHA256
);
DefenderRegistryMods
| union DefenderPSMods
| extend timestamp = TimeGenerated,
HostCustomEntity = DeviceName,
AccountCustomEntity = AccountName
| order by TimeGenerated desc
```
```kql
let servicelist = dynamic(['Services\\HealthService', 'Services\\Sense', 'Services\\WinDefend', 'Services\\MsSecFlt', 'Services\\DiagTrack', 'Services\\SgrmBroker', 'Services\\SgrmAgent', 'Services\\AATPSensorUpdater' , 'Services\\AATPSensor', 'Services\\mpssvc']);
let filename = dynamic(["subinacl.exe",'SetACL.exe']);
let parameters = dynamic (['/deny=SYSTEM', '/deny=S-1-5-18', '/grant=SYSTEM=r', '/grant=S-1-5-18=r', 'n:SYSTEM;p:READ', 'n1:SYSTEM;ta:remtrst;w:dacl']);
let FullAccess = dynamic(['A;CI;KA;;;SY', 'A;ID;KA;;;SY', 'A;CIID;KA;;;SY']);
let ReadAccess = dynamic(['A;CI;KR;;;SY', 'A;ID;KR;;;SY', 'A;CIID;KR;;;SY']);
let DenyAccess = dynamic(['D;CI;KR;;;SY', 'D;ID;KR;;;SY', 'D;CIID;KR;;;SY']);
let timeframe = 1d;
(union isfuzzy=true
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4670
| where ObjectType == 'Key'
| where ObjectName has_any (servicelist)
| parse EventData with * 'OldSd">' OldSd "<" *
| parse EventData with * 'NewSd">' NewSd "<" *
| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')
| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason
),
(
SecurityEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688
| extend ProcessName = tostring(split(NewProcessName, '\\')[-1])
| where ProcessName in~ (filename)
| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type
),
(
WindowsEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4670 and EventData has_any (servicelist) and EventData has 'Key'
| extend ObjectType = tostring(EventData.ObjectType)
| where ObjectType == 'Key'
| extend ObjectName = tostring(EventData.ObjectName)
| where ObjectName has_any (servicelist)
| extend OldSd = tostring(EventData.OldSd)
| extend NewSd = tostring(EventData.NewSd)
| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend ProcessName = tostring(EventData.ProcessName)
| extend ProcessId = tostring(EventData.ProcessId)
| extend Activity= "4670 - Permissions on an object were changed."
| extend HandleId = tostring(EventData.HandleId)
| extend SubjectLogonId = tostring(EventData.SubjectLogonId)
| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason
),
(
WindowsEvent
| where TimeGenerated >= ago(timeframe)
| where EventID == 4688 and EventData has_any (filename) and EventData has_any (servicelist) and EventData has_any (parameters)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend ProcessName = tostring(split(NewProcessName, '\\')[-1])
| where ProcessName in~ (filename)
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountDomain = tostring(EventData.AccountDomain)
| extend Activity="4688 - A new process has been created."
| extend EventSourceName=Provider
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type
),
(
DeviceProcessEvents
| where TimeGenerated >= ago(timeframe)
| where InitiatingProcessFileName in~ (filename)
| where InitiatingProcessCommandLine has_any(servicelist) and InitiatingProcessCommandLine has_any (parameters)
| extend Account = iff(isnotempty(InitiatingProcessAccountUpn), InitiatingProcessAccountUpn, InitiatingProcessAccountName), Computer = DeviceName
| project TimeGenerated, Computer, Account, AccountDomain, ProcessName = InitiatingProcessFileName, ProcessNameFullPath = FolderPath, Activity = ActionType, CommandLine = InitiatingProcessCommandLine, Type, InitiatingProcessParentFileName
)
)
| extend AccountName = tostring(split(Account, "\\")[0]), AccountNTDomain = tostring(split(Account, "\\")[1])
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
```
```kql
AWSCloudTrail
| where (EventName == "DeleteDetector" and isempty(ErrorCode) and isempty( ErrorMessage)) or (EventName == "UpdateDetector" and tostring(parse_json(RequestParameters).enable) == "false" and isempty(ErrorCode) and isempty( ErrorMessage))
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
```
## Escalation Criteria
- EDR/antivirus tamper protection was bypassed successfully.
- Security event logs were cleared.
- Conditional Access or tenant security policy was weakened.
- Change occurred on a server holding sensitive data or privileged access.
## False Positive Considerations
- Approved maintenance window disabling AV for a software deployment.
- Legitimate security tooling migration/replacement project.
- Scheduled log rotation misidentified as log clearing.
Generated by SOC Response Atlas by Basyrix.
Want to push this directly to Confluence? Upgrade to Basyrix Pro.
- /api/techniques/T1685.json
- /api/recommendations/T1685.json
- /api/d3fend/T1685.json
- /api/mappings/T1685.json
- /api/confluence/T1685.md
Example curl:
curl https://atlas.basyrix.com/api/recommendations/T1685.json Response:
{
"technique_id": "T1685",
"name": "Disable or Modify Tools",
"priority": "high",
"status": "complete",
"version": "0.1.0",
"last_reviewed": "2026-07-23",
"generated_by": "SOC Response Atlas by Basyrix",
"tactics": [
"Defense Impairment"
],
"platforms": [
"Windows",
"Linux",
"macOS",
"Azure AD",
"Office 365"
],
"summary": "Adversaries may disable, degrade, or tamper with security tools -- EDR, antivirus, logging agents, sensors -- to impair or reduce visibility of defensive capabilities. This also includes blocking or manipulating the indicators and telemetry those tools rely on for detection, not just disabling the tool itself. Formerly tracked as \"Impair Defenses\" (T1562), renamed and moved to the Defense Impairment tactic.\n",
"soc_recommendation": "Any tampering with security controls (EDR uninstall/exclusion, log clearing, firewall or Conditional Access policy change) should be treated as a high-confidence indicator of active, deliberate intrusion rather than routine administration, because legitimate reasons to disable these controls are rare and should already be tracked as changes.\n",
"d3fend_mappings": [
{
"id": "D3-EHB",
"name": "Endpoint Health Beacon",
"relationship": "detect",
"practical_action": "Detect when an EDR/monitoring agent stops reporting or heartbeats irregularly -- often the first visible sign a security tool was disabled or tampered with.\n",
"tooling": [
"Defender for Endpoint"
]
},
{
"id": "D3-SICA",
"name": "System Init Config Analysis",
"relationship": "detect",
"practical_action": "Detect changes to startup/init configuration used to disable or block security agents from launching.\n",
"tooling": [
"Sentinel",
"Defender for Endpoint"
]
},
{
"id": "D3-RC",
"name": "Restore Configuration",
"relationship": "restore",
"practical_action": "Re-enable or restore the security control's configuration once tampering is confirmed.\n",
"tooling": [
"Defender for Endpoint",
"Entra ID"
]
},
{
"id": "D3-SCF",
"name": "System Call Filtering",
"relationship": "isolate",
"practical_action": "Apply tamper protection / system call filtering so security agents cannot be stopped or reconfigured by unauthorized processes.\n",
"tooling": [
"Defender for Endpoint"
]
}
],
"investigation_steps": {
"microsoft": [
"If PowerShell ran Set-MpPreference: trace back to what ran the PowerShell (GEN-EX-001 pattern)",
"If a registry modification by an unsigned process: the process is the malware dropper"
],
"generic": [
"Identify exactly which control was disabled, weakened, or had logs cleared.",
"Determine who or what process made the change and from where.",
"Check whether other defense-impairment or execution activity occurred around the same time.",
"Real detection reference: \"Defender Sensor Disabled\" -- Flags Windows Defender real-time protection, AMSI, or the MDE sensor being disabled via registry modification or Set-MpPreference. Attackers disable security tooling immediately before deploying malware. Zero tolerance - never suppress."
]
},
"evidence_to_collect": [
"Host or tenant affected",
"Control disabled/modified",
"Initiating process, user, or service principal",
"Timestamp of change",
"Prior and current configuration state"
],
"response_actions": [
{
"name": "Re-enable Defender real-time protection via MDE portal",
"category": "Containment",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "Defender for Endpoint"
},
{
"name": "If malicious binary detected during the blind window: isolat",
"category": "Containment",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide",
"notes": "If malicious binary detected during the blind window: isolate the device"
},
{
"name": "Ensure Tamper Protection is enabled to prevent recurrence",
"category": "Containment",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "Enable Tamper Protection on ALL customer endpoints via MDE p",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "Defender for Endpoint",
"notes": "Enable Tamper Protection on ALL customer endpoints via MDE policy"
},
{
"name": "Review all processes run during the Defender-disabled window",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "Submit unknown hashes to Microsoft Defender Threat Intellige",
"category": "Response",
"risk": "Low",
"automation_safe": true,
"approval_required": false,
"tool": "See investigation guide",
"notes": "Submit unknown hashes to Microsoft Defender Threat Intelligence"
}
],
"queries": {
"kql": [
{
"name": "GEN-DE-001 — Defender Sensor Disabled",
"description": "Flags Windows Defender real-time protection, AMSI, or the MDE sensor being disabled via registry modification or Set-MpPreference. Attackers disable security tooling immediately before deploying malware. Zero tolerance - never suppress. (Source: Bell Integration baseline detection library, mapped via sub-technique T1562.001.)",
"query": "let DefenderRegistryMods = (\n DeviceRegistryEvents\n | where TimeGenerated >= ago(5m)\n | where RegistryKey has_any (\n \"Windows Defender\\\\Real-Time Protection\\\\DisableRealtimeMonitoring\",\n \"Windows Defender\\\\DisableAntiSpyware\",\n \"Windows Defender\\\\DisableAntiVirus\",\n \"Windows Defender\\\\Features\\\\TamperProtection\",\n \"Windows Defender\\\\Real-Time Protection\\\\DisableBehaviorMonitoring\",\n \"Windows Defender\\\\Real-Time Protection\\\\DisableIOAVProtection\",\n \"Windows Defender\\\\Real-Time Protection\\\\DisableScriptScanning\",\n \"SENSE\\\\Start\"\n )\n | where RegistryValueData == \"1\" or RegistryValueData == \"4\"\n | project TimeGenerated, DeviceName, AccountName, RegistryKey, RegistryValueName, RegistryValueData,\n InitiatingProcessFileName, InitiatingProcessSHA256\n);\nlet DefenderPSMods = (\n DeviceProcessEvents\n | where TimeGenerated >= ago(5m)\n | where FileName =~ \"powershell.exe\"\n | where ProcessCommandLine has \"Set-MpPreference\"\n | where ProcessCommandLine has_any (\n \"DisableRealtimeMonitoring\", \"DisableIOAVProtection\",\n \"DisableBehaviorMonitoring\", \"DisableAntiSpyware\",\n \"ExclusionPath\", \"ExclusionExtension\", \"ExclusionProcess\"\n )\n | project TimeGenerated, DeviceName, AccountName, RegistryKey = \"\", RegistryValueName = ProcessCommandLine,\n RegistryValueData = \"\", InitiatingProcessFileName, InitiatingProcessSHA256 = SHA256\n);\nDefenderRegistryMods\n| union DefenderPSMods\n| extend timestamp = TimeGenerated,\n HostCustomEntity = DeviceName,\n AccountCustomEntity = AccountName\n| order by TimeGenerated desc"
},
{
"name": "473d57e6-f787-435c-a16b-b38b51fa9a4b — Security Service Registry ACL Modification",
"description": "Identifies attempts to modify registry ACL to evade security solutions. In the Solorigate attack, the attackers were found modifying registry permissions so services.exe cannot access the relevant registry keys to start the service. The detection leverages Security Event as well as MDE data to identify when specific security services registry permissions are modified. Only some portions of this detection are related to Solorigate, it also includes coverage for some common tools that perform this activity. Reference on guidance for enabling registry auditing: - https://docs.microsoft.com/windows/security/threat-protection/auditing/advanced-security-auditing-faq - https://docs.microsoft.com/windows/security/threat-protection/auditing/appendix-a-security-monitoring-recommendations-for-many-audit-events - https://docs.microsoft.com/windows/security/threat-protection/auditing/audit-registry - https://docs.microsoft.com/windows/security/threat-protection/auditing/event-4670 - For the event 4670 to be created the audit policy for the registry must have auditing enabled for Write DAC and/or Write Owner - https://github.com/OTRF/Set-AuditRule - https://docs.microsoft.com/dotnet/api/system.security.accesscontrol.registryrights?view=dotnet-plat-ext-5.0' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed), mapped via sub-technique T1562.)",
"query": "let servicelist = dynamic(['Services\\\\HealthService', 'Services\\\\Sense', 'Services\\\\WinDefend', 'Services\\\\MsSecFlt', 'Services\\\\DiagTrack', 'Services\\\\SgrmBroker', 'Services\\\\SgrmAgent', 'Services\\\\AATPSensorUpdater' , 'Services\\\\AATPSensor', 'Services\\\\mpssvc']);\nlet filename = dynamic([\"subinacl.exe\",'SetACL.exe']);\nlet parameters = dynamic (['/deny=SYSTEM', '/deny=S-1-5-18', '/grant=SYSTEM=r', '/grant=S-1-5-18=r', 'n:SYSTEM;p:READ', 'n1:SYSTEM;ta:remtrst;w:dacl']);\nlet FullAccess = dynamic(['A;CI;KA;;;SY', 'A;ID;KA;;;SY', 'A;CIID;KA;;;SY']);\nlet ReadAccess = dynamic(['A;CI;KR;;;SY', 'A;ID;KR;;;SY', 'A;CIID;KR;;;SY']);\nlet DenyAccess = dynamic(['D;CI;KR;;;SY', 'D;ID;KR;;;SY', 'D;CIID;KR;;;SY']);\nlet timeframe = 1d;\n(union isfuzzy=true\n(\nSecurityEvent\n| where TimeGenerated >= ago(timeframe)\n| where EventID == 4670\n| where ObjectType == 'Key'\n| where ObjectName has_any (servicelist)\n| parse EventData with * 'OldSd\">' OldSd \"<\" *\n| parse EventData with * 'NewSd\">' NewSd \"<\" *\n| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')\n| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason\n),\n(\nSecurityEvent\n| where TimeGenerated >= ago(timeframe)\n| where EventID == 4688\n| extend ProcessName = tostring(split(NewProcessName, '\\\\')[-1])\n| where ProcessName in~ (filename)\n| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)\n| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type\n),\n(\nWindowsEvent\n| where TimeGenerated >= ago(timeframe)\n| where EventID == 4670 and EventData has_any (servicelist) and EventData has 'Key'\n| extend ObjectType = tostring(EventData.ObjectType)\n| where ObjectType == 'Key'\n| extend ObjectName = tostring(EventData.ObjectName)\n| where ObjectName has_any (servicelist)\n| extend OldSd = tostring(EventData.OldSd)\n| extend NewSd = tostring(EventData.NewSd)\n| extend Reason = case( (OldSd has ';;;SY' and NewSd !has ';;;SY'), 'System Account is removed', (OldSd has_any (FullAccess) and NewSd has_any (ReadAccess)) , 'System permission has been changed to read from full access', (OldSd has_any (FullAccess) and NewSd has_any (DenyAccess)), 'System account has been given denied permission', 'None')\n| extend Account = strcat(tostring(EventData.SubjectDomainName),\"\\\\\", tostring(EventData.SubjectUserName))\n| extend ProcessName = tostring(EventData.ProcessName)\n| extend ProcessId = tostring(EventData.ProcessId)\n| extend Activity= \"4670 - Permissions on an object were changed.\"\n| extend HandleId = tostring(EventData.HandleId)\n| extend SubjectLogonId = tostring(EventData.SubjectLogonId)\n| project TimeGenerated, Computer, Account, ProcessName, ProcessId, ObjectName, EventData, Activity, HandleId, SubjectLogonId, OldSd, NewSd , Reason\n),\n(\nWindowsEvent\n| where TimeGenerated >= ago(timeframe)\n| where EventID == 4688 and EventData has_any (filename) and EventData has_any (servicelist) and EventData has_any (parameters)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend ProcessName = tostring(split(NewProcessName, '\\\\')[-1])\n| where ProcessName in~ (filename)\n| extend CommandLine = tostring(EventData.CommandLine)\n| where CommandLine has_any (servicelist) and CommandLine has_any (parameters)\n| extend Account = strcat(tostring(EventData.SubjectDomainName),\"\\\\\", tostring(EventData.SubjectUserName))\n| extend AccountDomain = tostring(EventData.AccountDomain)\n| extend Activity=\"4688 - A new process has been created.\"\n| extend EventSourceName=Provider\n| project TimeGenerated, Computer, Account, AccountDomain, ProcessName, ProcessNameFullPath = NewProcessName, EventID, Activity, CommandLine, EventSourceName, Type\n),\n(\nDeviceProcessEvents\n| where TimeGenerated >= ago(timeframe)\n| where InitiatingProcessFileName in~ (filename)\n| where InitiatingProcessCommandLine has_any(servicelist) and InitiatingProcessCommandLine has_any (parameters)\n| extend Account = iff(isnotempty(InitiatingProcessAccountUpn), InitiatingProcessAccountUpn, InitiatingProcessAccountName), Computer = DeviceName\n| project TimeGenerated, Computer, Account, AccountDomain, ProcessName = InitiatingProcessFileName, ProcessNameFullPath = FolderPath, Activity = ActionType, CommandLine = InitiatingProcessCommandLine, Type, InitiatingProcessParentFileName\n)\n)\n| extend AccountName = tostring(split(Account, \"\\\\\")[0]), AccountNTDomain = tostring(split(Account, \"\\\\\")[1])\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)"
},
{
"name": "9da99021-d318-4711-a78a-6dea76129b3a — AWSCloudTrail - AWS GuardDuty detector disabled or suspended",
"description": "Identifies AWS GuardDuty detectors being disabled or suspended. This behavior can indicate defense evasion and should be validated with the initiating identity and approved administrative activity. (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed), mapped via sub-technique T1562.)",
"query": "AWSCloudTrail\n| where (EventName == \"DeleteDetector\" and isempty(ErrorCode) and isempty( ErrorMessage)) or (EventName == \"UpdateDetector\" and tostring(parse_json(RequestParameters).enable) == \"false\" and isempty(ErrorCode) and isempty( ErrorMessage))\n| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)\n| extend UserName = tostring(split(UserIdentityArn, '/')[-1])\n| extend AccountName = case( UserIdentityPrincipalid == \"Anonymous\", \"Anonymous\", isempty(UserIdentityUserName), UserName, UserIdentityUserName)\n| extend AccountName = iif(AccountName contains \"@\", tostring(split(AccountName, '@', 0)[0]), AccountName),\n AccountUPNSuffix = iif(AccountName contains \"@\", tostring(split(AccountName, '@', 1)[0]), \"\")"
}
],
"spl": [
{
"name": "Antivirus/EDR tamper events",
"description": "Search for security control tampering in Splunk.",
"query": "index=endpoint (action=\"av_disabled\" OR action=\"edr_uninstall\") earliest=-24h\n"
}
],
"esql": [
{
"name": "89b68231-5134-4499-8eca-20e5d9c90cce — AWS Bedrock API Key Used for Destructive or Anti-Recovery Action",
"description": "(ESQL) Identifies an Amazon Bedrock API key (bearer token) being used to perform a destructive or anti-recovery control-plane action, such as deleting a guardrail, deleting a custom or imported model, removing provisioned throughput, or disabling model invocation logging... (Source: Elastic's official detection-rules repository (Elastic License v2), mapped via sub-technique T1562.)",
"query": "FROM logs-aws.cloudtrail-* METADATA _id, _version, _index\n| WHERE event.provider == \"bedrock.amazonaws.com\"\n AND aws.cloudtrail.additional_eventdata RLIKE \"\"\".*callWithBearerToken=true.*\"\"\"\n AND event.action IN (\n \"DeleteGuardrail\",\n \"DeleteModelInvocationLoggingConfiguration\",\n \"PutModelInvocationLoggingConfiguration\",\n \"DeleteImportedModel\",\n \"DeleteCustomModel\",\n \"DeleteModelCustomizationJob\",\n \"DeleteProvisionedModelThroughput\",\n \"DeleteMarketplaceModelEndpoint\"\n )\n| KEEP _id, _version, _index, @timestamp, aws.*, cloud.*, event.*, source.*, user.*, user_agent.*"
},
{
"name": "0ef5d3eb-67ef-43ab-93b7-305cfa5a21f6 — Sensitive Audit Policy Sub-Category Disabled",
"description": "(ESQL) Identifies attempts to disable auditing for some security sensitive audit policy sub-categories. This is often done by attackers in an attempt to evade detection and forensics on a system. (Source: Elastic's official detection-rules repository (Elastic License v2), mapped via sub-technique T1562.)",
"query": "from logs-windows.forwarded*, logs-system.security* metadata _id, _version, _index\n| where host.os.type == \"windows\" and event.code == \"4719\" and\n winlog.event_data.AuditPolicyChangesDescription in (\"Success removed\", \"Success Added\") and\n winlog.event_data.SubCategory in (\n \"Logon\",\n \"Audit Policy Change\",\n \"Process Creation\",\n \"Other System Events\",\n \"Security Group Management\",\n \"User Account Management\"\n )\n| eval Esql.time_window = DATE_TRUNC(5m, @timestamp)\n\n// Aggregate policy changes within each 5m window per host and sub-category,\n// then keep only removals that were not re-enabled in the same window\n| inline stats\n Esql.winlog_AuditPolicyChangesDescription_values = VALUES(winlog.event_data.AuditPolicyChangesDescription)\n by host.id, winlog.event_data.SubCategory, Esql.time_window\n| where winlog.event_data.AuditPolicyChangesDescription == \"Success removed\" and not MV_CONTAINS(Esql.winlog_AuditPolicyChangesDescription_values, \"Success Added\")\n\n// Wait 5m for a potential \"Success Added\" to arrive before alerting\n| where @timestamp < NOW() - 5m\n| keep *"
}
]
},
"automation": {
"safe": [
"Add recommendation as Sentinel incident comment.",
"Create ServiceNow SecOps task.",
"Run enrichment queries against the affected host/identity."
],
"approval_required": [
"Re-enable/restore the security control.",
"Isolate the host.",
"Revoke the identity/service principal responsible."
]
},
"escalation_criteria": [
"EDR/antivirus tamper protection was bypassed successfully.",
"Security event logs were cleared.",
"Conditional Access or tenant security policy was weakened.",
"Change occurred on a server holding sensitive data or privileged access."
],
"false_positive_considerations": [
"Approved maintenance window disabling AV for a software deployment.",
"Legitimate security tooling migration/replacement project.",
"Scheduled log rotation misidentified as log clearing."
],
"confluence": {
"title": "T1685 - Disable or Modify Tools Response Guidance",
"labels": [
"mitre",
"attack",
"d3fend",
"secops",
"basyrix"
],
"sections": [
"summary",
"d3fend_mappings",
"investigation_steps",
"response_actions",
"queries",
"automation",
"escalation_criteria",
"false_positive_considerations"
]
}
}