Project

General

Profile

Actions

Feature #8393

open
YD

Task #8388: firewall: support protocol hooks for all app-layer protocols

firewall: support SMTP hook states for firewall rule evaluation

Feature #8393: firewall: support SMTP hook states for firewall rule evaluation

Added by Yash Datre 26 days ago. Updated 20 days ago.

Status:
New
Priority:
High
Assignee:
-
Target version:
Effort:
Difficulty:
Label:

Description

SMTP is a widely deployed protocol that network firewalls commonly need to inspect and control. In Suricata 8.0.4, SMTP app-layer hook states are not registered for firewall mode. Attempting to use any smtp:* hook in a firewall rule fails with the error: "protocol smtp does not support hook" .

Without SMTP hooks, SMTP traffic on port 25/587 cannot be inspected at the application layer in firewall mode. Packet-layer rules can accept the TCP handshake, but once the SMTP app-layer parser engages, the flow is dropped by default_app_policy because no hooks exist for the firewall engine to evaluate.

This prevents common firewall use cases such as:
  • Allowing or blocking SMTP based on sender/recipient commands
  • Inspecting MAIL FROM / RCPT TO for policy enforcement
  • Controlling DATA transfer based on content inspection
  • Enforcing STARTTLS requirements
Potential SMTP states:
  • Connected
  • HELO/EHLO sent
  • Server greeting received
  • MAIL FROM sent
  • RCPT TO sent
  • DATA command sent
  • Message body transfer
  • Message accepted
  • QUIT sent
  • Connection closed
  • STARTTLS initiated
  • Authentication in progress

These states should be mapped to firewall hook points that allow rules to make accept/drop decisions at meaningful protocol transitions — for example, after EHLO, after MAIL FROM/RCPT TO, during DATA transfer, after STARTTLS negotiation, etc.

VJ Updated by Victor Julien 25 days ago Actions #1

  • Tracker changed from Bug to Feature
  • Subject changed from Firewall mode: Register SMTP hook states for firewall rule evaluation to firewall: support SMTP hook states for firewall rule evaluation
  • Priority changed from Normal to High
  • Target version changed from TBD to 9.0.0-beta1
  • Affected Versions deleted (8.0.4)

VJ Updated by Victor Julien 25 days ago Actions #2

  • Parent task set to #8388

VJ Updated by Victor Julien 21 days ago Actions #3

Could you provide a mock up of what a real world SMTP ruleset could look like? This is the first protocol that is a bit less structured in terms of order of commands than the other protocols supported, so it would be helpful to look at some examples.

VJ Updated by Victor Julien 20 days ago Actions #4

I'm thinking most or even all steps can be done by maintaining a relatively simple state machine, where we'd track all command-reponse pairs as transactions. These would be covered by the normal request_started and request_complete states.

Per transaction there would be mode variable to indicate where it fits in the connection state (thinking command, data, closed).

The rules would then have the ability to match on the mode, the command, command data, response code, response string.

A mock up of what a ruleset could look like:

accept:hook smtp:request_started any any -> any 25 (smtp.mode:command;)
accept:hook smtp:request_complete any any -> any 25 (smtp.command; content:"MAIL FROM"; smtp.command_data; dataset:isset,mail-from-allow-list,type string,load mfal.csv;)
reject:flow smtp:request_complete any any -> any 25 (smtp.command; content:"MAIL FROM"; smtp.command_data; content:"ceo@example.com";)
accept:hook smtp:request_complete any any -> any 25 (smtp.command; content:"MAIL FROM"; smtp.command_data; content:"example.com";)
accept:hook smtp:request_complete any any -> any 25 (smtp.command; content:"RCPT TO"; smtp.command_data; content:"example.com";)
accept:hook smtp:request_complete any any -> any 25 (smtp.command; pcre:/^(HELO|EHLO)$/; smtp.command_data; content:"mydomain.lan";)

# DATA command with options
drop:flow smtp:request_complete any any -> any 25 (smtp.command; content:"DATA"; smtp.command_data; bsize:>0;)
# accept DATA command
accept:hook smtp:request_complete any any -> any 25 (smtp.command; content:"DATA";)

accept:hook smtp:response_started any 25 -> any any ()
accept:hook smtp:response_complete any 25 -> any any (smtp.command; content:"MAIL_FROM"; smtp.response_code; content:"250";)
accept:hook smtp:response_complete any 25 -> any any (smtp.command; smtp.response_code; content:"220";)

drop:flow smtp:request_started .. (smtp.mode:data; smtp.data; content:"Buy my crypto";)
accept:hook smtp:request_started .. (smtp.mode:data;)
accept:hook smtp:request_complete .. (smtp.mode:data;)

accept:hook smtp:response_complete .. (smtp.mode:data; smtp.response_code:"250";)

The _started hooks are used to match on a partial command/response line. E.g. when a command like MAIL FROM would be sent in multiple packets.

For this to work the transaction handling would have to be redesigned and several keywords will have to be created. I would imagine that we'd store the helo/ehlo, mail from, rcpt to in the global state to add it to the data mode as well, so keywords can use it there too.

JI Updated by Jason Ish 20 days ago Actions #5

Victor Julien wrote in #note-4:

I'm thinking most or even all steps can be done by maintaining a relatively simple state machine, where we'd track all command-reponse pairs as transactions.

Do you see these transactions rippling into the logging as well? While it might make sense from a firewall state perspective, when it comes to logging, I think it makes more sense for a transaction to contain all the info from HELO to BYE/RSET?

VJ Updated by Victor Julien 20 days ago Actions #6

Jason Ish wrote in #note-5:

Victor Julien wrote in #note-4:

I'm thinking most or even all steps can be done by maintaining a relatively simple state machine, where we'd track all command-reponse pairs as transactions.

Do you see these transactions rippling into the logging as well? While it might make sense from a firewall state perspective, when it comes to logging, I think it makes more sense for a transaction to contain all the info from HELO to BYE/RSET?

I guess it kind of creates 2 classes of transactions. One is essentially the existing tx with the current logging, although the existing logic can also create a tx for something like a single QUIT command. The 2nd is a bit lower level, a per command tx, so I would imagine we'd disable it by default for logging.

I suppose the whole setup is a bit like the smb/nfs concept of transactions, where there are special "file tx" for tracking files.

Actions

Also available in: PDF Atom