Bug #6886
openHTTP Chunk Length Value disappearing
Description
Hey folks!
I'd like to report what I think is an issue with Currently supported (and developing) versions of suricata - 6.x, 7.x and 8.x.
Recently, I was working on providing coverage for cve-2024-21762. To summarize, its an issue with Fortinet FortiOS products and their handling of chunked HTTP requests.
Bishop Fox developed a python script that can be used to test whether fortinet products are vulnerable to exploitation of this CVE. The original code is here: https://github.com/BishopFox/cve-2024-21762-check
I made some slight changes to the code in order for it to throw the vulnerability check over plain HTTP. I've taken the liberty of attaching my modified script to this request.
So I ran the exploit checker against python http.server listening on port 80 in order to just get the pcaps I needed. I wrote a relatively simple rule designed to capture vulnerability checks using this vulnerability scanning tool:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; http.request_body; content:0000000000000000FF|0d 0a 0d 0a|"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:1; rev:1;)
I tested this rule again using Dalton, and the rule didn't fire. In an effort to troubleshoot it, I used dalton's ability to dump the HTTP buffers and noticed that the http client request buffer just contains |0d 0a|. That the chunk size isn't included in the buffer. I've attached a screenshot to better illustrate what I'm experiencing.
However, with a slight edit to the original rule, looking for the chunk size value WITHOUT the http.request_body buffer:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; content:|0d 0a 0d 0a|0000000000000000FF|0d 0a 0d 0a|"; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:1; rev:1;)
...triggers alerts just fine.
For the sake of testing, I ran dalton with the full series of http-events.rules, plus the following set of rules:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; http.request_body; content:"0000000000000000FF"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:1; rev:1;) alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; http.request_body; content:"0000000000000000FF|0d 0a|"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:2; rev:1;) alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; http.request_body; content:"0000000000000000FF|0d 0a 0d 0a|"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:3; rev:1;) alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET WEB_SPECIFIC_APPS Bishop Fox Fortigate CVE-2024-21762 Vulnerability Scanner Attempt"; flow:established,to_server; content:"|0d 0a 0d 0a|0000000000000000FF|0d 0a 0d 0a|"; http.method; content:"POST"; http.uri; content:"/remote/VULNCHECK"; fast_pattern; http.header; content:"Transfer-Encoding|3a 20|chunked"; reference:url,github.com/BishopFox/cve-2024-21762-check; classtype:trojan-activity; sid:4; rev:1;)
The only rule that would fire (aside from an http-events.rule for an invalid host header) was sid number 4. I've tested this on the latest suri 8, 7, and 6 builds, and have attached the dalton job zip files (includes pcap, rules, and suricata.yaml) to this ticket.
Here is what I want to know: Is this expected behavior? Should I assume that the http.request_body buffer is normalizing out the chunk length value in the request body? The reason I enabled the http-events.rules was to see if there were any triggers for anomalous http chunk/chunk length values in the packet capture I generated, but nothing related to http chunk anomalies triggered.
So, is suricata normalizing out the chunk length and not logging any details relating to that? If this is expected behavior, at a minimum I would like to see this documented in all currently supported releases of Suricata -- more specifically, the documentation relating to http.request_body and http.response_body should have notes about this somewhere.
In an ideal world, I'd like to be able to alert on this unusual traffic without resorting to the work-around of creating an unbuffered content match, because according to our conversations, unbuffered content matches are very inefficient. I don't know if that means re-evaluating how Suricata analyzes chunk data, and/or chunk length values, or adding in a new keyword in a future release to be able to analyze raw, chunked data in the http.request_body http.response_body and/or file.data buffer (maybe a modifier like dotprefix --- e.g. --- http.request_body; raw_chunks; content:"0000000000000000FF|0d 0a 0d 0a|";
Thank again for all you do to make Suricata better with every release. Please let me know if there are additional details I can provide.
Files
Updated by Victor Julien 6 months ago
- Status changed from New to Assigned
- Assignee changed from OISF Dev to Philippe Antoine
Updated by Philippe Antoine 6 months ago
Hi Tony, taking a quick Look : yes Suricata is meant to dechunk the entity body (as Wireshark does on first tcp stream), as it does gzip decompression for instance...
The reason I enabled the http-events.rules was to see if there were any triggers for anomalous http chunk/chunk length values in the packet capture I generated, but nothing related to http chunk anomalies triggered.
Did you expect something because of the leading zeroes ?
Otherwise, this looks like the request is not complete and Wireshark and Suricata expect the next 255 byte chunk, where we get only 2 bytes 0d 0a.
Am I misunderstanding something ?
unbuffered content matches are very inefficient
Even with the use of buffered content, including the fast_pattern ?
I guess the good way to do it in the future will be to use frames when they are available for http1
Updated by Philippe Antoine about 1 month ago
ping @Tony Robinson ?
I will close this issue, as Suricata behaves as expected if I understand correctly.
Updated by Philippe Antoine about 1 month ago
- Related to Feature #7177: http1: add frame support added