Security Operations Platform arrow_forward expand_more
Solutions arrow_forward expand_more
Why Chronicle arrow_forward expand_more
Why Chronicle

Rely on a modern approach to threat detection and response.

Why Chronicle
Partners arrow_forward expand_more
Resources arrow_forward expand_more
Security Operations Platform arrow_forward expand_more
Solutions arrow_forward expand_more
Why Chronicle arrow_forward expand_more
Why Chronicle

Rely on a modern approach to threat detection and response.

Why Chronicle
Partners arrow_forward expand_more
Resources arrow_forward expand_more
IDC Study: Customers cite 407% ROI with Google Chronicle. Learn More IDC Study: Customers cite 407% ROI with Google Chronicle. .
New to Chronicle: Fall is the perfect time for CIDR, particularly in functions and reference lists

This is the 10th post from Google Cloud Principal Security Strategist John Stoner as part of his deep-dive "New to Chronicle" series, which helps propel forward security teams either new to SIEM or replacing their SIEM with Chronicle. You can view the entire series here.

Apologies for the wordy title folks, but this time of year in Virginia is the time of apple harvesting and apple cider, so why not some free association!

Today, we won’t talk about the ways to enjoy cider (the kind you drink), but we will talk about ways to use CIDR (classless inter-domain routing) notation with Chronicle when writing rules!

Over the past few posts, we introduced a number of functions to work with strings, including regular expressions. Our last post introduced reference lists that would match exact strings as well as lists that contain regular expressions. Normally, I would tell you that if you haven’t read those yet, I will patiently wait while you read them before continuing here, but because we are moving away from strings and regular expressions and charting new territory, I’m going to have to assign you some homework to go back and read those on your own time. Sorry about that!

Today we are working with network addresses and introducing CIDR reference lists, as well as a network function that will provide content developers a way to more easily target their rules to specific portions of their networks.

Let’s start with the function. For dedicated readers of this blog, you will recall that we can use the re.regex function to match on a string. If we wanted to isolate a rule to a specific netblock for the principal.ip field in YARA-L, we could use re.regex to craft a line of criteria for the entire 10.0.0.0 to 10.255.255.255 address space, like this.

re.regex($event.principal.ip, `(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)`)

OK, you in the back with the smirk on your face. Yes, you are right that you could also represent this by using this notation as well:

$event.principal.ip = /10\./

However, if we need to look across variable size netblocks or multiple netblocks, this could get a little more elaborate. How elaborate? Well, if we wanted to filter our rule across all of the RFC1918 (non-routable IP addresses) space, our regex would look something like this.

re.regex($event.principal.ip, `(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)|(192\.168(?:\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2}$)|(172\.(?:1[6-9]|2\d|3[0-1]) (?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2})`)

The good news is that with the net.ip_in_range_cidr function, we don’t have to do this. In fact, all we really need to do is calculate the CIDR notation by taking our starting and ending IP addresses and using our favorite method to convert IP address ranges to CIDR notation. You might do this in your head, or have a cheat sheet, or a specific web site. In the example below, we entered the range 10.0.0.0-10.255.255.255 which converts to 10.0.0.0/8 in CIDR. From there, we can add that value to our function and we’re done.

Our rule will now look for the principal.ip to be one of those IP addresses in that entire range.

https://www.ipaddressguide.com/cidr

net.ip_in_range_cidr($event.principal.ip, "10.0.0.0/8")

If we wanted to focus our rule to isolate on all private netblocks, as defined in RFC1918, we could do it easily, like this:

net.ip_in_range_cidr($event.principal.ip, "10.0.0.0/8") or net.ip_in_range_cidr($event.principal.ip, "172.16.0.0/12") or net.ip_in_range_cidr($event.principal.ip, "192.168.0.0/16")

Don’t forget we also have the NOT modifier as well so if we wanted to consider any netblock except 10.0.0.0/8, we could do that too!

not net.ip_in_range_cidr($event.principal.ip, "10.0.0.0/8")

