What the Heck PsExec!
Service creation and related events can be caught using existing methods, but having an accurate correlation between service creation and deletion events would allow even more activities to be reliability identified.
With Azure Sentinel being our current SIEM of choice, we came up with the following.
Event | where EventID == 7045 | where Source == "Service Control Manager" | parse EventData with * '<Data Name="ServiceName">' InstalledService '</Data>' '<Data Name="ImagePath">' Exe '</Data>' * | extend SourceTimeRounded = bin(TimeGenerated, 1s) | project SourceTime = TimeGenerated, SourceTimeRounded, Computer, UserName, InstalledService, Exe, SourceEventID = EventID | join kind=inner ( SecurityEvent | where EventID == 4674 | where AccessMask has "%%1537" | extend TargetTimeRounded = bin(TimeGenerated, 1s) | project TargetTime = TimeGenerated, TargetTimeRounded, Computer, UserName = Account, InstalledService = ObjectName, TargetEventID = EventID ) on UserName, Computer | where (TargetTimeRounded - SourceTimeRounded) between (0s .. 24h) | summarize arg_max(SourceTime, *) by InstalledService | project SourceTime, SourceEventID, TargetTime, TargetEventID, Computer, UserName, InstalledService, Exe | sort by SourceTime
When a service is created on a host, EventID 7045 (a new service was installed) is logged from where two new fields, InstalledService and Exe are pulled from the available event information.
We then look for EventID 4674 (an operation was attempted on a privileged object), which can be used to determine if/when a service is deleted. In this instance the translation of %%1537 relates to delete. This post from 2015 was a great help with these code translations.
Finally, we’re looking within a 24-hour period in which such a pattern may emerge. This may be too long, or even too short for many organisations, so please change accordingly. As several hits may be seen in quick succession (4674 events can be quite chatty), we’re limiting this to just the newest entry of any result set.
We should also note that in testing we sometimes saw strange activity where the service creation event would actually show in logs milliseconds after the service deletion event (this occurred with variants of PsExec from Metasploit, for example) where the two events would generally happen in close succession (more on this below within the “Testing with PsExec” section).
We needed a method to ensure that both events were captured in sequence, hence the new SourceTimeRounded and TargetTimeRounded fields were introduced. These were essentially used to round down to the nearest second. Although potentially not the cleanest (if you have any ideas, we’d love to hear), it did the job.
Testing with PsExec
During testing we noted that certain PsExec tools handle service creation/deletion differently. For example we found that both the Sysinternals version of PsExec as well as Metasploit’s exploit module both create and terminate services almost immediately, whereas Impacket’s variant only terminates the service after exiting the supplied shell, resulting in the delayed creation of EventID 4674.
These may only be minor differences, but differences that could throw off a SOC looking for specific patterns, timings or behaviours.
In the following screenshot it’s possible to see that using the aforementioned query, each event is caught, with an obvious delay in the Impacket event captures.