# T1003 - OS Credential Dumping

## SOC Recommendation
Treat any tool or process accessing LSASS memory, the SAM hive, or NTDS.dit outside of known-good backup/administrative tooling as a near-certain credential dumping attempt requiring immediate containment and full credential rotation for anything that may have been exposed.

## D3FEND Mappings
| D3FEND Technique | Relationship | Practical SOC Action |
|---|---|---|
| Process Spawn Analysis | Detect | Detect processes opening a handle to lsass.exe outside of known security/monitoring tooling. |
| File Analysis | Detect | Detect access to SAM/SYSTEM hives, NTDS.dit, or shadow copies used to extract them. |
| Kernel-based Process Isolation | Isolate | Enable Credential Guard / virtualization-based LSASS protection so credential material cannot be read even by a process with local admin. |
| Credential Revocation | Evict | Rotate all credentials that may have been present in memory or the dumped store, including the krbtgt account if domain controllers are involved. |

## Investigation Steps
1. MDE portal → Device inventory → <DEVICE_NAME> → Isolate device
2. Record: initiating process name, command line, folder path, and SHA256 hash
3. Submit the SHA256 hash to VirusTotal immediately — is it a known tool?
4. Is the process running from %TEMP%, %APPDATA%, C:\ProgramData, or C:\Users? → Almost certainly malicious
5. Is the process digitally signed? By whom? (An unsigned process accessing LSASS is extremely high confidence)
6. Notify SOC Manager and open P1 incident ticket
7. Immediately reset the password — do not wait for investigation completion
8. For domain admin accounts: treat as Critical escalation — KRBTGT reset may be required

## Evidence to Collect
- Host affected (and whether it is a domain controller)
- Process that accessed the credential store
- Technique used (LSASS dump, SAM/NTDS extraction, shadow copy)
- Accounts/hashes potentially exposed
- Any follow-on authentication using exposed credentials

## Response Actions
| Action | Risk | Automation Safe | Approval Required |
|---|---|---|---|
| Isolate device | Medium | No | Yes |
| Reset ALL passwords | High | No | Yes |
| Disable the initiating account | Medium | No | Yes |
| Purge Kerberos tickets | Medium | No | Yes |
| Notify customer CISO | Low | Yes | No |
| Open P1 incident ticket | Low | Yes | No |
| Force MFA re-enrolment for all affected accounts | Low | No | Yes |
| Revoke all active sessions for affected accounts across M365 | Medium | No | Yes |

