Bug #6874
closedlibhtp appears to stop parsing HTTP client requests mid-pcap - /libhtp::request_uri_not_seen
Description
Hello!
My name is Tony, and I work with the Proofpoint Emerging Threats Team. I'd like to report a problem that I've across in Suricata 8.0.0-dev (3/13 build), 7.0.3, and 6.0.0.16. All builds are on x86-64, utilizing the test platform, Dalton (https://github.com/secureworks/dalton).
We got a report from a user for some new rules to cover "AsukaStealer". If you're interested, take a look at the forum post here:
https://community.emergingthreats.net/t/asukastealer-observerstealer-gen/1470
The bottom line is that towards the end of the post, the submitter claims that they had to do content matches that do not utilize the http buffers in order to get their rules to trigger. Here is a link to the any.run sandbox run (and the pcap): https://app.any.run/tasks/8b1ee45a-87de-4fc5-a755-84546a974a44
For those who don't have (or don't want) an any.run account, I've taken the liberty of attaching the pcap (in a dalton job zip file) associated with this issue.
So, to test the submitter's assertions that HTTP buffers weren't working, I took one of the rules they submitted to us, and transformed it a bit:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET MALWARE [ANY.RUN] AsukaStealer SQLite Browser Data Exfiltration Attempt"; flow:established,to_server; http.method; content:"POST"; http.content_type; content:"multipart|2f|form-data|3b 20|boundary|3d|"; http.header; content:"X-Config|3a 20|"; fast_pattern; pcre:"/^(?:Google\x5f|Edge\x5f|Steam\x5f|Firefox\x5fF)/R"; content:"COK|0d 0a|"; within:20; http.header_names; content:"|0d 0a|X-Session|0d 0a|"; content:"|0d 0a|X-Info|0d 0a|"; content:"|0d 0a|X-Config|0d 0a|"; reference:md5,ae5537f1a506140ee101ffdf4605fdcc; reference:url,app.any.run/tasks/7a36fb55-3738-4f40-b760-b443689c9edd; reference:url,community.emergingthreats.net/t/asukastealer-observerstealer-gen; classtype:trojan-activity; sid:1; rev:1;)
For reference, here was the original rule (minus a very slight error that would cause it to not trigger):
alert http any any -> any any (msg:"ET MALWARE [ANY.RUN] AsukaStealer Exfiltrates SQLite Browsers Data"; flow:established,to_server; content:"POST"; startswith; content:"Content-Type|3a 20|multipart|2f|form-data|3b 20|boundary="; distance:0; content:"X-Session|3a| "; within:350; content:"X-Info|3a|"; within:45; content:"X-Config|3a| "; within:350; pcre:"/^(Google_COK|Firefox_COK|Edge_COK)\r/R"; content:"X-ID|3a| "; within:22; threshold:type limit, seconds 120, count 1, track by_src; classtype:credential-theft; reference:md5,ae5537f1a506140ee101ffdf4605fdcc; reference:url,app.any.run/tasks/7a36fb55-3738-4f40-b760-b443689c9edd; reference:url,community.emergingthreats.net/t/asukastealer-observerstealer-gen; metadata:malware_family asukastealer, created_at 2024_03_19; sid:1; rev:1;)
The rule I wrote will not trigger on the sandbox pcap. However, there are several existing ET rules that will trigger on that pcap that make use of HTTP buffers. I've noticed that after the HTTP client POST that sends a large PNG file, libhtp starts throwing errors. Here is the output from the Dalton job's HTTP log:
02/09/2024-05:46:12.189215 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:12.989933 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:13.756718 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:14.867041 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:15.067488 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:15.753600 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:16.471367 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:17.826489 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:18.248283 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:20.315563 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:24.411779 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:26.703613 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:26.928567 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:27.087962 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:27.306797 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:27.508658 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:27.678091 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:27.835970 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:28.044538 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:28.235679 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:28.395542 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:28.642545 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:28.904393 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:29.063432 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:29.264992 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:29.467883 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:46:29.725990 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
02/09/2024-05:45:52.397646 <hostname unknown>[**]/libhtp::request_uri_not_seen[**]<useragent unknown>[**]192.168.100.185:49208 -> 5.42.66.25:3000
I'm not sure why this is happening. The submitted rule does trigger, but it only appears to trigger on the packet thread. I've attached a screenshot the submitter supplied to show how/why they had to use content matches without sticky buffers to get the rule to work. Just as a sanity check I used flowsynth to create a packet capture that would trigger both of the rules above, and I've attached that. I can confirm that both rules will fire on that pcap.
I thought that maybe I was hitting an http client inspection depth configuration problem. The default for Dalton is 100kb for both client and server inspection depth. I upped this to 100mb just to rule it out, and have attached the job zip file for that as well. The rule I created still refuses to trigger. Near as I can tell the HTTP requests in the sandbox pcap are well-formed, there are no irregularities that I have noticed in the pcap, and copying one of the malicious POST requests and using it to create a new packet capture with flowsynth worked just fine. At this point, I'm at a loss.
If there is any other information I can supply to help in finding the root of this problem and/or correcting it, please let me know.
Files