# 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.
