Content filtering does not seem to work without other payload keywords

Hi everyone, I just started learning Suricata and the first problem I’m trying to solve is looking for certain certificate exchange patterns in TLS communication. The heximal sequence I am interested in searching for is ‘16 03 03’. However, my custom rules do not raise an alert unless I combine the content keyword with others, such as offset, or depth. Many examples I have come across do use content keyword to search for the desired pattern in entire payload. I know it’s not the most performant approach, but I am having a hard time understanding why it won’t work just like that.

A snapshot of the packet capture I am working against:

What works:

alert tcp 172.31.83.104/32 any -> any 443 (msg:"Tracking certificate exchange flows"; flow:established,to_server; content:"|16 03 03|"; offset:0; sid:2;)

What does not work:

alert tcp 172.31.83.104/32 any -> any 443 (msg:"Tracking certificate exchange flows"; flow:established,to_server; content:"|16 03 03|"; sid:2;)

The command I’m using to test this on a local setup with a pre-recorded pcap file:

suricata -vvvv -r /home/ubuntu/tls1.2/tls1.2-with-mtls-without-clientcert.pcapng --runmode autofp -l /var/log/suricata/ -c /etc/suricata/suricata.yaml -k none

Edit:

Adding to the confusion, I see another packet has been picked up for alerting (in another pcap) which doesn’t seem to have the “|16 03 03|” pattern at all. And this alert was raised with just the content keyword being used.

Command used:

suricata -vvvv -r /home/ubuntu/tls1.2/tls1.2-with-mtls-with-clientcert.pcapng --runmode autofp -l /var/log/suricata/ -c /etc/suricata/suricata.yaml -k none

Rule:

alert tls 172.31.83.104/32 any -> any 443 (msg:"Tracking certificate exchange flows"; flow:established,to_server; content:"|16 03 03|"; sid:2;)

Building on this knowledge, eventually, I want to track mTLS workflows where client certificates are not sent. I have some doubts if this might be possible with TLSv1.3, as a lot of exchange seems to be encrypted. Is there any functionality within Suricata that I could leverage to look into the packets for this pattern? Many thanks!

Could you please share the Suricata version you’re using and if possible the pcaps you’re using to test?

@sbhardwaj sure, Suricata version is 7.0.4 RELEASE

Also attached the two pcaps below:

tls1.2-with-mtls-without-clientcert.pcapng (20.7 KB)
tls1.2-with-mtls-with-clientcert.pcapng (22.3 KB)

TCP packets are inspected when acked unless stream.inline is set in the configuration