Bug #7199
openSuricata 7 no longer logging app-layer metadata in alerts
Description
After upgrading from Suricata 6 to 7, alerts in the eve JSON output no longer seem to include app-layer metadata.
This is what we use to have:
{ "timestamp": "2023-03-09T20:00:28.210821+0000", "flow_id": 627175734391745, "in_iface": "antrea-l7-tap0", "event_type": "alert", "vlan": [ 1 ], "src_ip": "10.10.1.5", "src_port": 43352, "dest_ip": "10.10.1.4", "dest_port": 80, "proto": "TCP", "alert": { "action": "blocked", "gid": 1, "signature_id": 1, "rev": 0, "signature": "Reject by AntreaClusterNetworkPolicy:test-l7-ingress", "category": "", "severity": 3, "tenant_id": 1 }, "http": { "hostname": "10.10.1.4", "url": "/admin", "http_user_agent": "curl/7.74.0", "http_method": "GET", "protocol": "HTTP/1.1", "length": 0 }, "app_proto": "http", "flow": { "pkts_toserver": 3, "pkts_toclient": 1, "bytes_toserver": 284, "bytes_toclient": 74, "start": "2023-03-09T20:00:28.209857+0000" } }
This is what we have now with Suricata 7.0.6:
{ "timestamp": "2024-08-26T22:19:16.005590+0000", "flow_id": 1147586615954996, "in_iface": "antrea-l7-tap0", "event_type": "alert", "vlan": [ 1 ], "src_ip": "10.10.1.9", "src_port": 54728, "dest_ip": "10.10.1.10", "dest_port": 80, "proto": "TCP", "pkt_src": "wire/pcap", "tenant_id": 1, "alert": { "action": "blocked", "gid": 1, "signature_id": 1, "rev": 0, "signature": "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2", "category": "", "severity": 3, "tenant_id": 1 }, "app_proto": "http", "direction": "to_server", "flow": { "pkts_toserver": 3, "pkts_toclient": 1, "bytes_toserver": 302, "bytes_toclient": 78, "start": "2024-08-26T22:19:16.005049+0000", "src_ip": "10.10.1.9", "dest_ip": "10.10.1.10", "src_port": 54728, "dest_port": 80 } }
The first output was captured with Suricata 6 a while back, but the rules were essentially the same. These are the rules I am using now:
reject ip any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; flow: to_server, established; sid: 1;) pass http any any -> any any (msg: "Allow http by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; http.uri; content:"/api/v2/"; startswith; http.method; content:"GET"; http.host; content:"foo.bar.com"; startswith; endswith; sid: 2;)
And this is the relevant part of the config:
%YAML 1.1
---
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: eve-%Y-%m-%d.json
rotate-interval: day
pcap-file: false
community-id: false
community-id-seed: 0
xff:
enabled: no
types:
- alert:
tagged-packets: yes
- http:
extended: yes
tagged-packets: yes
- tls:
extended: yes
It seems to me that this change, which was not backported to 6, is responsible: https://github.com/OISF/suricata/pull/10876/files, as it added an extra condition for logging app-layer data.
I am assuming that even though the action is "blocked", the expectation is that http data can still be logged here (with the default `metadata` configuration for alerts).
Updated by Antonin Bas 4 months ago
- Subject changed from Suricata 7 no longer logging app-layer metadata in alerts for blocked requests to Suricata 7 no longer logging app-layer metadata in alerts
I changed the action from "reject" to "alert" in my rule, and the behavior is the same: no app-layer (http) metadata in the alert
{ "timestamp": "2024-08-06T20:51:58.137656+0000", "flow_id": 1709562107260689, "in_iface": "antrea-l7-tap0", "event_type": "alert", "vlan": [ 1 ], "src_ip": "10.10.1.2", "src_port": 51350, "dest_ip": "10.10.1.3", "dest_port": 80, "proto": "TCP", "pkt_src": "wire/pcap", "tenant_id": 1, "alert": { "action": "allowed", "gid": 1, "signature_id": 1, "rev": 0, "signature": "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2", "category": "", "severity": 3, "tenant_id": 1 }, "app_proto": "http", "direction": "to_server", "flow": { "pkts_toserver": 3, "pkts_toclient": 1, "bytes_toserver": 291, "bytes_toclient": 78, "start": "2024-08-06T20:51:58.135894+0000", "src_ip": "10.10.1.2", "dest_ip": "10.10.1.3", "src_port": 51350, "dest_port": 80 } }
Updated by Antonin Bas 4 months ago · Edited
Sorry for the additional update.
My guess is that because there is no match on any http attribute, the alert doesn't include a tx_id and no app-layer data is logged.
If I change my rule to
alert http any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; http.method; content:"GET"; sid: 1;)
With a match on the HTTP method, the JSON alert does contain the "http" section.
(If I match on "http" only, without the "http.method" matcher, then I still don't get the app-layer data, which is puzzling to me) But these questions remain:
- Is this the intended behavior? The protocol is detected as http but there is no app-layer data.
- Should this behavioral change between Suricata 6 and 7 be documented?
Updated by Juliana Fajardini Reichow 3 months ago · Edited
Thanks for your report, we'll create a suricata-verify test to try to reproduce it, and add `engine-analysis` checks - which should help in understanding how the engine interprets these rules.
If you have any pcap that you could share, this would help with reproducing the bug, too ;)
One thing to note is that for the first rule shared:
reject ip any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; flow: to_server, established; sid: 1;)
As this is an ip
rule, here it would be expected not to see app-layer metadata with any alerts generated.
Updated by Philippe Antoine 3 months ago
For the configuration, is this IPS mode with stream.inline = true ?
Updated by Philippe Antoine 3 months ago
What about reject http any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; flow: to_server, established; dsize: >0; sid: 1;)
Updated by Antonin Bas 3 months ago
Thanks for the replies.
@Philippe Antoine Changing the rule to an http rule and adding the `dsize: >0` matcher didn't change the behavior (still no app-layer metadata in the logs). It's only when I use a matcher that actually requires parsing the HTTP request (e.g., `http.method; content:"GET"`) that the app-layer metadata is included in the logs (but then the connection hangs, with apparently no TCP RST). When said like this, it makes perfect sense of course :), but it's the change of behavior between Suricata 6 and 7 that was puzzling me, and I wasn't sure whether it was intentional. Also the HTTP data should be "available" as it is required by the other rule (the `pass` rule), which is probably why it was showing up with Suricata 6?
This is the log with the rule you suggested:
{"timestamp":"2024-08-27T17:27:04.616964+0000","flow_id":105949864071100,"in_iface":"antrea-l7-tap0","event_type":"alert","vlan":[1],"src_ip":"10.10.1.3","src_port":55718,"dest_ip":"10.10.1.2","dest_port":80,"proto":"TCP","pkt_src":"wire/pcap","tenant_id":1,"alert":{"action":"blocked","gid":1,"signature_id":1,"rev":0,"signature":"Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2","category":"","severity":3,"tenant_id":1},"app_proto":"http","direction":"to_server","flow":{"pkts_toserver":3,"pkts_toclient":1,"bytes_toserver":291,"bytes_toclient":78,"start":"2024-08-27T17:27:04.614492+0000","src_ip":"10.10.1.3","dest_ip":"10.10.1.2","src_port":55718,"dest_port":80}}
# cat /etc/suricata/rules/antrea-l7-networkpolicy-1.rules reject http any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; flow: to_server, established; dsize: >0; sid: 1;) pass http any any -> any any (msg: "Allow http by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; http.uri; content:"/api/v2/"; startswith; http.method; content:"GET"; http.host; content:"foo.bar.com"; startswith; endswith; sid: 2;)
Yes, this is IPS mode. We use the default configuration for `stream.inline`:
# suricata --dump-config | grep -i stream.inline stream.inline = auto
@Juliana Fajardini Reichow It's just an HTTP GET request generated with curl, but I am happy to provide a pcap. Should I just capture with tcpdump on the tap interface?
Updated by Philippe Antoine 3 months ago
The change you pointed is indeed the right one : https://github.com/OISF/suricata/pull/10876/files
Before that, we always logged transaction id 0 for an alert which did not have transaction keywords...
Now, we try to look the latest transaction, but only for stream alerts.
Maybe the best hack is to use a negated content (even if it is redundant with the previous rule)
reject http any any -> any any (msg: "Reject by AntreaNetworkPolicy:default/ingress-allow-http-request-to-api-v2"; flow: to_server, established; http.uri; content:!"/api/v2/"; startswith; sid: 1;)
But this rule will not fire on non-HTTP traffic
Updated by Antonin Bas 3 months ago
@Philippe Antoine We need a "catch-all" default reject rule for all the IP traffic that is not covered by the protocol-specific pass rules.
Based on your comment, it sounds like the "new" behavior is the expected one, which makes sense to me. And I guess just using protocol detection and checking for the HTTP protocol (`reject http ...` instead of `reject ip ...`) is not enough to make it a stream alert? This is the one thing that's a bit confusing to me but it's probably just lack of familiarity with Suricata.
Thanks for the follow-up and feel free to close this issue if appropriate.
Updated by Philippe Antoine 3 months ago
And I guess just using protocol detection and checking for the HTTP protocol (`reject http ...` instead of `reject ip ...`) is not enough to make it a stream alert?
Maybe we could add a new feature/keyword like try_to_log_some_tx_anyways
This keyword would try to make the rule behave as before.
The difficulty here is that this rule alerts on one packet, and one packet may have 0, 1, or multiple transactions associated to it
Updated by Philippe Antoine 3 months ago
Or "config:logging force, type tx, scope tx; "
Updated by Juliana Fajardini Reichow about 2 months ago
Finally an SV, thanks for the offer of submitting a pcap, created one myself - though a bit lazy to do a full clean-up.
Used 4 of the rules indicated here, and showed how it was, and how it is now.
Updated by Jason Ish 24 days ago
- Related to Task #7350: firewall usecase: log app-layer metadata for for catch-all drop rules added