Bug #9087
opendetect: bidirectional rule alerts on its toserver half when the toserver buffer has the higher progress
Description
A bidirectional (=>) rule can alert when only its toserver half matched. The toclient buffers are never inspected, so whatever the rule asks of the response is ignored.
Reproducer¶
One plain HTTP/1.1 exchange, GET /index.html with Host: example.com, answered by 200 OK.
alert http any any => any any (msg:"toclient condition cannot match"; flow:established; http.host; content:"example"; http.stat_msg; content:"ZZZZZZ"; sid:1;) alert http any any => any any (msg:"control"; flow:established; http.uri; content:"index"; http.stat_msg; content:"ZZZZZZ"; sid:2;)
The status message is "OK", so neither rule can match. On main (d996d85dcf) sid 1 alerts once. sid 2, which only differs in the toserver buffer, correctly does not.
Cause¶
DetectRunTxInspectRule() declares a full match when its engine loop reaches the end of the list having matched at least once (src/detect.c:1495, engine == NULL && total_matches). While it inspects the toserver direction of a SIG_FLAG_TXBOTHDIR signature it steps over the toclient engines, and the only thing holding the match back is this, at src/detect.c:1481:
if (direction == 0 && engine->next == NULL) {
// do not match yet on request only
break;
}
That only works when the engine being stepped over is the last one in the list. Engines are sorted by progress, across both directions. For sid 1, --engine-analysis gives
http_host/toserver/http2/p1 | http_stat_msg/toclient/http2/p0 | http_stat_msg/toclient/http/p1 | http_host/toserver/http/p2
The HTTP/1 http.host engine has progress 2, the http.stat_msg engine progress 1, so a toserver engine is last. The loop steps over the toclient engine with engine->next != NULL, runs the toserver engine, matches, falls off the end and reports a full match. For sid 2, http.uri has progress 1 and a toclient engine ends the list, so the guard holds.
Any => rule whose toserver buffer has a higher progress value than its toclient buffer is affected; http.request_body (progress 3) with http.stat_code behaves the same way.
Impact¶
False positives: the rule fires on the request alone, before the response exists. It also means a toclient condition in such a rule has no effect at all.
Notes¶
Found while working on #7801, whose tests for a byte variable crossing directions failed for this reason and not for the one they were written for. Two such tests are kept on a suricata-verify branch as reproducers for the fix. The same code is in main-8.0.x (not run there).
JL Updated by Jeff Lucovsky 1 day ago
- Related to Feature #7801: rules: support multi-buffer byte variables added