# T1176 - Software Extensions

## SOC Recommendation
Investigate Software Extensions activity in the context of Persistence: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.

## D3FEND Mappings
| D3FEND Technique | Relationship | Practical SOC Action |
|---|---|---|
| Software Update | Harden | Apply Software Update to reduce this technique's viability before an incident occurs. |
| Restore Software | Restore | Use Restore Software to recover affected systems or data after containment. |
| Software Inventory | Model | Use Software Inventory to establish a baseline that makes this technique's deviations easier to spot. |

## Investigation Steps
1. Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.
2. Check Sentinel analytics rules and incidents correlated with this technique.
3. Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource.

## Evidence to Collect
- Host or resource affected
- Account or identity involved
- Timestamp of the activity
- Related process, file, or network artifact
- Any preceding or follow-on alerts

## Response Actions
| Action | Risk | Automation Safe | Approval Required |
|---|---|---|---|
| Remove or disable the unauthorised browser extension from th | Medium | No | Yes |
| If malicious activity is suspected, isolate the device and p | Medium | No | Yes |
| Block the extension ID, publisher, update URL, or related do | Medium | No | Yes |
| Review and remediate browser extension policies, including f | Low | Yes | No |
| Hunt for the same extension ID, publisher, install path, reg | Low | No | Yes |
| Reset affected user credentials and revoke sessions if the e | Medium | No | Yes |
| Add approved business extensions to the allowlist and tune t | Low | Yes | No |

