<div dir="ltr"><span style="font-family:courier new,monospace">Hello,<br><br>I'm experiencing an issue when http_inspect preprocessor handles an HTTP packet with two identical Content-Length headers present. <br>When two identical headers (with the same value) are present, the rule trying to match a string inside http_client_body fails. The only header that triggers this condition is Content-Length.<br>
<br>This could be a mechanism to evade HTTP signatures based on http_inspect preprocessor.<br><br>OS: Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux<br>Snort Package: snort (2.9.2.2-3)<br>Preprocessors enabled: stream5, http_inspect<br>
(Find below a snort.conf can be used for testing purposes)<br><br>Steps to reproduce the bug (python+scapy):<br><br>1. Install Scapy (<a href="http://www.secdev.org/projects/scapy/">http://www.secdev.org/projects/scapy/</a>)<br>
2. Install Snort version 2.9.2 (I'm using the apt-get from Debian repositories)<br>3. Install the supplied snort.conf enabling http_inspect and stream5 preprocessors<br>4. Start Scapy and try the examples below.<br><br>
Best regards,<br><br>Pablo<br><br><br>--- Example 1: HTTP POST packet with double Content-Length ---<br><br>DST_SERVER = 'xxx.xxx.xxx.xxx' # Complete!<br><br>httpheaderN =  'POST / HTTP/1.1\r\nHost: '+ DST_SERVER +'\r\nUser-Agent: Wget/1.13.4 (linux-gnu)\r\nContent-Length: 86\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 86\r\n\r\n'<br>
<br>httpbodyN = "Nobody can go back and start a new beginning, but anyone can start today a new ending."<br>    <br><br>pDouble = IP(dst=DST_SERVER) / TCP(dport=80)  / (httpheaderN+httpbodyN)<br><br>send(pDouble) # should trigger both rules! Fails to match http_client_body rule<br>
<br>--- End Example 1 ---<br><br>--- Example 2 ---<br>DST_SERVER = 'xxx.xxx.xxx.xxx' # Complete!<br><br>httpheaderD =  'POST / HTTP/1.1\r\nHost: '+ DST_SERVER +'\r\nUser-Agent: Wget/1.13.4 (linux-gnu)\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 86\r\n\r\n'<br>
<br>httpbodyD = "Nobody can go back and start a new beginning, but anyone can start today a new ending."<br><br>pNormal = IP(dst= DST_SERVER) / TCP(dport=80)  / (httpheaderD+httpbodyD)<br><br>send(pNormal) # Should trigger both rules! OK<br>
<br>--- End Example 2 ---<br><br><br>--- used snort.conf ---<br>output unified2: filename snort_unified2.out, limit 128<br>output alert_fast<br><br>preprocessor stream5_global: \<br>  track_tcp yes \<br>  track_udp yes<br>
preprocessor stream5_tcp: \<br>  policy bsd, \<br>  timeout 86400, \<br>  ports all<br>preprocessor stream5_udp: \<br>  timeout 86400<br><br>preprocessor http_inspect: \<br>  global \<br>  iis_unicode_map unicode.map 1252<br>
<br>preprocessor http_inspect_server: \<br>  server default \<br>  profile all \<br>  client_flow_depth 0 \<br>  server_flow_depth 0 \<br>  post_depth 0 \ <br>  extended_response_inspection \<br>  ports { 80 } http_methods { GET POST PUT SEARCH MKCOL COPY MOVE LOCK UNLOCK NOTIFY POLL BCOPY BDELETE BMOVE LINK UNLINK OPTIONS HEAD DELETE TRACE TRACK CONNECT SOURCE SUBSCRIBE UNSUBSCRIBE PROPFIND PROPPATCH BPROPFIND BPROPPATCH RPC_CONNECT PROXY_SUCCESS BITS_POST CCM_POST SMS_POST RPC_IN_DATA RPC_OUT_DATA RPC_ECHO_DATA }<br>
<br><br>var DST_SERVER xxx.xxx.xxx.xxx # Complete!! and erase this comment!<br><br>alert tcp any any -> $DST_SERVER 80 (  flow: to_server; content: "Nobody"; nocase; \<br>http_client_body;  content: "Beginning"; nocase; http_client_body;  msg: "Rule with http_client_body ";  \<br>
sid: 2;)<br><br>alert tcp any any -> $DST_SERVER 80 (  flow: to_server; content: "Nobody"; nocase; \  <br>content: "Beginning"; nocase; msg: "Rule without http_client_body ";  sid: 1)<br><br>
</span></div>