Recently, SentinelOne had a blog post about how Lockbit Ransomware was using Windows Defender to side load Cobalt Strike. Considering that this technique I sat down to write up a query(that is available at my Github here) for a custom detection of this procedure based off the information in the SentinelOne Blog post. Here I am going to go through the query and break it down.
The full query looks like this:
DeviceFileEvents | join DeviceFileCertificateInfo on DeviceName //This is for checking if it is a signed version of the dll joined on Device Name for distinct usage | where Timestamp > ago(7d) // look back over the past week | where InitiatingProcessFileName == "MpCmdRun.exe" and IsSigned // checks to make sure that mpclient is being run | where FileName contains "mpclient"// checks for the misused dlls. | where FolderPath !contains "\\programdata\\microsoft\\windows defender\\platform" // do not check the normal location for the dll being run | distinct DeviceName, Timestamp, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessFolderPath
So when I started writing the query I started simple. Look for the dll name which is mpclient not running from its normal location. this mean I would be starting in the DeviceFileEvents table. It simply came about to look like this:
DeviceFileEvents | where FileName contains "mpclient" | where FolderPath !contains "\\programdata\\microsoft\\windows defender\\platform"
This query returned the maximum number of results. First thing I noticed was the duplicate DeviceNames(computer names) in the list, so I added a line using the distinct command to get rid of that.
DeviceFileEvents | where FileName contains "mpclient" | where FolderPath !contains "\\programdata\\microsoft\\windows defender\\platform" | distinct DeviceName, Timestamp, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessFolderPath
While better, this query still was noisy. Updaters and some normal network services tended to call upon that dll in some other locations. So the question became how could I reduce the noise without blinding myself to extra paths? I went back into the original blog post and saw that the intel said the dll was being run using the MpCmdRun.exe command and that the command was legit and signed. Unfortunately the DeviceFileEvents table does not have a way of checking for signatures. While I could have done this:
DeviceFileEvents | where InitiatingProcessFileName == "MpCmdRun.exe" | where FileName contains "mpclient" | where FolderPath !contains "\\programdata\\microsoft\\windows defender\\platform" | distinct DeviceName, Timestamp, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessFolderPath
I felt that making sure the Initiating Process was signed would also help quell the noise a little. Checking for that required joining a table called DeviceFileCertificateInfo. To bring in another table one must use the join command. The join command requires you to join the table with a common point. I originally thought the SHA1 of the process would be perfect, but came to realize that created a problem with my distinct output, so joining them on the DeviceName was the better option. When doing a join it never hurts to double check what field you can join the tables together on, as there are usually a number of options and it does make a difference.
| join DeviceFileCertificateInfo on DeviceName
Once joined I could use the IsSigned field to make sure there was a signature for the file/process. The question is where to put it. In the initial query I put it after checking for mpclient, but came to realize that doing it that way was also checking for a valid signature on the mpclient.dll file that was malicious. Since there would be no guarantee this would be the case I moved the join to immediately after the table call and added the IsSigned as a must have condition only for the InitiatingProcessFileName check.
At this point we have the full query as shown at the start. using a couple of backslashes you can comment out any of the lines in the query for testing different parts of it.
When writing a query like this tables and field are listed on the left hand side of the Advanced Hunting screen. The value of having that right at your fingertips is huge. The hardest part is finding detailed information on fields or commands themselves. Even Microsoft’s own documentation on the web is pretty poor overall, so patience with trial and error is key. Kusto Query Language I have found is a powerful query language, and something people will need to know more going forward.