Detection rules › Kusto

LSASS Dumping using Debug Privileges

Group by
DeviceId, InitiatingProcessId, InitiatingProcessSHA1
Author
FalconForce
Source
github.com/FalconForceTeam/FalconFriday

This query searches for a process that requests the SeDebugPrivilege privilege and opens LSASS memory using specific permission 0x1fffff which represents PROCESS_ALL_ACCESS.

Known false positives

  • There are some applications that perform these actions for legitimate purposes. One example is Procmon by Sysinternals.

MITRE ATT&CK coverage

TacticTechniques
Execution
Credential Access

References

Telemetry coverage

Rule body

let timeframe = 2*1h;
let SeDebugPrivilege = binary_shift_left(1, 20); // Value for SeDebugPrivilege is 2**20 = 0x100000.
let LSASSOpen=materialize (
    DeviceEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "OpenProcessApiCall"
    | where FileName =~ "lsass.exe"
    | extend AccessRights=parse_json(AdditionalFields).DesiredAccess
    | where AccessRights == 0x1fffff // PROCESS_ALL_ACCESS.
    | summarize by DeviceId, InitiatingProcessId, InitiatingProcessSHA1
);
DeviceEvents
| where ingestion_time() >= ago(timeframe)
| where ActionType == "ProcessPrimaryTokenModified"
| where isnotempty(InitiatingProcessSHA1)
// Look for processes that request debug privilege that also opened LSASS
| where InitiatingProcessSHA1 in ((LSASSOpen | project InitiatingProcessSHA1)) // Speeds up the query.
| lookup kind=inner LSASSOpen on DeviceId, InitiatingProcessSHA1, InitiatingProcessId
// Check that debug privilege is enabled.
| extend AdditionalFields=parse_json(AdditionalFields)
| extend CurrentTokenPrivEnabled = toint(AdditionalFields.CurrentTokenPrivEnabled)
| extend OriginalTokenPrivEnabled = toint(AdditionalFields.OriginalTokenPrivEnabled)
// Value for SeDebugPrivilege is 2**20 = 0x100000.
// Refer to https://downloads.volatilityfoundation.org//omfw/2012/OMFW2012_Gurkok.pdf for numeric values for privileges.
| extend DebugPrivCurrent = binary_and(CurrentTokenPrivEnabled,SeDebugPrivilege) == SeDebugPrivilege
| extend DebugPrivOrig = binary_and(OriginalTokenPrivEnabled,SeDebugPrivilege) == SeDebugPrivilege
// Check for processes that have debug privilege after the event, but did not have it before.
| where not(DebugPrivOrig) and DebugPrivCurrent
| extend CleanCmdLine = parse_command_line(InitiatingProcessCommandLine, "windows")
| where not(InitiatingProcessFileName =~ "tasklist.exe" and CleanCmdLine has_any ("/m", "-m"))
| extend HostName=tostring(split(DeviceName,".")[0]),DnsDomain=iif(DeviceName contains ".", substring(DeviceName, indexof(DeviceName, ".") + 1, strlen(DeviceName)),"")
| project-reorder Timestamp, DeviceId, InitiatingProcessFileName
// Begin environment-specific filter.
// End environment-specific filter.

Stages and Predicates

Parameters

let timeframe = 2*1h;
let SeDebugPrivilege = binary_shift_left(1, 20);

Let binding: LSASSOpen used in Stages 1, 7

let LSASSOpen = materialize (
    DeviceEvents
    | where ingestion_time() >= ago(timeframe)
    | where ActionType == "OpenProcessApiCall"
    | where FileName =~ "lsass.exe"
    | extend AccessRights=parse_json(AdditionalFields).DesiredAccess
    | where AccessRights == 0x1fffff
    | summarize by DeviceId, InitiatingProcessId, InitiatingProcessSHA1
);

Stage 1: source

let LSASSOpen

Stage 2: source

DeviceEvents

Stage 3: where

where ...

Stage 4: where

where ActionType =~ "ProcessPrimaryTokenModified"

Stage 5: where

where isnotempty(InitiatingProcessSHA1)

Stage 6: where

where /* macro: (InitiatingProcessSHA1 in <NestedQuery>) */

Stage 7: kusto:lookup

lookup kind=inner (LSASSOpen) on DeviceId, InitiatingProcessSHA1, InitiatingProcessId

Stage 8: extend (5 consecutive steps)

extend AdditionalFields, CurrentTokenPrivEnabled, DebugPrivCurrent, DebugPrivOrig, OriginalTokenPrivEnabled

Stage 9: where

where /* macro: DebugPrivOrig */

Stage 10: extend

extend CleanCmdLine

Stage 11: where

where not (((CleanCmdLine contains "/m" or CleanCmdLine contains "-m") and InitiatingProcessFileName =~ "tasklist.exe"))

Stage 12: extend

extend DnsDomain, HostName

Stage 13: project-reorder

project-reorder

Stage 14: summarize aggregation inside the lookup branch

summarize by DeviceId, InitiatingProcessId, InitiatingProcessSHA1

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
DeviceIdsummarize
InitiatingProcessIdsummarize
InitiatingProcessSHA1summarize