Good so far? Alright, let’s apply this to a YARA-L rule. Let’s build a detection that informs us when the netblock that our Windows servers reside in are seeing networking connections over port 3389 (RDP - Remote Desktop Protocol) from somewhere other than that specific IP netblock. Yes, we can dress this up further, but this serves as a great starting point!

rule inbound_rdp_network_detection {  meta:    author = "John Stoner"    description = "Detect inbound traffic destined for our server netblock over RDP port 3389"    severity = "Informational"

 events:    $event.metadata.event_type = "NETWORK_CONNECTION"    $event.target.port = 3389    //principal.ip is where traffic originates from    not net.ip_in_range_cidr($event.principal.ip, "10.128.0.0/24")    //target.ip represents our internal network    net.ip_in_range_cidr($event.target.ip, "10.128.0.0/24")    $event.target.hostname  = $targetHost

 match:    $targetHost over 60m

 condition:    $event }

In the events section, we are looking for network connections with a target port of 3389 to focus just on RDP traffic. In our example, all Windows servers reside in the 10.128.0.0/24 netblock. We will use the net.ip_in_range_cidr function to establish that all network connections must originate elsewhere, by adding a not to the start of our criteria as it pertains to principal.ip. The destination of this network connection is in the target.ip field so we will use our function with this field as well. From there, we are going to use target.hostname to create a match variable and look for events occurring over a 60 minute window for grouping. We could adjust this window to change the frequency and of course we could refine our rule further to narrow our results, but hopefully this provides a nice introduction to the net.ip_in_range_cidr function.

Notice how we have a set of detections grouped by the targetHost.

If we expand the last detection, we can see in the raw and UDM event the IP address that targeted one of our Windows servers in the netblock, as well as the country where the connection originated from.

Let’s pivot to the list manager and CIDR syntax. Reference list syntax in its simplest form looks like this: <field_name> in %<list_name>. When we covered lists with regex, we added the term regex after the operator in. With CIDR, our syntax looks like this: <field_name> in cidr %<list_name>.

Notice in our list manager, we have a list called suspicious_cidr_blocks and a set of IP netblocks in CIDR format listed.

It has a little flag next to that denotes that this list’s syntax will use CIDR and not string matching, which does not have a flag next to it. It is important to note that when creating a list, setting the syntax type to either string, RegEx or CIDR should be carefully considered. As of the writing of this blog, once it is set and saved, it can’t be changed.

With our list of IP netblocks created, we can take our previous rule and make a slight change, which can be seen in bold. In this example, we still care about network traffic coming into our Windows netblock over 3389, but rather than triggering on anyone outside of the netblock attempting a connection, we only want to be alerted when specific netblocks are attempting connections. Perhaps we have determined that a server on the internet is going to continually have connections attempted to it, but there are specific IP ranges that we want to know about when they attempt to connect.

rule inbound_rdp_network_detection_watchlist {

 meta:    author = "John Stoner"    description = "Detect inbound traffic destined for our server netblock over RDP port 3389"    severity = "Informational"

 events:    $event.metadata.event_type = "NETWORK_CONNECTION"    $event.target.port = 3389    //principal.ip is where traffic originates from    $event.principal.ip in cidr %suspicious_cidr_blocks    //target.ip represents our internal network    net.ip_in_range_cidr($event.target.ip, "10.128.0.0/24")    $event.target.hostname  = $targetHost

 match:    $targetHost over 60m

 condition:    $event }

When we test our rule, we get detections, including this one, where the principal.ip is 213.226.123.38.

We don’t have that IP address listed specifically, but because we made a determination that the entire address block was of concern, our rule will fire anytime we see an IP address from that block.

This ability to use CIDR notation in functions and in lists (along with regex) opens up a number of possibilities when building detections. Because the CIDR and regex list functionality is new, as of this writing it is constrained to a maximum of 2 CIDR or regex lists per rule and seven total lists to a rule, as well as a maximum of 50 lines per list CIDR and regex list. However, this provides a great way to start leveraging lists and even more functions to draw inspiration from when building your rules.

See you next time!

New to Chronicle Series

Let’s work together

Ready for Google-speed threat detection and response?

Contact us Visit the contact us page