New to Google SecOps" is a deep-dive series by Google Cloud Principal Security Strategist John Stoner which provides practical guidance for security teams that are either new to SIEM or replacing their SIEM with Google SecOps.
This month we are dedicating New To Google SecOps to common questions we receive from users. Let's dive into this second edition of User Mailbag.
I understand the pain that this one causes but there is a straightforward method to address this. Let’s start with the port fields. The UDM field list defines port fields as integer fields. This means that when they are used in search or rules, they are defined as the value itself whereas string fields will be enclosed in quotes. Here is a search to illustrate the different syntax used.
Taking this a step further, reference lists are expecting strings, but as we just mentioned, a port is an integer, not a string. The solution to this is to use the strings.concat function which will convert our integer to a string which can then be compared to a string reference list.
strings.concat($net.target.port,"") = $target_port
$target_port in %suspicious_ports
Admittedly this rule is overly simplified and will need to be improved to identify network traffic flow, netblocks and more, but this will provide a good starting point. In the events section, we can use the strings.concat function to output the port value we are interested in, append a null string to it and output it to a placeholder variable. In the following line, we then take that placeholder variable and compare that to our list called suspicious_ports.
In our test rule results, we can see that ports including 135 and 445 are returned which align to the listing of ports in our list.
We won’t be able to cover every permutation here, but here are a few tips that should help.
This last bullet is what we are highlighting below. Here are a few different methods to identify an event log being cleared from a Windows system.
Lines 17-21 contain one method, 23-26 a second and 28-36 a third. Notice how each one is bounded with parenthesis and how each uses and/or to separate terms. If we don’t do this, that nice little green check mark in the corner turns red and we can’t save our rule.
Digging a little deeper into our third method, we can see that we have three distinct values we are looking for in specific fields and then we have two additional regular expression strings and we are expecting one or the other to meet this specific set of conditions. Notice that we have a parenthesis around those two pieces of criteria (lines 33-34) nested within the larger criteria and how we are using and/or throughout our criteria. Finally, notice that line 37 is outside of all the parenthesis and applies to any of the three methods listed above it. Because we are outside of the parentheses, we are back in a place where the and operator is assumed.
Pro tip: Using tabs to stagger criteria in the events section provides a nice way to visualize multiple sets of criteria and to more easily track where your and/or/not operators should be.
Absolutely. In the Impacket section of the CISA Joint Advisory, it references the use of wmiexec which redirects output to a file containing an epoch timestamp for its name. In the example below, a command was executed by wmiexec.py and the logged event included a command line that looks like this:
cmd.exe /Q /c dir 1> \\127.0.0.1\ADMIN$\__1684956600.123456 2>&1
The first thing to mention is that if you want to get familiar with Impacket (or any other tool), it’s best to load and test it to experience the different logs that it generates in your environment. That said, if we wanted to build a strict match, we could start our pattern with the cmd.exe. The problem with that approach is 1) PowerShell can be used as well, 2) even if you encounter cmd.exe /Q /c , the command that follows it could be just about anything and 3) cmd.exe /Q /c could be used legitimately. With that in mind, let’s start our match after the command is issued. Because wmiexe.py is using command redirection to the admin$ share, we could build a regular expression that starts with 1> and ends with 2>&1. Additional variation is possible, but for now, we will keep the admin$ share in our regular expression for the purpose of this example.
It is important to note that greater than (>), is stored in Google SecOps as >, less than (<) as < and ampersand (&) as &. So our regular expression will look something like this;
re.regex($process.target.process.command_line, `1>.*\\ADMIN\$\\__.*2>&1`) nocase
Pro tip: When working with command lines, always leverage the modifier nocase. I like using nocase on most non-enumerated fields, but always use it with command line.
This is why I mention ingesting sample data if possible. If we ingested the data into our Google SecOps instance, we would see that the command_line value is stored in Google SecOps like this:
target.process.command_line = "cmd.exe /Q /c dir c:\\windows 1> \\\\127.0.0.1\\ADMIN$\\__1689025024.9777138 2>&1"
Of course, there are variations but this serves as a good place to start when building our detection for wmiexec.py. Here are the results of our test rule.
That last question was a bit heavier than I intended but hopefully these topics from the mailbag were helpful and can be applied to your rule writing moving forward!