Snort custom variables
-
I guess I don't have good forum etiquette, since a lot of my posts go unanswered (not only here but on the internet in general) but I hope that this backstory explains my intent enough that it's clear to see what I'm hoping to do. I will appreciate any feedback.
I have recently switched jobs and due to some confusion with the previous IT team who is no longer here, they enabled block rules at the bottom of their rule set. I don't think they realized this happens by default, but also had enabled logging. I have always just relied on the default deny rule with no logging enabled so I never noticed how much crap actually hits the firewall. This gave me a new idea but at the time I did not realize that someone thought of it before me. My new idea was to assume that if a connection attempt was made on a port that is closed that it would therefore be malicious, as the act of the attempted discovery was enough for me to consider them a bad actor. Obviously they're getting blocked by the firewall on the closed ports, but we host publicly available services, so it would be cool to block those bad actors on future connection attempts on the open ports as well. I thought SNORT would be great at performing this task, as it can run on the WAN interface before the firewall drops the denied traffic. I attempted to write my very first SNORT custom rule, but did not get very far. So I started to search the internet and came across an old post with a smart guy ranting about golden rules and young grasshoppers, so apparently my new idea ain't so new. That led me to the exact rules I was looking for, yay!
Please stick with me, SNORT is a great intrusion detection/prevention system (obviously because that's what it is) but the reputation component of it I'm not a huge fan of. PFblockerNG is phenomenal at this. I am using many of the IP feeds and it is working great. Here's the question, I would like SNORT to only alert/block bad actors that are not already being blocked by pfBlockerNG. Can custom SNORT rules use custom variables that are pfSense aliases/tables, and if so can the alias be the deny alias that pfBlockerNG creates? Thank you.
-
No, Snort (the binary, which does all of the actual work inspecting and blocking) can't communiate at all with any other package. Thus it has no way of knowing that pfBlocker even exists, much less any knowledge of what pfBlocker is blocking.
None of the pfSense add-on packages are really "aware" of each other in any meaningful way. Each package stands on its own.
And the Snort binary is incapable of ingesting aliases in its rules. Adding that capability would be almost a total rewrite of the Snort binary on pfSense. That kind of feature (ingesting aliases) is not part of the Snort package from upstream (the Snort Development Team at Cisco/Talos). The only customization added to Snort on pfSense is a custom blocking module compiled as an Output Plugin (the Snort term for such things). That is how Snort blocks traffic on pfSense. Regular Snort in the FreeBSD Ports repository, or Snort on Linux or Windows, can't block traffic because it lacks the custom blocking pluging.
-
Hi Bill, I understand that this is an off the wall idea, but I think it kind of makes sense for my use case above where only the custom golden rules are running on the WAN interface and using the LAN interface for the standard Snort implementation.
Custom golden rules I'm referring to:
alert tcp $EXTERNAL_NET [0:1023] -> $HOME_NET [0:1023] (msg:"Golden Rule BAD TCP"; classtype:attempted-recon; sid:9900001; rev:1;) alert udp $EXTERNAL_NET [0:1023] -> $HOME_NET [0:1023] (msg:"Golden Rule BAD UDP"; classtype:attempted-recon; sid:9900002; rev:1;) alert udp $EXTERNAL_NET any -> $HOME_NET [0:1023] (msg:"Golden Rule NO SERVER UDP"; classtype:network-scan; sid:9900003; rev:1;) alert tcp $EXTERNAL_NET any -> $HOME_NET [0:1023,![80,443]] (msg:"Golden Rule NO SERVER TCP"; classtype:network-scan; sid:9900004; rev:2;)
I didn't want to hijack the other post but I think bchok's mistake is what I want to do. I understand that the Pass Lists and the HOME_NET or EXTERNAL_NET are completely separate things. And in almost all cases those predefined variables should be left as default. Here is my confusion, the drop-down lists where you can manually define those variables pull from the Pass List tab.
If you choose any other option in the external net drop down list it completely breaks snort, as there is no way to implement a "!" in a custom list shown in the screenshot above. If there was, I could say $EXTERNAL_NET = !HOME_NET, !pfB_PRI1_v4 and then any ip already in the pfBblockerNG alias would not be considered an External Net ip and therefore not be evaluated and subsequently not alerted on or blocked.
By the way I really appreciate how quickly you were able to get the Pass List changes into development to fix my other issue.
-
@rtw915 said in Snort custom variables:
Hi Bill, I understand that this is an off the wall idea, but I think it kind of makes sense for my use case above where only the custom golden rules are running on the WAN interface and using the LAN interface for the standard Snort implementation.
Custom golden rules I'm referring to:
alert tcp $EXTERNAL_NET [0:1023] -> $HOME_NET [0:1023] (msg:"Golden Rule BAD TCP"; classtype:attempted-recon; sid:9900001; rev:1;) alert udp $EXTERNAL_NET [0:1023] -> $HOME_NET [0:1023] (msg:"Golden Rule BAD UDP"; classtype:attempted-recon; sid:9900002; rev:1;) alert udp $EXTERNAL_NET any -> $HOME_NET [0:1023] (msg:"Golden Rule NO SERVER UDP"; classtype:network-scan; sid:9900003; rev:1;) alert tcp $EXTERNAL_NET any -> $HOME_NET [0:1023,![80,443]] (msg:"Golden Rule NO SERVER TCP"; classtype:network-scan; sid:9900004; rev:2;)
I didn't want to hijack the other post but I think bchok's mistake is what I want to do. I understand that the Pass Lists and the HOME_NET or EXTERNAL_NET are completely separate things. And in almost all cases those predefined variables should be left as default. Here is my confusion, the drop-down lists where you can manually define those variables pull from the Pass List tab.
If you choose any other option in the external net drop down list it completely breaks snort, as there is no way to implement a "!" in a custom list shown in the screenshot above. If there was, I could say $EXTERNAL_NET = !HOME_NET, !pfB_PRI1_v4 and then any ip already in the pfBblockerNG alias would not be considered an External Net ip and therefore not be evaluated and subsequently not alerted on or blocked.
By the way I really appreciate how quickly you were able to get the Pass List changes into development to fix my other issue.
That would not necessarily prevent the IP from being evaluated nor alerted on. It depends on the rule. Some rules use $EXTERNAL_NET as a variable, but plenty of others do not.
I do not understand your desired use case here. Are you trying to turn Snort into pfBlockerNG, or vice-versa? If you want to block large swaths of the Internet, you should use pfBlockerNG for that, and put Snort on your internal interfaces running only the rules required to protect the exposures you have internally behind those interfaces.
I am actually not a fan at all of attempting to "block the world" with huge IP lists. It's a never ending whack-a-mole prospect, many of the lists are not well maintained and thus have legitimate IP space mixed in with the malware space, and you burden your firewall with keeping up with and testing thousands and even hundreds of thousands of IP addresses for every single packet that passes through. Just rely on the default DENY rule for that kind of blocking -- much less taxing on the firewall.
-
Thank you for your time and yeah I don't think I'm explaining this well. I'm not trying to turn Snort into pfBlockerNG or vice-versa. I'm trying to remove an area where there is overlap between the two.
@bmeeks said in Snort custom variables:
If you want to block large swaths of the Internet, you should use pfBlockerNG for that, and put Snort on your internal interfaces running only the rules required to protect the exposures you have internally behind those interfaces.
I am currently doing exactly as you suggested but wanted to implement an additional feature.
On the WAN interface I want Snort to sniff and only sniff the bad actors that are knocking on closed ports, so that they can be also blocked on future connections to open ports(80, 443). Said in a different way, the four rules I posted above would be the only four rules configured on the WAN interface to block the door knockers.
The thing is, the large swaths of IP's pfBlockerNG blocks would also be getting sniffed by those same four golden rules since snort takes a copy of the packet on the interface before it is filtered. This means the known bad actors that pfBlockerNG is already blocking could overlap with the bad actors (door knockers) knocking on closed ports.
To remove the overlap I could exclude the IPs already in the pfBblockerNG alias from the $EXTERNAL_NET var on the WAN interface, since it is only those 4 rules and they all use $EXTERNAL_NET -> $HOME_NET. The problem is the available dropdown for External Net in my screenshot can not currently include the "!" (not) operator.
-
@rtw915 said in Snort custom variables:
Thank you for your time and yeah I don't think I'm explaining this well. I'm not trying to turn Snort into pfBlockerNG or vice-versa. I'm trying to remove an area where there is overlap between the two.
@bmeeks said in Snort custom variables:
If you want to block large swaths of the Internet, you should use pfBlockerNG for that, and put Snort on your internal interfaces running only the rules required to protect the exposures you have internally behind those interfaces.
I am currently doing exactly as you suggested but wanted to implement an additional feature.
On the WAN interface I want Snort to sniff and only sniff the bad actors that are knocking on closed ports, so that they can be also blocked on future connections to open ports(80, 443). Said in a different way, the four rules I posted above would be the only four rules configured on the WAN interface to block the door knockers.
The thing is, the large swaths of IP's pfBlockerNG blocks would also be getting sniffed by those same four golden rules since snort takes a copy of the packet on the interface before it is filtered. This means the known bad actors that pfBlockerNG is already blocking could overlap with the bad actors (door knockers) knocking on closed ports.
To remove the overlap I could exclude the IPs already in the pfBblockerNG alias from the $EXTERNAL_NET var on the WAN interface, since it is only those 4 rules and they all use $EXTERNAL_NET -> $HOME_NET. The problem is the available dropdown for External Net in my screenshot can not currently include the "!" (not) operator.
You can't use dynamic aliases anywhere but in an actual Pass List to prevent blocks, so what you are asking for can't work anyway (even if the "!" operator were permitted). The traffic inspection engine in Snort has no concept of aliases and can't use them. So having a list of IP addresses in a pfBlockerNG alias is of zero use to Snort, because it can't even see them.
Go back and read what I wrote in the description of the new alias feature. It can't work with rules at all. You also can't use it in HOME_NET nor can you use it in EXTERNAL_NET. So what you want to do can't happen unless the Snort binary is completely rewritten for pfSense.
So what would you be trying to accomplish if you can't update the alias dynamically? You can only put IP addresses in HOME_NET or EXTERNAL_NET at startup of Snort, and then they can't be changed until the next shutdown and startup sequence. That's a limitation of the Snort binary itself.
-
Thank you for taking your time understanding what I was trying to accomplish. I had a brain fart not putting the limitations of the Snort binary you specified in the new alias feature with my ask.
-
@rtw915 said in Snort custom variables:
Thank you for taking your time understanding what I was trying to accomplish. I had a brain fart not putting the limitations of the Snort binary you specified in the new alias feature with my ask.
The concept of aliases is a pfSense thing. Snort has no concept of that, nor does it have any kind of similar feature. Native Snort does not even have a blocking ability. That ability on pfSense is provided by a custom output plugin I wrote that is compiled into Snort on pfSense only.
Native Snort works only with static IP addresses. I did, just recently, add the ability to use dynamic aliases in a Pass List so that some dynamic IPs could be prevented from getting blocked by the custom output plugin. But aliases only work in that specific custom module. And that module only exists in Snort on pfSense. It's not in Snort on any other platform. And that custom module only works for blocking. It has nothing to do with evaluating traffic against rules. The regular Snort code does that, and once it decides to "alert" on somthing, it refers to a list of linked functions it needs to call to "log" that alert. My custom blocking plugin is one of those linked "log" functions. But instead of simply logging, it also makes a FreeBSD system call to put the IP address in a
pf
firewall engine table. That's how the blocking works. -
@bmeeks
I have been using Snort on pfSense for 4 years now but at my previous company we used a WAF and that eliminated a lot of the noise. Your explanation helps me gain context around how the package works. I knew you were the maintainer, but did not realize you wrote the custom blocking plugin. This also explains how the the Snort rule header action of "alert" actually ends up dropping the traffic. I expected the rules to have the drop action described here.http://manual-snort-org.s3-website-us-east-1.amazonaws.com/node29.html
I still think your Cron job suggestion to restart Snort shortly after the pfBlockerNG Cron job updates the dynamic lists (as long as it doesn't conflict with Snorts Cron job) circumvents the static nature of Snort.
-
@rtw915 said in Snort custom variables:
@bmeeks
I have been using Snort on pfSense for 4 years now but at my previous company we used a WAF and that eliminated a lot of the noise. Your explanation helps me gain context around how the package works. I knew you were the maintainer, but did not realize you wrote the custom blocking plugin. This also explains how the the Snort rule header action of "alert" actually ends up dropping the traffic. I expected the rules to have the drop action described here.http://manual-snort-org.s3-website-us-east-1.amazonaws.com/node29.html
I still think your Cron job suggestion to restart Snort shortly after the pfBlockerNG Cron job updates the dynamic lists (as long as it doesn't conflict with Snorts Cron job) circumvents the static nature of Snort.
I modified the DAQ portion of Snort in early 2020 to use netmap with a kernel endpoint so that a viable inline IPS mode was possible on pfSense. The default behavior of DAQ when using netmap mode required two physical interfaces. This was not really useful on a firewall. I submitted my changes upstream to the Snort team and they were accepted, but thus far they have not published an update for DAQ that includes my accepted change. We do, however, use my modified DAQ module on pfSense.
The Inline IPS Mode of Snort does allow use of the DROP action, and thus the ability to distinguish between DROP and ALERT. The Legacy Blocking Mode, which uses my custom blocking module, cannot do that.
I also created the Suricata package for pfSense and put the same technology in that package (a Legacy Blocking Mode). Suricata already had a netmap inline mode that allowed OS kernel stack endpoints.
So if you have a compatible NIC (that supports the FreeBSD kernel netmap device), then you can switch to Inline IPS Mode and use the SID MGMT tab features to change selected rules or entire categories to DROP while leaving other rules at ALERT. Thus you gain finer control over the blocking action. When you use Inline IPS Mode, there is no need for a Pass List (and no facility for interpreting one anyway), so Pass Lists are disabled with Inline IPS Mode. You should instead implement a pass list function, if needed (and that is really only if you have a honey pot), using PASS rules. You don't really need a Pass List with Inline Mode because you are not blocking an IP. You are just dropping individual packets when they match. Blocking an IP blocks everything, so you sometimes need a safety belt to prevent that, hence the Pass List. With Inline IPS Mode, you just drop individual packets that trigger a rule. Other packets, that don't trigger the rule, pass unmolested.
-
@bmeeks You are awesome!
Once again, mind blown. I did not realize that native Snort only drops the matching packet and does not block the IP. This does raise a couple of questions though, when running Snort in inline mode does the packet drop still show up in the pfSense firewall logs? Also does this mean that Snort is only inspecting the traffic that has already been filtered by the rules on the WAN, or for that matter any interface?
Actually I found where you have written extensive info about the new inline mode and I'm going to have a nice read over dinner.
https://forum.netgate.com/topic/143812/snort-package-4-0-inline-ips-mode-introduction-and-configuration-instructions
Thanks again!
-
@rtw915 said in Snort custom variables:
@bmeeks You are awesome!
Once again, mind blown. I did not realize that native Snort only drops the matching packet and does not block the IP. This does raise a couple of questions though, when running Snort in inline mode does the packet drop still show up in the pfSense firewall logs? Also does this mean that Snort is only inspecting the traffic that has already been filtered by the rules on the WAN, or for that matter any interface?
Actually I found where you have written extensive info about the new inline mode and I'm going to have a nice read over dinner.
https://forum.netgate.com/topic/143812/snort-package-4-0-inline-ips-mode-introduction-and-configuration-instructions
Thanks again!
Snort sits between a physical network interface and the firewall engine. So if on the WAN, packets hit Snort before they hit the firewall (for inbound traffic, outbound is of course the opposite - hitting the firewall before Snort). The LAN is the same idea. That's why when Snort is on the WAN, all local firewall networks show up after NAT is applied and thus all local hosts show as the firewall's static WAN IP address. That makes it not easy to identify which host is the source (or destination) and may be compromised. Running the IDS/IPS on the LAN or other internal interface makes more sense. Then local IPs show up as themselves while external IPs still show up as themselves.
The netmap kernel device is a pipe that sits between the NIC hardware driver and the FreeBSD networking stack. Snort with Inline IPS Mode sits in that pipeline and forms a gate. Packets that don't match rules are allowed to pass from the NIC to the kernel (or vice-versa for outbound traffic). Packets that match a DROP rule are simply dropped in the pipe and not passed on to the kernel (for inbound) or the NIC (for outbound). This action is not logged by the firewall because again, Snort is a bolt-on accessory package. It and the firewall don't communicate nor coordinate with each other. When Snort drops a packet, it notes it on the ALERTS tab by printing in red and putting a thumbs-down icon in the Action column. The only way anything shows up in the firewall logging is if Snort is configured to log to syslog. But even that is just to syslog and not specifically to the firewall log. Snort provides its own Dashboard Widget to show what it is doing (if enabled on the Dashboard). Plus it logs things in its own logs and on the ALERTS tab.
I think a lot of folks have a basic misunderstanding of pfSense in terms of being a firewall. All pfSense really is, is a collection of PHP modules that construct a GUI to make creating a configuration file for the native FreeBSD
pf
firewall easy. If you are familiar withiptables
on Linux,pf
on FreeBSD is essentially the same thing. It's a binary tool that runs as a daemon and uses a text-based configuration file to know what to do. On pfSense, the GUI just gives you a clickety-click method of creating that text-based configuration file for thepf
firewall binary to use. Snort is the same way. The GUI package just gives you a clickety-click method of creating thesnort.conf
configuration file the Snort binary needs in order to start and run. But on pfSense, I created some customizations of the Snort binary to give users some additional features. Those include Legacy Blocking (the mode that blocks an IP for every ALERT), and the Inline IPS Mode that uses the netmap kernel device to allow dropping of individual packets instread of needing to block an IP entirely. -
@bmeeks said in Snort custom variables:
I don't drink but I would like to buy you a beer.
-
@rtw915 said in Snort custom variables:
@bmeeks said in Snort custom variables:
I don't drink but I would like to buy you a beer.
Thanks, but I'm not a drinker either ... . Not that I'm against it, but just never got into it.
-
@bmeeks said in Snort custom variables:
You don't really need a Pass List with Inline Mode because you are not blocking an IP. You are just dropping individual packets when they match.
Over dinner I read through the snort inline thread and the adjustability of the rules so you can alert or block is huge. I can see so much value with running snort inline. However, I was pretty bummed out to see the limitations with lag and VLANS. I use both of those technologies when architecting highly available networks.
It got me thinking though, that the inline mode and the custom output plugin you wrote really provide two different strategies. Along with some of the other posts you've written I'm starting to question my IPS approach.
My approach has been to identify bad actors in any way possible so that they can be blocked to prevent future harm. So say for example a bad actor is attacking using an ActiveX vulnerability and even though our environment doesn't use ActiveX I still have those rules enabled. This way if the same attacker moves on to use a SQL injection attack they are already blocked, as they don't become unblocked in my case for an extended period of time. At which point I'm hoping they'll just move on.
-
@rtw915 said in Snort custom variables:
@bmeeks said in Snort custom variables:
You don't really need a Pass List with Inline Mode because you are not blocking an IP. You are just dropping individual packets when they match.
Over dinner I read through the snort inline thread and the adjustability of the rules so you can alert or block is huge. I can see so much value with running snort inline. However, I was pretty bummed out to see the limitations with lag and VLANS. I use both of those technologies when architecting highly available networks.
It got me thinking though, that the inline mode and the custom output plugin you wrote really provide two different strategies. Along with some of the other posts you've written I'm starting to question my IPS approach.
My approach has been to identify bad actors in any way possible so that they can be blocked to prevent future harm. So say for example a bad actor is attacking using an ActiveX vulnerability and even though our environment doesn't use ActiveX I still have those rules enabled. This way if the same attacker moves on to use a SQL injection attack they are already blocked, as they don't become unblocked in my case for an extended period of time. At which point I'm hoping they'll just move on.
The limitation with VLANs and LAGG is due to the way the netmap kernel device is plumbed within FreeBSD. It's not a Snort limitation. The netmap idea had great promise when it was introduced a few years ago into FreeBSD and Linux, but some of the grand plans have not taken shape. Thus the various limitations of the technology. You can read up on netmap via Google searches.
As for IDS/IPS strategy, there are as many opinions on what is "right" as there are IDS admins. But generally I favor keeping the workload on my firewall as light as possible while still affording protection. The reality is that almost any firewall today is pretty darn secure. This is especially true if you limit the amount of third-party stuff (such as packages) that you install on it. Remember each installed package brings in a bunch of shared libraries that may, in turn, bring in still more shared libraries. And any of these libraries can harbor vulnerabilities. So the fewer packages, the better.
As for blocking, as I stated, I'm not a fan of putting in specific blocks for the world. Put in Pass rules for explicitly what you want to come in (unsolicited), and then let the default deny rule take care of everything else. If you don't trust your firewall to be secure on its own and by default, why are you using it? (Rhetorical question, not an accusation ... ).
For IDS/IPS, run the rules that protect the exposures you have. Don't waste CPU and RAM resources on rules that protect against threats you are not vulnerable to. Spend your time and effort keeping your internal machines patched with the latest security hotfixes. That is 99% of cyber security right there! And it's much more effective than running every pfBlockerNG IP list or Snort rule in existence.