If you have been in security for any length of time then you have probably seen David Bianco’s Pyramid of Pain. One of the thoughts behind the pyramid is that the higher up you go the more cost to the adversary you bring. The top of the pyramid is where we really want to be as it’s much harder for an adversary to change how they operate and we, as defenders, can make it very difficult for them to carry out their operations if we can begin to find them at these upper levels..
I said yesterday in a tweet that a goal of mine is to be able to track an entire intrusion simply by the alerts that I generate. While that tweet may be a little far fetched, the sentiment behind the tweet is not. I want to know as much as I can about attacker activity so that I can effectively build a web of detection. The bigger and tighter the web, the more chances I will have to identify patterns that would be indicative of attacker activity. By studying past attacks, public reporting and any peer sharing I can shape the things that I should be going after.
Lets say that we have a fictitious actor that we are tracking that we’re calling FridayFun. Lets also say that we have been tracking FridayFun since 2012 when we initially responded to them HERE (Note: This is a link to the download of a memory forensics challenge I created in 2012). During the course of time we have identified some of the following regarding techniques used for Kill Chain 7 activity.
- The use of net commands for enumeration and lateral movement.
- The scheduling of remote tasks.
- The use of psexec for tool execution.
- Copying of files via command line.
Lets take a look at each of the above and how we may be able to find it in the Windows security events. Note that these methods require additional windows logging. I’m also including Splunk searches that can be used to find this behavior. If you aren’t a Splunk user, my hope is that you can take these queries and incorporate them into a solution or method you have available.
We have identified FridayFun often copying files to $ shares via the command line as in the example below.
copy thisisbad.bat \\192.168.56.10\c$\windows\thisisbad.bat
When a file is copied via the command the logs produced are different than if you were to copy them via Windows Explorer. Both methods produce multiple file share access events, but the Access Masks are different depending on method. From the command line, theses are the unique values:
The following query will identify the 3 unique access masks being created within the same second on a single machine.
sourcetype=wineventlog:security EventCode=5145 Object_Type=File Share_Name=*$ (Access_Mask=0x100180 OR Access_Mask=0x80 OR Access_Mask=0x130197) |bucket span=1s _time |rex "(?<thingtype>(0x100180|0x80|0x130197))" |stats values(Relative_Target_Name) AS Relative_Target_Name, values(Account_Name) AS Account_Name, values(Source_Address) AS Source_Address, dc(thingtype) AS distinct_things by ComputerName, _time |search distinct_things=3
For the scheduling of remote tasks, lets say that we have identified a pattern of behavior each time FridayFun has utilized this tactic.
- Query the remote machine for the local time (think about machines in different time zones).
- The remote task is created.
- The source machine queries the scheduled task on the remote machine.
This command sequence may look like:
- net time \\192.168.56.10
- at \\192.168.56.10 03:25 c:\windows\thisisbad.bat
- at \\192.168.56.10
The net time command and remote At query will both a produce a 5145 file share event where the IPC$ is the share being accessed. The Access Mask for these 2 events will be 0x12019f. The Relative Target Name will be different. A srvsvc named pipe will be created for the net time command while an atsvc named pipe will be created for the At query. For the creation of the scheduled task we are looking for 4698 events and specifically looking for At jobs in the Task Name.
The following query will identify the above 3 events occurring within an hour time frame on a single machine.
sourcetype=wineventlog:security (EventCode=4698 Task_Name=\\At*) OR (EventCode=5145 Object_Type=File Share_Name=*IPC$ Access_Mask=0x12019f (Relative_Target_Name=srvsvc OR Relative_Target_Name=atsvc)) |bucket span=1h _time |rex "(?<thingtype>(\\\\At.|srvsvc|atsvc))" |stats values(Relative_Target_Name) AS Relative_Target_Name, values(Account_Name) AS Account_Name, values(Task_Name) AS Task_Name, dc(thingtype) AS distinct_things by ComputerName, _time |search distinct_things=3
Friday fun often utilizes psexec to aid in execution on remote machines. We have identified them using commands such as the following:
psexec -accepteula \\192.168.56.10 -c gsecdump.exe
When looking for psexec being executed I have found that it may be more beneficial to look for indications on the destination side. Psexec can often be renamed and may be harder to identify on the source if you aren’t able to log the FileDescription metadata field of the binary when it executes. On the destination side a 5145 event will be created where the share name is ADMIN$ and the Relative Target Name is PSEXESVC.EXE. We are also looking for any new process creation within that same second to identify what psexec executed on the destination machine (Note: when psexec copies a file and executes it , it will be spawned from the IPC$ share).
This behavior can be identified by the following query.
sourcetype=wineventlog:security ((EventCode=4688 New_Process_Name!=*\\PSEXESVC.EXE New_Process_Name!=*\\conhost.exe New_Process_Name!=*\\dllhost.exe) OR (EventCode=5145 Share_Name=*ADMIN$ Relative_Target_Name=PSEXESVC.EXE)) |bucket span=1s _time |rex "(?<thingtype>(4688|PSEXESVC))" |stats values(Relative_Target_Name) AS Relative_Target_Name, values(Account_Name) AS Account_Name, values(Source_Address) AS Source_Address, values(New_Process_Name) AS New_Process_Name, dc(thingtype) AS distinct_things by ComputerName, _time |search distinct_things=2
Copying files from the destination to the source machine will produce different logs than if I were to copy files from the source to the destination. FridayFun has used commands such as the following.
copy \\192.168.56.20\c$\windows\system32\1.txt .\1.txt
This method is much like the first query with the exception of the Access Masks. The following query can be used to identify this behavior.
sourcetype=wineventlog:security EventCode=5145 Object_Type=File Share_Name=*$ (Access_Mask=0x100081 OR Access_Mask=0x80 OR Access_Mask=0x120089) |bucket span=1s _time |rex "(?<thingtype>(0x100081|0x80|0x120089))" |stats values(Relative_Target_Name) AS Relative_Target_Name, values(Account_Name) AS Account_Name, values(Source_Address) AS Source_Address, dc(thingtype) AS distinct_things by ComputerName, _time |search distinct_things=3
For those that like dashboards, I created the following to show what the output would look like.
As a defender, i think far too often we are focused on singular events that will give us that "ah ha" moment. Sure, there are some that may be a dead giveaway of a malicious actor operating in our environment, but I think often singular alerts are valued by their true to false positive ratio. With the method I showed above I can look for specific behavior, regardless of noise, and bucket events into previously identified attacker activity. When the number of unique events meets a certain value based on source, destination or user I can then raise an alarm. The more behavior that I can identify and query for, the larger my web becomes. I don’t know that I will ever be able to piece together wan entire intrusion by the alerts I generate, but I at least want to make it extremely difficult for any adversary to be able to operate freely in my environment.
I would love to hear any comments. You can find me on twitter under @jackcr.