← Back to team overview

touch-packages team mailing list archive

[Bug 1448396] Re: DNS Query poisoning Application UDP socket descriptor

 

** Information type changed from Private Security to Public

-- 
You received this bug notification because you are a member of Ubuntu
Touch seeded packages, which is subscribed to eglibc in Ubuntu.
https://bugs.launchpad.net/bugs/1448396

Title:
  DNS Query poisoning Application UDP socket descriptor

Status in eglibc package in Ubuntu:
  New

Bug description:
  Problem Description:

  When DNS query is fired from ubuntu (14.04) it uses random source port
  to send outgoing DNS request. It has been observed that random source
  port is not being checked if the port is already in use by other user
  application. As a result When DNS server sends the response, response
  is received by user application which may cause corruption/security
  issues in the application code.

  To make the problem easily reproducible we have increased few system
  limits to create 25000 UDP servers so that UDP port conflict with DNS
  happen frequntly

  Steps to Reproduce problem:
  ========================
  Step 1. Increase limit

      Per-User Limit

      Open file: /etc/security/limits.conf

      Paste following towards end:

      *         hard    nofile      500000
      *         soft    nofile      500000
      root      hard    nofile      500000
      root      soft    nofile      500000

  
      System-Wide Limit

      Set this higher than user-limit set above.

      Open /etc/sysctl.conf

      Add following:

      fs.file-max = 2097152

  Step 2. Reboot ubuntu

  Step 3. Verify new limits

      Use following command to see max limit of file descriptors:
      #cat /proc/sys/fs/file-max

      Hard Limit
      #ulimit -Hn

      Soft Limit
      #ulimit -Sn

  Step 4. Put following code in server.c and compile it (gcc server.c -o
  server). This will bind 25K UDP ports.

  /* 
   * server.c
   * 
   * Author: Vipin Kumar Gahlaut
   * 
   * CoreEmbedded Technologies Pvt Ltd
   * 
   */

  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <string.h>
  #include <fcntl.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <sys/epoll.h>

  #define MAX_CONNECTIONS             25000
  #define MAX_IP_STR                  16
  #define MAX_EPOLL_EVENTS_PER_RUN    1

  int setup_udp_server(char *ip, int port)
  {
      int sock;
      struct sockaddr_in  saddr;

      saddr.sin_family = AF_INET;
      saddr.sin_port = htons (port);
      saddr.sin_addr.s_addr = inet_addr(ip);

      if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
      {
         printf("Failed to created UDP Socket :%m\n");
          return -1;
      }

      if (bind (sock, (struct sockaddr *)&saddr, sizeof (saddr)) < 0)
      {
          close (sock);
          printf("Failed to bind on UDP port :%m\n");
          return -1;
      }

      return sock;
  }

  int main (int argc, char *argv[])
  {
      char                        ip[MAX_IP_STR];
      char                        buf[1024];
      int                         efd,sfd,nfds;
      struct epoll_event          ev,*events;
      int                         i=0,len;
      struct sockaddr_in          saddr;
      socklen_t                   addrlen=sizeof(struct sockaddr_in);

      if(argc < 2)
      {
          printf("Usage: server <ip>\n");
          exit(0);
      }
      if(strlen(argv[1]) >= MAX_IP_STR)
      {
          printf("Failed: Invalid IP Address\n");
          exit(0);
      }
      strcpy(ip,argv[1]);

      if((efd = epoll_create1(0)) < 0)
      {
          printf("Failed: epoll_create1: %m\n");
          exit(0);
      }

      for(i=0; i<MAX_CONNECTIONS; i++)
      {
          if((sfd=setup_udp_server(ip, 0)) < 0)
          {
              exit(0);
          }
          ev.events = EPOLLIN | EPOLLET | EPOLLERR;
          ev.data.fd = sfd;

          if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &ev) < 0)
          {
              printf("Couldn't add client socket to epoll set: %m\n");
              exit(0);
          }
          if (getsockname(sfd, (struct sockaddr *)&saddr, &addrlen ))
          {
              printf("Failed to get port for socket: %m\n");
              exit(0);
          }
          printf("FD: %d Port: %d Number of active servers: %d\n",sfd, ntohs(saddr.sin_port), i);
      }

      events = (struct epoll_event *)malloc(
                      MAX_EPOLL_EVENTS_PER_RUN * sizeof(struct epoll_event));

      if(events == NULL)
      {
          exit(0);
      }
      
      while(1)
      {
          nfds = epoll_wait(efd, events, MAX_EPOLL_EVENTS_PER_RUN, -1);

          if (nfds < 0) 
          {
              printf("epoll_wait failed: %m\n");
              exit(0);
          }

          for(i = 0; i < nfds; i++)
          {
              if (getsockname(events[i].data.fd, (struct sockaddr *)&saddr, &addrlen ))
              {
                  printf("Failed to get port for socket: %m\n");
                  exit(0);
              }

              printf("epoll waked on fd: %d port %d\n",events[i].data.fd,ntohs(saddr.sin_port));
              if(events[i].events & EPOLLIN)
              {
                  len = recvfrom(events[i].data.fd, buf, 1024, 0, 
                          (struct sockaddr *)&saddr, &addrlen);

                  printf("Received %d bytes on %d fd %m\n",len, events[i].data.fd);
                  printf("Source IP:Port %s:%d\n",inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
              }
          }
          

      }

      close(efd);
      return 0;
  }

  Step 5. Run server program by providing IP address of machine (example
  ./server 192.168.0.2)

  Step 6. User following shell script in another terminal to initiate
  DNS queries

  #!/bin/bash 
  COUNTER=0
      while [  $COUNTER -lt 100 ]; do
      nslookup www.ubuntu.com
  done

  Step 7. Observe that sometime DNS response is received by ./server
  instead of DNS client

  Problem Analysis: We have observed on wireshark that when problem
  happens source port used by DNS client/resolver library etc is one of
  the source port on which user application (in this case server) is
  already bind on that port and using it.

  This is a big concern because it causes problem both in DNS client
  (times out) and user application received spurious data. To my opinion
  this is a security issue as I am receiving data on a port that I have
  not exposed to anybody and depending on data it my crash/hijack my
  application. So I am also marking this bug as a security vulnerability
  so that security team can better asses the situation.

  Please note that With small number of UDP server chances of port
  conflict reduces but does not eliminate problem. DNS clinet/resolver
  library must have checked if source port is already in use or better
  to bind on port 0 (zero) so that system allocates available port not
  just random port. DNS client need to use random **available** port not
  just a random port.

  ProblemType: Bug
  DistroRelease: Ubuntu 14.04
  Package: libc6-dev 2.19-0ubuntu6
  ProcVersionSignature: Ubuntu 3.13.0-24.46-generic 3.13.9
  Uname: Linux 3.13.0-24-generic i686
  ApportVersion: 2.14.1-0ubuntu3
  Architecture: i386
  CurrentDesktop: Unity
  Date: Sat Apr 25 13:03:30 2015
  InstallationDate: Installed on 2014-05-20 (339 days ago)
  InstallationMedia: Ubuntu 14.04 LTS "Trusty Tahr" - Release i386 (20140417)
  SourcePackage: eglibc
  UpgradeStatus: No upgrade log present (probably fresh install)

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1448396/+subscriptions