## KQL
```kql
let detectionWindow = 1h;
let baselineWindow = 14d;
let AllowedExtensionIds = dynamic([
    "ppnbnpeolgkicgegkbkbjmhlideopiji" // Microsoft Single Sign-On, installed by policy.
]);
let ExtensionManifestEvents = materialize(
    DeviceFileEvents
    | where TimeGenerated >= ago(baselineWindow)
    | where ActionType in~ ("FileCreated", "FileRenamed")
    | where FileName =~ "manifest.json"
    | extend NormalizedPath = tolower(FolderPath)
    | where NormalizedPath has "\\extensions\\"
    | where NormalizedPath has_any ("\\google\\chrome\\user data\\", "\\microsoft\\edge\\user data\\")
    | extend Browser = case(
        NormalizedPath has "\\google\\chrome\\user data\\", "Chrome",
        NormalizedPath has "\\microsoft\\edge\\user data\\", "Edge",
        "Unknown"
    )
    | extend ExtensionId = extract(@"\\extensions\\([a-p]{32})\\", 1, NormalizedPath)
    | where isnotempty(ExtensionId)
    | where ExtensionId !in~ (AllowedExtensionIds)
);
let PriorExtensions =
    ExtensionManifestEvents
    | where TimeGenerated < ago(detectionWindow)
    | summarize by DeviceId, Browser, ExtensionId;
let NewlyObservedExtensionManifests =
    ExtensionManifestEvents
    | where TimeGenerated >= ago(detectionWindow)
    | join kind=leftanti PriorExtensions on DeviceId, Browser, ExtensionId
    | project
        TimeGenerated,
        DeviceId,
        DeviceName,
        AccountName = InitiatingProcessAccountName,
        Browser,
        ExtensionId,
        EvidenceType = "ExtensionManifestCreated",
        EvidencePath = FolderPath,
        FileName,
        InitiatingProcessFileName,
        InitiatingProcessCommandLine,
        InitiatingProcessSHA256,
        RegistryKey = "",
        RegistryValueName = "",
        RegistryValueData = "";
let ExtensionPolicyInstalls =
    DeviceRegistryEvents
    | where TimeGenerated >= ago(detectionWindow)
    | where ActionType in~ ("RegistryKeyCreated", "RegistryValueSet")
    | extend RegistryKeyLower = tolower(RegistryKey)
    | where RegistryKeyLower has_any (
        "\\software\\policies\\google\\chrome\\extensioninstallforcelist",
        "\\software\\policies\\google\\chrome\\extensionsettings",
        "\\software\\policies\\microsoft\\edge\\extensioninstallforcelist",
        "\\software\\policies\\microsoft\\edge\\extensionsettings"
    )
    | extend Browser = case(
        RegistryKeyLower has "\\google\\chrome\\", "Chrome",
        RegistryKeyLower has "\\microsoft\\edge\\", "Edge",
        "Unknown"
    )
    | extend ExtensionId = extract(@"([a-p]{32})", 1, tolower(strcat(RegistryKey, " ", RegistryValueName, " ", RegistryValueData)))
    | where isempty(ExtensionId) or ExtensionId !in~ (AllowedExtensionIds)
    | extend AccountName = iff(
        isnotempty(tostring(column_ifexists("InitiatingProcessAccountName", ""))),
        tostring(column_ifexists("InitiatingProcessAccountName", "")),
        tostring(column_ifexists("AccountName", ""))
    )
    | project
        TimeGenerated,
        DeviceId,
        DeviceName,
        AccountName,
        Browser,
        ExtensionId,
        EvidenceType = "BrowserExtensionPolicySet",
        EvidencePath = RegistryKey,
        FileName = "",
        InitiatingProcessFileName,
        InitiatingProcessCommandLine,
        InitiatingProcessSHA256,
        RegistryKey,
        RegistryValueName,
        RegistryValueData;
union isfuzzy=true NewlyObservedExtensionManifests, ExtensionPolicyInstalls
| summarize
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated),
    EvidenceTypes = make_set_if(EvidenceType, isnotempty(EvidenceType), 10),
    EvidencePaths = make_set_if(EvidencePath, isnotempty(EvidencePath), 20),
    FileNames = make_set_if(FileName, isnotempty(FileName), 20),
    InitiatingProcesses = make_set_if(InitiatingProcessFileName, isnotempty(InitiatingProcessFileName), 10),
    InitiatingProcessCommandLines = make_set_if(InitiatingProcessCommandLine, isnotempty(InitiatingProcessCommandLine), 10),
    InitiatingProcessHashes = make_set_if(InitiatingProcessSHA256, isnotempty(InitiatingProcessSHA256), 10),
    RegistryValues = make_set_if(RegistryValueData, isnotempty(RegistryValueData), 10)
    by DeviceId, DeviceName, AccountName, Browser, ExtensionId
| extend ExtensionInstallMethod = case(
    set_has_element(EvidenceTypes, "BrowserExtensionPolicySet") and set_has_element(EvidenceTypes, "ExtensionManifestCreated"), "Policy and local manifest",
    set_has_element(EvidenceTypes, "BrowserExtensionPolicySet"), "Policy-based install or force install",
    "Local profile extension manifest"
)
| project
    TimeGenerated = LastSeen,
    FirstSeen,
    LastSeen,
    DeviceId,
    DeviceName,
    AccountName,
    Browser,
    ExtensionId,
    ExtensionInstallMethod,
    EvidenceTypes,
    EvidencePaths,
    FileNames,
    InitiatingProcesses,
    InitiatingProcessCommandLines,
    InitiatingProcessHashes,
    RegistryValues
| extend timestamp = TimeGenerated,
         HostCustomEntity = DeviceName,
         AccountCustomEntity = AccountName
| order by TimeGenerated desc
```
```kql
let threshold = 5;
GWorkspaceActivityReports
| where isnotempty(UserAgentOriginal)
| summarize user_ua = makeset(UserAgentOriginal) by SrcIpAddr, bin(TimeGenerated, 5m)
| where array_length(user_ua) > threshold
| extend IPCustomEntity = SrcIpAddr
```

## Escalation Criteria
- Software Extensions activity observed on a privileged account or critical system.
- Activity follows or precedes other suspicious behaviour in the same investigation.
- Automated triage cannot confidently rule out malicious intent.

## False Positive Considerations
- Legitimate administrative or maintenance activity matching this pattern.
- Approved security testing or red team exercise.
- Known benign software producing similar telemetry.

Generated by SOC Response Atlas by Basyrix.
