Remote Interactive Task Manager LSASS Dump#

Hypothesis#

Adversaries might be RDPing to computers in my environment and interactively dumping the memory contents of LSASS with task manager.

Technical Context#

Offensive Tradecraft#

The Windows Task Manager may be used to dump the memory space of lsass.exe to disk for processing with a credential access tool such as Mimikatz. This is performed by launching Task Manager as a privileged user, selecting lsass.exe, and clicking “Create dump file”. This saves a dump file to disk with a deterministic name that includes the name of the process being dumped.

Pre-Recorded Security Datasets#

Metadata

Value

docs

https://securitydatasets.com/notebooks/atomic/windows/credential_access/SDWIN-191027055035.html

link

https://raw.githubusercontent.com/OTRF/Security-Datasets/master/datasets/atomic/windows/credential_access/host/rdp_interactive_taskmanager_lsass_dump.zip

Download Dataset#

import requests
from zipfile import ZipFile
from io import BytesIO

url = 'https://raw.githubusercontent.com/OTRF/Security-Datasets/master/datasets/atomic/windows/credential_access/host/rdp_interactive_taskmanager_lsass_dump.zip'
zipFileRequest = requests.get(url)
zipFile = ZipFile(BytesIO(zipFileRequest.content))
datasetJSONPath = zipFile.extract(zipFile.namelist()[0])

Read Dataset#

import pandas as pd
from pandas.io import json

df = json.read_json(path_or_buf=datasetJSONPath, lines=True)

Analytics#

A few initial ideas to explore your data and validate your detection logic:

Analytic I#

Look for taskmgr creating files which name contains the string lsass and with extension .dmp.

Data source

Event Provider

Relationship

Event

File

Microsoft-Windows-Sysmon/Operational

Process created File

11

Logic#

SELECT `@timestamp`, Hostname, Image, TargetFilename, ProcessGuid
FROM dataTable
WHERE Channel = "Microsoft-Windows-Sysmon/Operational"
    AND EventID = 11
    AND Image LIKE "%taskmgr.exe"
    AND lower(TargetFilename) RLIKE ".*lsass.*\.dmp"

Pandas Query#

(
df[['@timestamp','Hostname','Image','TargetFilename','ProcessGuid']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 11)
    & (df['Image'].str.lower().str.endswith('taskmgr.exe', na=False))
    & (df['TargetFilename'].str.lower().str.contains('.*lsass.*dmp', regex=True))
]
)

Analytic II#

Look for task manager access lsass and with functions from dbgcore.dll or dbghelp.dll libraries.

Data source

Event Provider

Relationship

Event

Process

Microsoft-Windows-Sysmon/Operational

Process accessed Process

10

Logic#

SELECT `@timestamp`, Hostname, SourceImage, TargetImage, GrantedAccess
FROM dataTable
WHERE Channel = "Microsoft-Windows-Sysmon/Operational"
    AND EventID = 10
    AND lower(SourceImage) LIKE "%taskmgr.exe"
    AND lower(TargetImage) LIKE "%lsass.exe"
    AND (lower(CallTrace) RLIKE ".*dbgcore\.dll.*" OR lower(CallTrace) RLIKE ".*dbghelp\.dll.*")

Pandas Query#

(
df[['@timestamp','Hostname','SourceImage','TargetImage','GrantedAccess','CallTrace']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 10)
    & (df['SourceImage'].str.lower().str.endswith('taskmgr.exe', na=False))
    & (df['TargetImage'].str.lower().str.endswith('lsass.exe', na=False))
    & (
        (df['CallTrace'].str.lower().str.contains('.*dbgcore.*', regex=True))
        | (df['CallTrace'].str.lower().str.contains('.*dbghelp.*', regex=True))
    )
]
.head()
)

Analytic III#

Look for any process accessing lsass and with functions from dbgcore.dll or dbghelp.dll libraries.

Data source

Event Provider

Relationship

Event

Process

Microsoft-Windows-Sysmon/Operational

Process accessed Process

10

Logic#

SELECT `@timestamp`, Hostname, SourceImage, TargetImage, GrantedAccess
FROM dataTable
WHERE Channel = "Microsoft-Windows-Sysmon/Operational"
    AND EventID = 10
    AND lower(TargetImage) LIKE "%lsass.exe"
    AND (lower(CallTrace) RLIKE ".*dbgcore\.dll.*" OR lower(CallTrace) RLIKE ".*dbghelp\.dll.*")

Pandas Query#

(
df[['@timestamp','Hostname','SourceImage','TargetImage','GrantedAccess','CallTrace']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 10)
    & (df['TargetImage'].str.lower().str.endswith('lsass.exe', na=False))
    & (
        (df['CallTrace'].str.lower().str.contains('.*dbgcore.*', regex=True))
        | (df['CallTrace'].str.lower().str.contains('.*dbghelp.*', regex=True))
    )
]
.head()
)