## KQL
```kql
let AllowedInitiators = dynamic([
    "MsMpEng.exe",
    "MsSense.exe",
    "SenseIR.exe",
    "wermgr.exe",
    "csrss.exe",
    "svchost.exe",
    "werfault.exe"
]);
DeviceProcessEvents
| where TimeGenerated >= ago(5m)
| where ProcessCommandLine has_any ("lsass", "MiniDump", "procdump", "sekurlsa")
| where FileName !in~ (AllowedInitiators)
| where InitiatingProcessFileName !in~ (AllowedInitiators)
| project
    TimeGenerated,
    DeviceName,
    DeviceId,
    AccountName,
    FileName,
    ProcessCommandLine,
    InitiatingProcessFileName,
    InitiatingProcessCommandLine,
    InitiatingProcessSHA256,
    InitiatingProcessIntegrityLevel
| extend timestamp = TimeGenerated,
         HostCustomEntity = DeviceName,
         AccountCustomEntity = AccountName
| order by TimeGenerated desc
```
```kql
let files1 = dynamic(["C:\\Windows\\TAPI\\lsa.exe", "C:\\Windows\\TAPI\\pa.exe", "C:\\Windows\\TAPI\\pc.exe", "C:\\Windows\\TAPI\\Rar.exe"]);
let files2 = dynamic(["svchost.exe","wdmsvc.exe"]);
let FileHash1 = dynamic(["43109fbe8b752f7a9076eaafa417d9ae5c6e827cd5374b866672263fdebd5ec3", "ab50d8d707b97712178a92bbac74ccc2a5699eb41c17aa77f713ff3e568dcedb", "010e32be0f86545e116a8bc3381a8428933eb8789f32c261c81fd5e7857d4a77",     "56cd102b9fc7f3523dad01d632525ff673259dbc9a091be0feff333c931574f7"]);
let FileHash2 = dynamic(["2a1044e9e6e87a032f80c6d9ea6ae61bbbb053c0a21b186ecb3b812b49eb03b7", "9ab7e99ed84f94a7b6409b87e56dc6e1143b05034a5e4455e8c555dbbcd0d2dd", "18a072ccfab239e140d8f682e2874e8ff19d94311fc8bb9564043d3e0deda54b"]);
imProcessCreate
| where ((Process has_any (files1)) and (ActingProcessSHA256 has_any (FileHash1))) or ((Process has_any (files2)) and (ActingProcessSHA256 has_any (FileHash2)))
// Increase risk score if recent alerts for the host
| join kind=leftouter (
  SecurityAlert
  | where ProviderName =~ "MDATP"
  | extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
  | mv-expand todynamic(Entities)
  | extend DvcId = tostring(parse_json(Entities).MdatpDeviceId)
  | where isnotempty(DvcId)
  // Higher risk score are for Defender alerts related to threat actor
  | extend AlertRiskScore = iif(ThreatName has_any ("Backdoor:MSIL/ShellClient.A", "Backdoor:MSIL/ShellClient.A!dll", "Trojan:MSIL/Mimikatz.BA!MTB"), 1.0, 0.5)
  | project DvcId, AlertRiskScore) 
  on DvcId
| extend AlertRiskScore = iif(isempty(AlertRiskScore), 0.0, AlertRiskScore)
| extend AccountName = tostring(split(ActorUsername, @'\')[1]), AccountNTDomain = tostring(split(ActorUsername, @'\')[0])
| extend HostName = tostring(split(Dvc, ".")[0]), DomainIndex = toint(indexof(Dvc, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Dvc, DomainIndex + 1), Dvc)
| project-away DomainIndex
```
```kql
let files1 = dynamic(["C:\\Windows\\TAPI\\lsa.exe", "C:\\Windows\\TAPI\\pa.exe", "C:\\Windows\\TAPI\\pc.exe", "C:\\Windows\\TAPI\\Rar.exe"]);
let files2 = dynamic(["svchost.exe","wdmsvc.exe"]);
let FileHash1 = dynamic(["43109fbe8b752f7a9076eaafa417d9ae5c6e827cd5374b866672263fdebd5ec3", "ab50d8d707b97712178a92bbac74ccc2a5699eb41c17aa77f713ff3e568dcedb", "010e32be0f86545e116a8bc3381a8428933eb8789f32c261c81fd5e7857d4a77",         "56cd102b9fc7f3523dad01d632525ff673259dbc9a091be0feff333c931574f7"]);
let FileHash2 = dynamic(["2a1044e9e6e87a032f80c6d9ea6ae61bbbb053c0a21b186ecb3b812b49eb03b7", "9ab7e99ed84f94a7b6409b87e56dc6e1143b05034a5e4455e8c555dbbcd0d2dd", "18a072ccfab239e140d8f682e2874e8ff19d94311fc8bb9564043d3e0deda54b"]);
DeviceProcessEvents
| where ( FolderPath has_any (files1) and SHA256 has_any (FileHash1)) or (FolderPath has_any (files2) and SHA256 has_any (FileHash2))
| extend DvcId = DeviceId
| join kind=leftouter (SecurityAlert
| where ProviderName =~ "MDATP"
| extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
| mv-expand todynamic(Entities)
| extend DvcId = tostring(parse_json(Entities).MdatpDeviceId)
| where isnotempty(DvcId)
// Higher risk score are for Defender alerts related to threat actor
| extend AlertRiskScore = iif(ThreatName has_any ("Backdoor:MSIL/ShellClient.A", "Backdoor:MSIL/ShellClient.A!dll", "Trojan:MSIL/Mimikatz.BA!MTB"), 1.0, 0.5)
| project DvcId, AlertRiskScore) on DvcId
| extend AlertRiskScore = iif(isempty(AlertRiskScore), 0.0, AlertRiskScore)
| extend InitiatingProcessAccount = strcat(InitiatingProcessAccountDomain, "\\", InitiatingProcessAccountName)
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
| extend timestamp = TimeGenerated
```

## Escalation Criteria
- Domain controller involved.
- Known dumping tool signature matched.
- Follow-on authentication observed using a potentially exposed credential.
- Privileged or service account credentials potentially exposed.

## False Positive Considerations
- Windows Defender Antivirus (MsMpEng.exe) — Pre-excluded in the approved list — verify hash matches Microsoft's known-good
- MDE Sense process (SenseCE.exe / MsSense.exe) — Pre-excluded — verify the hash matches the installed MDE version
- Authorised penetration test — Pentest scope document, written approval, date/time window
- Azure AD Connect agent — AzureADConnectAuthenticationAgentService.exe — pre-excluded

Generated by SOC Response Atlas by Basyrix.
