Search code examples
alertrulessignaturesnortbotnet

Snort rule doesn't generate alerts when hosts responding simultaneously


alert tcp any any -> any any (msg:"PRIVMSG from an IRC channel suspecious act"; content:"PRIVMSG"; offset:0; depth:7; nocase; dsize:<64; flow:to_server,established; tag:session,300,seconds; classtype:bad-unknown; sid:2000346; rev:4;)

The above rule is written to monitor bots responding messages to the botmaster. The rule is working fine, but only when one bot making the respond and there is no alert or even one alert for one host when more than one host responding simultaneously. I have changed the session time to 30 or 150 but no luck.

Any tips or tricks to make it efficient?

Thanks.

-Aymen


Solution

  • I don't think I am fully-grasping what you are trying to do with this rule. Could you clarify the specifics on why you're looking for just a PRIVMSG without a channel name (or even a bot's nick name, for that matter)?

    That said, some quick suggestions on making the rule more efficient. Adapt as necessary:

    • dsize and flow are considered "discrete" options and should be specified before any payload options (such as content and its modifiers, etc). Discrete options are generally checking protocol-specific fields and never touch the payload, so they are extremely fast (second only to the fast-pattern matcher). I.e., you should make flow come after msg, and then dsize after flow.

    • Next, you're probably setting the timer for tag too high. There's a built-in cutoff for tag, called the tagged_packet_limit, and it defaults to 256 packets. So your rule would cease tagging on one of three possible conditions (whichever happens first):

      • End of the session.
      • After 5 minutes (300 seconds).
      • 256 packets are tagged.


      The seconds metric can fluctuate a bit based on other factors on your sensor, such as link speed, system load, etc. Thus, the rule might stop tagging packets after 297 seconds or 303 seconds. It's probably better to use the packets metric and set it to a really high value, such as 1000. This has the added benefit of overriding tagged_packet_limit. You can even specify multiple metrics simultaneously:

      tag:session,240,seconds,8000,bytes,1000,packets;
      
    • You should consider using a pair of flowbits to control when the tagging operation begins and ends:

      <discrete options>; flowbits:isnotset,botnet.tagged; <payload options>; flowbits:set,botnet.tagged;
      

      This prevents the tagging operation from being interrupted when another packet matching the rule comes across the wire, because the flowbits will enforce that the rule has already alerted once, and is currently tagging the traffic of interest.

    • You should define a variable for common IRC ports and use it in the destination ports field. Snort uses the destination port field in conjunction with the fast-pattern matcher to optimize which rules a packet is checked against (i.e., HTTP traffic shouldn't be checked by a rule targeting IRC). In lieu of a destination port, it will try to use a source port (the specifics of this are available in comments at the top of src/pcrm.c in the source code). If the target IRC server only uses a single port, then use that instead. A single port is better than a group of ports, but a group of ports is WAY better than just any:

      portvar IRC_PORTS [6666:6669]
      
    • Lastly, You need to use a unique string to truly take advantage of the fast-pattern matcher. PRIVMSG is extremely common in the IRC protocol, so if you're trying to restrict the rule to a very specific channel, consider something like:

      content:"PRIVMSG #foobar:"; fast_pattern:only;
      


      The fast_pattern:only; bit, available in snort-2.9.0 and up, only uses the content match within the fast-pattern matcher and will not re-use it in the actual payload search. Side-effect: you can't use additional content matches relative to this content match. and this match is performed in a case-insensitive manner!

      It's hard to wrap one's head around this little change when coming off of 2.8.6, but a quick way to know if it works for you is, "Do I only care if this string is found SOMEWHERE in the packet?", if yes, then fast_pattern:only; will do exactly that and save you a few processor cycles. Otherwise, if you need to ensure that the string not only exists in a packet, but at a very specific depth or offset, then you can omit that line completely. Snort will still use the longest content match in a rule as the fast-pattern match (but this can be overridden by just using fast_pattern; with no arguments on a content that you know to be the most unique string in a packet).


    Bringing all of this together:

    alert tcp any any -> any $IRC_PORTS (msg:"PRIVMSG from #foobar on IRC"; flow:established,to_server; dsize:<64; flowbits:isnotset,botnet.tagged; content:"PRIVMSG #foobar:"; flowbits:set,botnet.tagged; tag:session,1000,packets; classtype:bad-unknown; sid:2000346; rev:4;)