Analytic IV#

Look for combinations of process access and process creation to get more context around potential lsass dump form task manager or other binaries.

Data source

Event Provider

Relationship

Event

Process

Microsoft-Windows-Sysmon/Operational

Process accessed Process

10

Process

Microsoft-Windows-Sysmon/Operational

Process created Process

1

Logic#

SELECT o.`@timestamp`, o.Hostname, o.Image, o.LogonId, o.ProcessGuid, a.SourceProcessGUID, o.CommandLine
FROM dataTable o
INNER JOIN (
    SELECT Hostname,SourceProcessGUID
    FROM dataTable
    WHERE Channel = "Microsoft-Windows-Sysmon/Operational"
        AND EventID = 10
        AND lower(TargetImage) LIKE "%lsass.exe"
        AND (lower(CallTrace) RLIKE ".*dbgcore\.dll.*" OR lower(CallTrace) RLIKE ".*dbghelp\.dll.*")
    ) a
ON o.ProcessGuid = a.SourceProcessGUID
WHERE o.Channel = "Microsoft-Windows-Sysmon/Operational"
    AND o.EventID = 1

Pandas Query#

processCreateDf = (
df[['@timestamp','Hostname','Image','LogonId','ProcessGuid','CommandLine']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 1)
]
)

processAccessDf = (
df[['@timestamp','Hostname','SourceImage','SourceProcessGUID','TargetImage','GrantedAccess','CallTrace']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 10)
    & (df['TargetImage'].str.lower().str.endswith('lsass.exe', na=False))
    & (
        (df['CallTrace'].str.lower().str.contains('.*dbgcore.*', regex=True))
        | (df['CallTrace'].str.lower().str.contains('.*dbghelp.*', regex=True))
    )
]
)

(
pd.merge(processCreateDf, processAccessDf,
    left_on = 'ProcessGuid', right_on = 'SourceProcessGUID', how = 'inner')
)

Analytic V#

Look for binaries accessing lsass that are running under the same logon context of a user over an RDP session.

Data source

Event Provider

Relationship

Event

Process

Microsoft-Windows-Sysmon/Operational

Process accessed Process

10

Process

Microsoft-Windows-Sysmon/Operational

Process created Process

1

Authentication log

Microsoft-Windows-Security-Auditing

User authenticated Host

4778

Logic#

SELECT o.`@timestamp`, o.Hostname, o.SessionName, o.AccountName, o.ClientName, o.ClientAddress
FROM dataTable o
INNER JOIN (
    SELECT LogonId, Image, CommandLine
    FROM (
        SELECT o.Image, o.LogonId, o.CommandLine
        FROM dataTable o
        INNER JOIN (
            SELECT Hostname,SourceProcessGUID
            FROM dataTable
            WHERE Channel = "Microsoft-Windows-Sysmon/Operational"
                AND EventID = 10
                AND lower(TargetImage) LIKE "%lsass.exe"
                AND (lower(CallTrace) RLIKE ".*dbgcore\.dll.*" OR lower(CallTrace) RLIKE ".*dbghelp\.dll.*")
            ) a
        ON o.ProcessGuid = a.SourceProcessGUID
        WHERE o.Channel = "Microsoft-Windows-Sysmon/Operational"
            AND o.EventID = 1
        )
    ) a
ON o.LogonID = a.LogonId
WHERE lower(o.Channel) = "security"
    AND o.EventID = 4778

Pandas Query#

processCreateDf = (
df[['@timestamp','Hostname','Image','LogonId','ProcessGuid','CommandLine']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 1)
]
)

processAccessDf = (
df[['@timestamp','Hostname','SourceImage','SourceProcessGUID','TargetImage','GrantedAccess','CallTrace']]

[(df['Channel'] == 'Microsoft-Windows-Sysmon/Operational')
    & (df['EventID'] == 10)
    & (df['TargetImage'].str.lower().str.endswith('lsass.exe', na=False))
    & (
        (df['CallTrace'].str.lower().str.contains('.*dbgcore.*', regex=True))
        | (df['CallTrace'].str.lower().str.contains('.*dbghelp.*', regex=True))
    )
]
)

firstJoinDf = (
pd.merge(processCreateDf, processAccessDf,
    left_on = 'ProcessGuid', right_on = 'SourceProcessGUID', how = 'inner')
)

sessionReconnectDf = (
df[['@timestamp','Hostname','LogonID','SessionName','AccountName','ClientName','ClientAddress']]

[(df['Channel'].str.lower() == 'security')
    & (df['EventID'] == 4778)
]
)

(
pd.merge(firstJoinDf, sessionReconnectDf,
    left_on = 'LogonId', right_on = 'LogonID', how = 'inner')
)

Known Bypasses#

False Positives#

Hunter Notes#

  • Add context to your queries by joining RDP remote interactive authentication events by the logon ID.