What is lateral account movement?
Lateral account movement is a technique used by attackers to traverse through a network, starting from a compromised host. This technique is generally used to identify and gain access to sensitive data, with the possibility for exfiltration where desired. There are also a lot of confirmed cases of cyberattacks where malware infects a host, and then spreads to other hosts using inbuilt and trusted Windows functions such as SMB and PsExec.
This generally starts by collating as much information regarding the compromised host and then attempting to enumerate further across the network/domain for a target. Once they have acquired a target, they will attempt to gain access to the target either by using credential harvesting tools such as “PwDump” and “MimiKatz”, brute forcing logins, or using application specific vulnerabilities.
How do you detect it?
Despite the varying types of networks found within organisations today, there are a common set of IOCs (Indicators of Compromise) regarding lateral account movement attempts. The most common and noisy indicators within event logs for lateral movement attempts are failed logins; the most common event IDs for this are 529 & 4625. Each method of lateral movement has its own set of associated event IDs. For example, attempts to login to accounts via SMB will generate event IDs 552 or 4648 (logon attempt using explicit credentials), and PsExec will show 601 or 4697 (service was installed in the system).
After this activity, attackers will generally attempt to cover their tracks in several methods. This can generally be quite noisy; for example there is “sdelete” which deletes files once they’ve been overwritten a large amount of times, “timestomp” which alters a files timestamps (indicator of event ID 4663 “An Attempt Was Made To Access An Object” where the “WriteAttributes” token is set to “Audit Success”) and “wevtutil” which is used to delete Windows event logs (indicator of event ID 104 “The Application log file was cleared”).
For a more detailed breakdown of tracking lateral movement using event logs, take a look at the following JPCERT report.
Example analytics rule
For this example, I am going to display and talk through an analytics rule written in the Azure Kusto Query Language (KQL). Essentially what I wanted this analytics rule to do is detect lateral movement attempts via explicit credentials, from one account to another.
let timeFrame = 1h;
let ignoredAccounts = dynamic([“IgnoredAccountName”]);
let knownTargets = datatable (user:string)
[“John.Doe , Jane.Doe”];
let allChanges = SecurityEvent
| where TimeGenerated >= ago(timeFrame)
| extend SubjectUserName = tolower(SubjectUserName), TargetUserName = tolower(TargetUserName)
| where EventID == 4648 and SubjectUserName !endswith “$” and TargetUserName !endswith “$” and SubjectUserName != TargetUserName and SubjectUserName !in (ignoredAccounts) and TargetUserName !in (ignoredAccounts)
| where SubjectUserName != “-” and TargetUserName != “-” and isnotempty(SubjectUserName) and isnotempty(TargetUserName)
| extend user = strcat(SubjectUserName, ” , “, TargetUserName)
| distinct user;
allChanges | join kind = leftanti knownTargets on user
Let us break that down into steps:
Let timeFrame = 1h;
This sets a value for the TimeGenerated variable for the query to lookback; this is done so that the organisation can easily modify the lookback time dependant on requirements.
let ignoredAccounts = dynamic([“IgnoredAccountName”])
Here we can better set the scope for which accounts to use by negating those which are not relevant to this detection.
let knownTargets = datatable (user:string)
[“John.Doe , Jane.Doe”];
This further aids with tuning the incident logic to not alert on accounts which provide no security value. For example, a standard activity where one account attempts to switch to one of their own accounts. This data table is dynamically expandable dependant on the organisation’s requirements.
let allChanges = SecurityEvent
Specifies a custom table called “allChanges” which we can later compare to our known targets for anomalies within the SecurityEvent table.
| where TimeGenerated >= ago(timeFrame)
Sets how far to look back in the SecurityEvent table. As previously mentioned, the timeFrame variable can be modified to meet the organisations requirements.
| extend SubjectUserName = tolower(SubjectUserName), TargetUserName = tolower(TargetUserName)
This normalises the SubjectUserName and TargetUserName fields to lowercase text, to prevent inaccurate matches.
| where EventID == 4648 and SubjectUserName !endswith “$” and TargetUserName !endswith “$” and SubjectUserName != TargetUserName and SubjectUserName !in (ignoredAccounts) and TargetUserName !in (ignoredAccounts)
This specifies the query to only look for event IDs 4648 (logon attempt using explicit credentials), where neither of the accounts is a machine account (common naming scheme is where the account ends with a “$”), where the subject user isn’t equal to the target user (one user switching to a different user) and where the subject and target user aren’t listed in the predefined list of accounts to be ignored.
| where SubjectUserName != “-” and TargetUserName != “-” and isnotempty(SubjectUserName) and isnotempty(TargetUserName)
Ensuring the subject and target user are not logged as blank, and that either fields aren’t empty, so we only receive accurate data regarding accounts switching to other accounts.
| extend user = strcat(SubjectUserName, ” , “, TargetUserName) | distinct user;
This concatenates both fields into a singular column for easier comparison, and then only displays the unique values.
allChanges | join kind = leftanti knownTargets on user
This joins the allChanges table on the knownTargets table, only displaying unique values not present within the predefined incident tuning of knownTargets.
How do you prevent it?
As per NCSC guidelines, ensuring that strong authentication and proper security methodologies are in place will aid in both the prevention of initial access and lateral movement. Please see the following NCSC document regarding preventing lateral account movement within enterprise networks.