While recently working on a malware sample which had some HTTP2 traffic in it. I was surprised that Suricata did not log or alert on any of the traffic for HTTP2, despite having written a rule for the traffic. Turns out, the default configuration included with Suricata 6 have the HTTP/2 parsing disabled.
When it comes to rule writing, the concept of “Overloading” is important and is detailed below.
Configuration Items
When working with HTTP/2 traffic, I would suggest using with at least Suricata version 6.0.4. This version supports all of the required configuration options to enable HTTP/2 logging and alerting.
There are there major settings that need changed.
- App-Layer
app-layer.protocols.http2.enabled
- Logging
outputs.eve-log.types.http2
- Overloading
app-layer.protocols.http2.http1-rules
These settings will get you well on your way to using HTTP/2 on Suricata 6. It should be noted that these settings are slated to be enabled by default with Suricata 7.0 and are already enabled within Suricata 7.0 Beta1
History of HTTP/2 in Suricata
Overall HTTP/2 support within Suricata can be tracked via issue 4201. HTTP/2 support was first added via a commit to Suricata on Aug 7th 2020. In that commit, we can see that the HTTP/2 logging and the protocol parser was marked as “Experimental” and disabled by default:
This initial support for HTTP/2 was eventually included in Suricata 6.0.0 when released on Oct 8 2020.
Overloading
From a rule writer’s perspective, the next major HTTP/2 feature was the ability to “overload” Suricata’s already existing HTTP/1 keywords and buffers with content from HTTP/2 traffic. This allows rules written for HTTP/1 to work on HTTP/2 traffic.
As an example, in HTTP/1 there is a “Host” header which “MUST” be included in every request and represents the “Internet host and port number of the resource being requested”. Suricata, when parsing HTTP/1 traffic will populate this header into the http.host
keyword.
However, in HTTP/2 there is no “Host” header, instead it uses the :authority:
pseudo-header field to convey the same information.
Now suppose a rule was required which alerted on an HTTP traffic to a specific host, without overloading, two rules would be required.
alert http $HOME_NET any -> any any (msg:"HTTP Outbound - Request to example.com"; flow:established,to_server; http.host; content:"example.com";)
alert http2 $HOME_NET any -> any any (msg:"HTTP Outbound - Request to example.com"; flow:established,to_server; http2.header; content:":authority: example.com";)
With overloading enabled via the http1-rules
configuration item Suricata will use HTTP/1 keywords on HTTP/2 traffic. This config item was introduced via a merge on Sep 6th 2021 which was released as 6.0.4.
With overloading enabled via the http1-rules
option in the [suricata configuration]both HTTP1 and HTTP2 traffic can be covered by a single rule.
alert http $HOME_NET any -> any any (msg:"HTTP Outbound - Request to example.com"; flow:established,to_server; http.host; content:"example.com";)
It’s important to note that not all HTTP/1 keywords currently support being overloaded. The expansion of HTTP/1 keywords which can be overloaded with HTTP/2 data continues today and can be tracked via Redmine Issue #4067.