Home / Blog / Detection Engineering
How to Detect LSASS Memory Access with Sysmon Event ID 10
Build a tuned LSASS access detection from Sysmon Event ID 10, with Splunk, Sentinel and Sigma versions, plus triage steps and the hardening that reduces your risk.
Attackers who reach local administrator often go straight for the credentials held in LSASS memory, because those credentials let them move on to other hosts. Sysmon Event ID 10 shows you which process opened LSASS and what rights it asked for, but an untuned rule buries you in noise. This guide helps detection engineers and senior analysts build a rule that stays quiet enough to trust.
Scenario: At 02:14 your SIEM flags WS-114. rundll32.exe, running as a local administrator, opened lsass.exe with GrantedAccess of 0x1FFFFF. Ninety seconds later a new .dmp file appears in C:\Windows\Temp. You need to decide quickly whether this is a crash dump or credential theft, and the quality of your rule decides how much of that work is already done.
Understand what Event ID 10 records
Sysmon logs Event ID 10 when one process opens a handle to another. The event is written to Applications and Services Logs/Microsoft/Windows/Sysmon/Operational. Microsoft warns that it can generate a lot of logging when diagnostic tools repeatedly open processes, so it should always be filtered.
These are the fields that matter most for this detection:
- SourceImage: the process that asked for access. Path and location are your first clues.
- TargetImage: the process being opened, here
C:\Windows\System32\lsass.exe. - GrantedAccess: a hexadecimal mask of the rights granted to the handle.
- CallTrace: the DLLs and offsets on the call stack when the handle was opened.
- SourceProcessGUID and SourceThreadId: identifiers that let you pivot to other Sysmon events from the same process.
Recent Sysmon versions also record SourceUser and TargetUser. Run sysmon64 -s to print the schema for the version you have deployed.
Read the access mask
The mask is a sum of process access rights. The right that matters most is PROCESS_VM_READ (0x0010), because reading memory is the point of credential dumping. Breaking a mask into its parts tells you what the source process could do with its handle.
| GrantedAccess | What it contains | How to treat it |
|---|---|---|
0x1000 | Query limited information | Common and low risk |
0x1400 | Query information and query limited information | Common and noisy, usually filtered out |
0x1010 | Query limited information and VM read | Investigate, can read memory |
0x1410 | Both query rights and VM read | Investigate, also seen with Task Manager dumps |
0x1438 | Both query rights, VM read, VM write and VM operation | High concern, write access to LSASS is rarely legitimate |
0x143A | As above, plus create thread | High concern |
0x1FFFFF | All access | Investigate, also seen with ProcDump and Task Manager dumps |
Note: Sysmon compares GrantedAccess as a literal string, not bitwise. A filter for 0x1010 will not match 0x1410, even though both include VM read. This is the main reason a short list of known bad masks misses things.
Collect the right events
You want every handle opened to LSASS except the two very common query only masks. Sysmon treats repeated rules on the same field as OR, and exclude rules override include rules, so a small configuration does the job.
<Sysmon schemaversion="4.90">
<EventFiltering>
<RuleGroup name="lsass-include" groupRelation="or">
<ProcessAccess>
<TargetImage condition="end with">\lsass.exe</TargetImage>
</ProcessAccess>
</RuleGroup>
<RuleGroup name="lsass-exclude" groupRelation="or">
<ProcessAccess>
<GrantedAccess condition="is">0x1000</GrantedAccess>
<GrantedAccess condition="is">0x1400</GrantedAccess>
</ProcessAccess>
</RuleGroup>
</EventFiltering>
</Sysmon>
Set schemaversion to match your deployed binary, then apply the file with sysmon64 -c yourconfig.xml. Test on a small pilot group first. If your estate has a noisy agent, exclude it in the SIEM before you exclude it on the host, so you can still see the events if that decision needs revisiting.
Baseline before you write the rule
Every estate has legitimate LSASS readers, such as security agents, monitoring tools and backup software. Find yours by counting source and mask pairs over 30 days. Run this after the configuration has been live long enough to cover patching and maintenance windows.
Event
| where TimeGenerated > ago(30d)
| where Source == "Microsoft-Windows-Sysmon" and EventID == 10
| extend TargetImage = extract(@'Name="TargetImage">([^<]+)<', 1, EventData),
SourceImage = extract(@'Name="SourceImage">([^<]+)<', 1, EventData),
GrantedAccess = extract(@'Name="GrantedAccess">([^<]+)<', 1, EventData)
| where TargetImage endswith @"\lsass.exe"
| summarize Events = count(), Hosts = dcount(Computer) by SourceImage, GrantedAccess
| order by Events desc
Review the output line by line. A source that appears on every host from a protected path under Program Files is a candidate for your allow list. A source that appears on one host from a user profile is a finding, not a baseline entry.
Watch out: Never allow list a whole folder or a process name on its own. An attacker can rename a binary, and rundll32.exe is a signed Microsoft file. Use full paths, and only for paths that standard users cannot write to.
Choose your detection logic
There are three common designs. Most teams should run the second as their main rule and add the third as a higher severity alert.
Known bad masks
Alert when the mask is on a fixed list such as 0x1010 or 0x1438. Easy to write, but misses any mask you did not list.
Good for a quick startInverse logic
Alert on any mask outside a short low risk list, from any source outside your allow list. New masks alert by default.
Recommended main ruleCorrelated sequence
Alert when suspicious access is followed by a dump file on the same host. Fewer alerts and much higher confidence.
Best for high severity pagingElastic's prebuilt Suspicious Lsass Process Access rule uses the inverse approach. It excludes low risk masks, known tools and specific call trace modules such as mpengine.dll, then alerts on what remains. Elastic also publishes a separate rule for handle duplication, which is worth copying as an idea: 0x40 (PROCESS_DUP_HANDLE) can be noisy, but it deserves its own review rather than being ignored.
Splunk version
index=sysmon EventCode=10 TargetImage="*\\lsass.exe"
NOT GrantedAccess IN ("0x1000", "0x1400", "0x100000", "0x101000", "0x101400")
NOT SourceImage IN ("C:\\Windows\\System32\\csrss.exe", "C:\\Windows\\System32\\wininit.exe", "C:\\Windows\\System32\\wbem\\WmiPrvSE.exe")
| stats count min(_time) as firstSeen max(_time) as lastSeen values(GrantedAccess) as masks values(CallTrace) as callTraces by host, SourceImage, SourceUser
| convert ctime(firstSeen) ctime(lastSeen)
| sort - count
Sentinel version
let LowRiskMasks = dynamic(["0x1000", "0x1400", "0x100000", "0x101000", "0x101400"]);
let AllowedSources = dynamic([
"C:\\Windows\\System32\\csrss.exe",
"C:\\Windows\\System32\\wininit.exe",
"C:\\Windows\\System32\\wbem\\WmiPrvSE.exe"
]);
Event
| where TimeGenerated > ago(1h)
| where Source == "Microsoft-Windows-Sysmon" and EventID == 10
| extend TargetImage = extract(@'Name="TargetImage">([^<]+)<', 1, EventData),
SourceImage = extract(@'Name="SourceImage">([^<]+)<', 1, EventData),
GrantedAccess = extract(@'Name="GrantedAccess">([^<]+)<', 1, EventData),
CallTrace = extract(@'Name="CallTrace">([^<]+)<', 1, EventData)
| where TargetImage endswith @"\lsass.exe"
| where GrantedAccess !in~ (LowRiskMasks)
| where SourceImage !in~ (AllowedSources)
| project TimeGenerated, Computer, SourceImage, GrantedAccess, CallTrace
Portable Sigma version
title: Suspicious Process Access to LSASS
id: 23a44e9a-2853-43c6-aadc-fcbb97037ca8
status: experimental
description: Detects handles opened to LSASS with rights outside a low risk list, from sources outside an allow list.
references:
- https://attack.mitre.org/techniques/T1003/001/
author: SOC Analysts
date: 2026-11-04
tags:
- attack.credential-access
- attack.t1003.001
logsource:
category: process_access
product: windows
detection:
selection:
TargetImage|endswith: '\lsass.exe'
filter_masks:
GrantedAccess:
- '0x1000'
- '0x1400'
- '0x100000'
- '0x101000'
- '0x101400'
filter_sources:
SourceImage:
- 'C:\Windows\System32\csrss.exe'
- 'C:\Windows\System32\wininit.exe'
- 'C:\Windows\System32\wbem\WmiPrvSE.exe'
condition: selection and not 1 of filter_*
falsepositives:
- Security agents, backup tools and monitoring software not yet in the allow list
level: high
Correlate with a dump file
Pairing access with a new dump file gives you an alert that is worth waking someone for. This query looks for a .dmp file, Sysmon Event ID 11 (FileCreate), within ten minutes of suspicious access on the same host.
let LowRiskMasks = dynamic(["0x1000", "0x1400", "0x100000", "0x101000", "0x101400"]);
let Access = Event
| where TimeGenerated > ago(1d)
| where Source == "Microsoft-Windows-Sysmon" and EventID == 10
| extend TargetImage = extract(@'Name="TargetImage">([^<]+)<', 1, EventData),
SourceImage = extract(@'Name="SourceImage">([^<]+)<', 1, EventData),
GrantedAccess = extract(@'Name="GrantedAccess">([^<]+)<', 1, EventData)
| where TargetImage endswith @"\lsass.exe"
| where GrantedAccess !in~ (LowRiskMasks)
| project AccessTime = TimeGenerated, Computer, SourceImage, GrantedAccess;
let Dumps = Event
| where TimeGenerated > ago(1d)
| where Source == "Microsoft-Windows-Sysmon" and EventID == 11
| extend TargetFilename = extract(@'Name="TargetFilename">([^<]+)<', 1, EventData),
Creator = extract(@'Name="Image">([^<]+)<', 1, EventData)
| where TargetFilename endswith ".dmp"
| project DumpTime = TimeGenerated, Computer, Creator, TargetFilename;
Access
| join kind=inner Dumps on Computer
| where DumpTime between (AccessTime .. (AccessTime + 10m))
| project AccessTime, DumpTime, Computer, SourceImage, GrantedAccess, Creator, TargetFilename
Tip: Add a command line detection alongside this. ATT&CK documents dumping through the built-in comsvcs.dll and its MiniDump export. Look for comsvcs together with minidump or #24 in Sysmon Event ID 1 or Windows Security Event ID 4688, if you have command line auditing enabled.
Triage a hit
When the rule fires, work out who opened LSASS, how, and what happened next. These cards cover the patterns you are most likely to meet.
Source in a writable path
HighSourceImage in a user profile, C:\Users\Public, C:\Windows\Temp or a share.
Isolate the host, collect the binary and treat exposed credentials as compromised.
Living off the land dump
Highrundll32.exe as the source, or dbghelp.dll or dbgcore.dll in CallTrace, with no matching change ticket.
Find the parent process and the command line, then locate and preserve the dump file.
Unbacked memory in the stack
HighUNKNOWN entries in CallTrace, which suggest code running outside a mapped file on disk.
Capture memory if your process allows it, then check the source process for injection.
Signed admin tool
MediumTask Manager or ProcDump opening LSASS, often with 0x1410 or 0x1FFFFF.
Confirm the user, the ticket and the reason. Dumping LSASS is rarely routine, so verify directly with the person.
New security or backup agent
MediumVendor signed binary under Program Files, seen on many hosts around a rollout.
Check signature and change record, then add the exact path to the allow list.
Then answer three questions before you close or escalate:
- Which parent process started the source, and which user was it running as? Pivot on
SourceProcessGUIDto the matching Event ID 1. - Was a dump file created, moved, compressed or copied off the host? Check Event ID 11 and network events around the same time.
- Which accounts had logged on to this host? Any of them may have been exposed, so check their later logons on other systems.
Reduce the risk on the endpoint
Detection tells you about an attempt, but hardening makes that attempt less likely to succeed. These three controls work well together.
Check LSA protection
On Windows 11 version 22H2 and later, LSA protection is enabled by default on new installs that are enterprise joined and capable of HVCI. Upgraded devices and many servers may not have it, so check rather than assume. A RunAsPPL value of 1 enables it with a UEFI lock. A value of 2 enables it without one, and is only enforced on Windows 11 22H2 and later.
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -Name RunAsPPL -ErrorAction SilentlyContinue
Get-WinEvent -FilterHashtable @{ LogName = 'System'; ProviderName = 'Microsoft-Windows-Wininit'; Id = 12 } -MaxEvents 1 |
Select-Object TimeCreated, Message
Event 12 from WinInit confirms that LSASS started as a protected process. Before enforcing the setting, use audit mode and review Event IDs 3065 and 3066 in the CodeIntegrity Operational log to spot LSA plugins and drivers that would fail to load.
Hunt ASR rule activity
The attack surface reduction rule is called "Block credential stealing from the Windows local security authority subsystem", with GUID 9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2. Microsoft says it is not required if LSA protection is enabled, because the two work similarly. It is still useful on devices where LSA protection cannot be turned on. In the Defender event log, Event ID 1121 is a block and 1122 is an audit.
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType in ("AsrLsassCredentialTheftBlocked", "AsrLsassCredentialTheftAudited")
| summarize Events = count(), Devices = dcount(DeviceName) by ActionType, InitiatingProcessFolderPath, InitiatingProcessFileName
| order by Events desc
Watch out: Microsoft notes that this rule produces a large volume of audit events, most of which are safe to ignore once it is in block mode. Use the audited events for hunting and baselining, not for alerting. Also keep your Sysmon detection running after hardening, because a protection setting does not remove the need to see an attempt.
Roll the detection out safely
Introduce the rule in stages so that your analysts see it as a reliable signal from the first day it pages anyone.
- L0CollectDeploy the Sysmon config to a pilot group and check event volume in your SIEM.Week 1
- L1BaselineReview source and mask pairs, and build an allow list of exact paths with an owner for each entry.Weeks 2 to 3
- L2TestIn an isolated lab, validate with a framework such as Atomic Red Team tests for T1003.001, and confirm each test alerts.Week 4
- L3PromoteEnable the inverse rule at medium severity and the correlated rule at high, then review allow list entries each quarter.Production
Key takeaways
- Read
GrantedAccessas a set of rights.PROCESS_VM_READis the one that most often matters for credential dumping. - Prefer inverse logic over a list of known bad masks, because Sysmon and most SIEM filters match the mask as an exact string.
- Baseline for 30 days and allow list exact paths only, never process names or whole folders.
- Use
CallTrace, the parent process and dump file creation to separate real attacks from admin activity. - Pair the detection with LSA protection and Credential Guard, and treat exposed accounts as compromised when a dump is confirmed.
Start with the baseline query this week, even if you cannot deploy the full rule yet. The list of processes touching LSASS in your estate is useful on its own, and anything on it that nobody can explain is your first hunt.