<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2658.2">
<TITLE>Snort DoS Fallacies</TITLE>
</HEAD>
<BODY>

<P><FONT FACE="Times New Roman">Hello,<BR>
<BR>
The recent advisory from the Snort team in regards to the DoS in the PrintTCPOptions() function of log.c is incorrect in a couple regards.</FONT></P>
<BR>

<P><FONT FACE="Times New Roman">Firstly, and most importantly- You _do not_ have to be running snort with -v, there are several execution path's in snort that leads to the function PrintTCPOptions(), excerpts from relevant code are below:<BR>
<BR>
First, let's us realize how the code gets to PrintTCPOptions().<BR>
</FONT>
<BR><FONT FACE="Times New Roman">PrintTCPOptions() is called by PrintTCPHeader(), which in turn is called by PrintIPPKT(), see below for relevant code snippets-- The line numbers are from the current CVS version of snort pulled down aprox. 1 hour ago.<BR>
<BR>
<BR>
snort/src/log.c<BR>
315 PrintIPPkt()<BR>
[...]<BR>
337 if(!p->frag_flag)<BR>
338 {<BR>
339 switch(p->iph->ip_proto)<BR>
340 {<BR>
341 case IPPROTO_TCP:<BR>
342 if(p->tcph != NULL)<BR>
343 {<BR>
344 PrintTCPHeader(fp, p);<BR>
345 }<BR>
<BR>
snort/src/log.c<BR>
934 PrintTCPHeader()<BR>
[...]<BR>
962 /* dump the TCP options */<BR>
963 if(p->tcp_option_count != 0)<BR>
964 {<BR>
965 PrintTcpOptions(fp, p);<BR>
966 }<BR>
<BR>
So we see here that, if someone is to call PrintIPPacket(), and the packet is not a fragment, and its protocol is TCP then we call TCPHeader() and once inside of PrintTCPHeader(), if the option_count is not 0, then we call PrintTCPOptions.<BR>
<BR>
Now a quick grep(1) of the source tree reveals several possible ways to end up at PrintIPPkt(), relevant source below:<BR>
<BR>
First, if we are using the option -A fast:<BR>
<BR>
snort/src/output-plugins/spo_alert_fast.c<BR>
134 AlertFast()<BR>
[...]<BR>
146 if(msg != NULL)<BR>
147 {<BR>
[...]<BR>
208 if(p && data->packet_flag)<BR>
209 {<BR>
210 fputc('\n', data->file);<BR>
211<BR>
212 if(p->iph)<BR>
213 PrintIPPkt(data->file, p->iph->ip_proto, p);<BR>
<BR>
<BR>
Second, if we are logging in ASCII mode (a lot of people):<BR>
<BR>
snort/src/output-plugins/spo_log_ascii.c<BR>
112 LogAscii()<BR>
[...]<BR>
137 if(p)<BR>
138 {<BR>
139 if(p->iph)<BR>
140 PrintIPPkt(log_ptr, p->iph->ip_proto, p);<BR>
<BR>
<BR>
Also, in the frag3 preprocessor, also I'm not sure what the point of defining DEBUG_FRAG3 at compile time would be (at least in this code segment), as the execution flow is exactly the same:<BR>
<BR>
snort/src/preprocessors/spp_frag3.c<BR>
2929 Frag3Rebuild()<BR>
[...]<BR>
3117 #ifdef DEBUG_FRAG3<BR>
[...]<BR>
3122 if (DEBUG_FRAG & GetDebugLevel())<BR>
3123 {<BR>
[...]<BR>
3126 PrintIPPkt(stdout, defrag_pkt->iph->ip_proto, defrag_pkt);<BR>
[...]<BR>
3129 }<BR>
3130 #endif<BR>
[...]<BR>
3133 PrintIPPkt(stdout, defrag_pkt->iph->ip_proto, defrag_pkt);<BR>
<BR>
It can also be called in the stream4 preprocessor, if a few debugging conditions are met:<BR>
<BR>
snort/src/preprocessors/stream4.c<BR>
4682 BuildPacket()<BR>
[...]<BR>
4841 #ifdef DEBUG<BR>
[...]<BR>
4852 if (DEBUG_STREAM & GetDebugLevel())<BR>
4853 {<BR>
[...]<BR>
4856 PrintIPPkt(stdout, IPPROTO_TCP, stream_pkt);<BR>
[...]<BR>
4863 }<BR>
4864 #endif<BR>
<BR>
<BR>
And finally, as the snort authors suggested, if you are using -v:<BR>
<BR>
snort/src/snort.c<BR>
766 /* print the packet to the screen */<BR>
767 if(pv.verbose_flag)<BR>
768 {<BR>
769 if(p.iph != NULL)<BR>
770 PrintIPPkt(stdout, p.iph->ip_proto, &p);<BR>
<BR>
<BR>
Additionally, as the second part of the misrepresentation of data, there is several bugs in PrintTCPOptions(), which is apparent by the changes they made-- these include nearly all of the TCP options, not just SACK. These include the following options:<BR>
<BR>
TCPOPT_MAXSEG, TCPOPT_WSCALE, TCPOPT_ECHO, TCPOPT_ECHOREPLY,<BR>
TCPOPT_TIMESTAMP, TCPOPT_CC, TCPOPT_CCNEW, TCPOPT_CCECHO, and _any_ unrecognized or invalid option.<BR>
<BR>
However, the snort team did say one thing correctly, and that these all are NULL pointer dereferences, and therefore only a DoS and not exploitable to run arbitrary code.</FONT></P>
<BR>

<P><FONT FACE="Times New Roman">Best Regards,<BR>
<BR>
</FONT><FONT SIZE=2 FACE="Arial">J. Ferguson</FONT>
<BR><FONT SIZE=2 FACE="Arial">Intrusion Analyst</FONT>
<BR><FONT SIZE=2 FACE="Arial">NNSA Information Assurance Response Center (IARC)</FONT>
<BR><FONT SIZE=2 FACE="Arial">fergusonj@...13492...</FONT>
</P>
<BR>

</BODY>
</HTML>