Suricata to Snort Translation of http.header_names.
Now, let’s translate sid:1 to Snort.
Consider sid:1, without translating the http.header_names content, we have the following template…
alert tcp $HOME_NET any → $EXTERNAL_NET $HTTP_PORTS (flow:established,to_server; content:“POST”; http_method; classtype:bad-unknown; sid:1; rev:1;)
Remember, Snort doesn’t have http.header_names, but has http_header and http_raw_header.
In the Snort docs, they provide an example as to how http_header is expected to be used:
http_header;
content:"User-Agent: abcip",fast_pattern,nocase;
content:"Accept-Language: en-us",nocase,distance 0;
Snort’s http_header/http_raw_header expects the HTTP Header name and value!
Suricata’s http.header_names does not expect any values! Only the header names.
Also, there is also no documented usage of \r\n, we will need to review Snort Hexdumps to undertand where they are.
To emphasize the above point, this rule, which wants to do an exact match on header names, will not translate 1:1.
alert tcp $HOME_NET any → $EXTERNAL_NET $HTTP_PORTS (flow:established,to_server; content:“POST”; http_method; content:“|0d 0a|Accept-Encoding|0d 0a|Content-Type|0d 0a|Referer|0d 0a|Content-Length|0d 0a|User-Agent|0d 0a|Host|0d 0a|Cookie|0d 0a|Connection|0d 0a 0d 0a|”; http_header; classtype:bad-unknown; sid:1; rev:1;)
The buffer parsed by http_header has headers and values. You can not ignore them with http_header/http_raw_header without the usage of PCRE.
Tackling Translation Quirks
The goal is to create a Snort rule that looks for these header names and skips the values. This can be done with PCRE.
Snort PCREs
Here’s a refresher on Snort PCRE usage:
http_uri;
content:"/vulnerable_endpoint.php",fast_pattern,nocase;
# pcre gets evaluated against data in the specified sticky buffer
pcre:"/[?&]interface=[\x60\x3b]/i";
What this means is that the content acts as an anchor. After Snort finds this anchor, it will then continue to apply the PCRE. We also see the use of modifiers like /i. Whenever possible we should take advantage of these. Here are modifiers relevant for our goal:
- i case insensitive
- m By default, the string is treated as one big line of characters. ^ and $ match at the beginning and ending of the string. When m is set, ^ and $ match immediately following or immediately before any newline in the buffer, as well as the very start and very end of the buffer.
- R Match relative to the end of the last pattern match. (Similar to distance:0;)
- H Match normalized HTTP request or HTTP response header (Similar to http_header). This modifier is not allowed with the unnormalized HTTP request or HTTP response header modifier(D) for the same content.
And so, we have a tiny template to consider:
content:"?" #anchor!
http_header;
pcre:"/?/Hi"
What should our drafted PCRE pattern be? It should be something like…
- Parse new header name
- Ignore header value
- \r\n
- Repeat
Let’s put that all together…
content:“Accept-Encoding”; depth:15; # Look for the content at the beginning of the line
http_header;
pcre:“/\x3a\x20[^\r\n]+\r\nContent-Type\x3a\x20[^\r\n]+\r\nReferer\x3a\x20[^\r\n]+\r\n\Content-Length\x3a\x20[^\r\n]+\r\nUser-Agent\x3a\x20[^\r\n]+\r\nHost\x3a\x20[^\r\n]+\r\nCookie\x3a\x20\r\nConnection\x3a\x20[^\r\n]+[\r\n]+$/HRi”;
OR, we could just do everything in a PCRE like…
pcre:“/^Accept-Encoding\x3a\x20[^\r\n]+\r\nContent-Type\x3a\x20[^\r\n]+\r\nReferer\x3a\x20[^\r\n]+\r\n\Content-Length\x3a\x20[^\r\n]+\r\nUser-Agent\x3a\x20[^\r\n]+\r\nHost\x3a\x20[^\r\n]+\r\nCookie\x3a\x20\r\nConnection\x3a\x20[^\r\n]+[\r\n]+$/Hi”;
Notice how we dropped the anchor and http_header.The /H modifier is used to denote
Whoa!!! Why did I add \x3a\x20?
Why does the Cookie header PCRE pattern ( Cookie\x3a\x20\r\nConnection) seem to skip the value? It looks different from the rest of the PCRE.
The WHY motivations are found in Snort Hexdumps.
** Quick Note: The Cookie header is parsed differently in Suricata and Snort. And it shows! This is worth another blog post – stay tuned.
Hidden Quirks when Snort parses HTTP Headers
Translating from Suriata to Snort is not easy. We rely on the hexdumps to help us build our rules.
For one thing, you’ll notice that Snort does not start the HTTP Header Names buffer with \r\n!
Also because Snort doesn’t parse the Header Names only, you’ll need to make sure your regex works as expected. The big takeaway here is to compare Snort and Suricata hex dumps when you need to troubleshoot your Snort rule translations. You’ll find the hiccups eventually!
Here’s how Snort parsed the sample as a hex dump
00000000 41 63 63 65 70 74 2D 45 6E 63 6F 64 69 6E 67 3A |Accept-Encoding:|
00000010 20 69 64 65 6E 74 69 74 79 0D 0A 43 6F 6E 74 65 | identity..Conte|
00000020 6E 74 2D 54 79 70 65 3A 20 61 70 70 6C 69 63 61 |nt-Type: applica|
00000030 74 69 6F 6E 2F 78 2D 77 77 77 2D 66 6F 72 6D 2D |tion/x-www-form-|
00000040 75 72 6C 65 6E 63 6F 64 65 64 0D 0A 52 65 66 65 |urlencoded..Refe|
00000050 72 65 72 3A 20 68 74 74 70 73 3A 2F 2F 6E 65 74 |rer: https://net|
00000060 66 6C 69 78 61 63 63 2D 6C 6F 67 6F 6E 2E 61 6E |flixacc-logon.an|
00000070 6F 6E 64 6E 73 2E 6E 65 74 2F 48 6F 6D 65 2F 0D |ondns.net/Home/.|
00000080 0A 43 6F 6E 74 65 6E 74 2D 4C 65 6E 67 74 68 3A |.Content-Length:|
00000090 20 32 33 0D 0A 55 73 65 72 2D 41 67 65 6E 74 3A | 23..User-Agent:|
000000a0 20 4D 6F 7A 69 6C 6C 61 2F 35 2E 30 20 28 57 69 | Mozilla/5.0 (Wi|
000000b0 6E 64 6F 77 73 20 4E 54 20 31 30 2E 30 3B 20 57 |ndows NT 10.0; W|
000000c0 69 6E 36 34 3B 20 78 36 34 3B 20 72 76 3A 38 32 |in64; x64; rv:82|
000000d0 2E 30 29 20 47 65 63 6B 6F 2F 32 30 31 30 30 31 |.0) Gecko/201001|
000000e0 30 31 20 46 69 72 65 66 6F 78 2F 38 32 2E 30 0D |01 Firefox/82.0.|
000000f0 0A 48 6F 73 74 3A 20 6E 65 74 66 6C 69 78 61 63 |.Host: netflixac|
00000100 63 2D 6C 6F 67 6F 6E 2E 61 6E 6F 6E 64 6E 73 2E |c-logon.anondns.|
00000110 6E 65 74 0D 0A 43 6F 6F 6B 69 65 3A 20 0D 0A 43 |net..Cookie: ..C|
00000120 6F 6E 6E 65 63 74 69 6F 6E 3A 20 63 6C 6F 73 65 |onnection: close|
00000130 0D 0A 0D 0A
And here’s the ASSUMED Suricata hexdump from the sample.
00000040 41 63 63 65 70 74 2d 45 6e A ccept-En
00000050 63 6f 64 69 6e 67 3a 20 69 64 65 6e 74 69 74 79 coding: identity
00000060 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 ..Conten t-Type:
00000070 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 2d 77 77 applicat ion/x-ww
00000080 77 2d 66 6f 72 6d 2d 75 72 6c 65 6e 63 6f 64 65 w-form-u rlencode
00000090 64 0d 0a 52 65 66 65 72 65 72 3a 20 68 74 74 70 d..Refer er: http
000000A0 73 3a 2f 2f 6e 65 74 66 6c 69 78 61 63 63 2d 6c s://netf lixacc-l
000000B0 6f 67 6f 6e 2e 61 6e 6f 6e 64 6e 73 2e 6e 65 74 ogon.ano ndns.net
000000C0 2f 48 6f 6d 65 2f 0d 0a 43 6f 6e 74 65 6e 74 2d /Home/.. Content-
000000D0 4c 65 6e 67 74 68 3a 20 32 33 0d 0a 55 73 65 72 Length: 23..User
000000E0 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f -Agent: Mozilla/
000000F0 35 2e 30 20 28 57 69 6e 64 6f 77 73 20 4e 54 20 5.0 (Win dows NT
00000100 31 30 2e 30 3b 20 57 69 6e 36 34 3b 20 78 36 34 10.0; Wi n64; x64
00000110 3b 20 72 76 3a 38 32 2e 30 29 20 47 65 63 6b 6f ; rv:82. 0) Gecko
00000120 2f 32 30 31 30 30 31 30 31 20 46 69 72 65 66 6f /2010010 1 Firefo
00000130 78 2f 38 32 2e 30 0d 0a 48 6f 73 74 3a 20 6e 65 x/82.0.. Host: ne
00000140 74 66 6c 69 78 61 63 63 2d 6c 6f 67 6f 6e 2e 61 tflixacc -logon.a
00000150 6e 6f 6e 64 6e 73 2e 6e 65 74 0d 0a 43 6f 6f 6b nondns.n et..Cook
00000160 69 65 3a 20 50 48 50 53 45 53 53 49 44 3d 39 37 ie: PHPS ESSID=97
00000170 32 63 64 38 66 66 62 63 63 39 61 63 62 39 62 63 2cd8ffbc c9acb9bc
00000180 36 37 32 36 30 38 33 63 61 36 33 37 33 34 0d 0a 6726083c a63734..
00000190 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 Connecti on: clos
000001A0 65 0d 0a 0d 0a e....
Snort Rule
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Rule with anchor content flow:established,to_server; content:"Accept-Encoding"; http_header; pcre:"/\x3a\x20[^\r\n]+\r\nContent-Type\x3a\x20[^\r\n]+\r\nReferer\x3a\x20[^\r\n]+\r\n\Content-Length\x3a\x20[^\r\n]+\r\nUser-Agent\x3a\x20[^\r\n]+\r\nHost\x3a\x20[^\r\n]+\r\nCookie\x3a\x20\r\nConnection\x3a\x20[^\r\n]+[\r\n]+$$/Hi"; classtype:bad-unknown; sid:3; rev:1;)
or
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Rule with PCRE only"; flow:established,to_server; pcre:“/^Accept-Encoding\x3a\x20[^\r\n]+\r\nContent-Type\x3a\x20[^\r\n]+\r\nReferer\x3a\x20[^\r\n]+\r\n\Content-Length\x3a\x20[^\r\n]+\r\nUser-Agent\x3a\x20[^\r\n]+\r\nHost\x3a\x20[^\r\n]+\r\nCookie\x3a\x20\r\nConnection\x3a\x20[^\r\n]+[\r\n]+$/Hi”; classtype:bad-unknown; sid:4; rev:1;)