SV.BFC.USING_STRUCT

Insecurely bound socket

Insecurely bound sockets can permit a malicious user to 'hijack' the server socket, gaining control of the connections and stealing user information.

On most systems, a combination of setting the SO_REUSEADDR socket option, and a call to bind() allows any process to bind to a port to which a previous process has bound with INADDR_ANY. Using INADDR_ANY allows the server to receive data on all the host's network interfaces. The bind() function doesn't check to make sure there isn't a socket already bound to INADDR_ANY on the same port when binding to a specific address. This situation allows malicious code to bind to the specific address of a server bound to INADDR_ANY on an unprivileged port, and access its UDP packets or TCP connection.

For this vulnerability, the SV.BFC.USING_STRUCT checker flags instances of INADDR_ANY in the sin_addr.s_addr field of struct sockaddr associated with a call to the bind function.

Vulnerability and risk

When a socket is created with a call to the socket function, it exists in a namespace, but has no name assigned to it. The bind function establishes the local association of the socket by assigning a local name to an unnamed socket.

A malicious application can call setsockopt() to set a socket option to SO_REUSEADDR and then forcibly bind to a port already in use for standard network protocol services in order to deny access to those services.

In the case of TCP connections, if an attacker binds an additional socket to a port already in use, any incoming TCP connection requests on that port cannot be guaranteed to be handled by the correct socket: the behavior is non-deterministic. The exception to the non-deterministic behavior is for multicast sockets. If two socket members of the same multicast group are bound to the same network interface and the port, data will be delivered to both sockets instead of a randomly selected one.

In these cases, packets from a variety of network services may be stolen or the services spoofed. A malicious user can also launch a denial-of-service (DoS) attack against the server.

Mitigation and prevention

Although it's easier to use INADDR_ANY than to specify an exact address, this practice allows another program to listen to the same port for a specific address on the machine, and a malicious program can intercept data coming from a client to the server. For this reason, it's best to use specific addresses in your code.

Vulnerable code example

Copy
  #include <sys/types.h>
  
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <arpa/inet.h>
  
  void bind_socket(void) {
 
      int server_sockfd;
      int server_len;
      struct sockaddr_in server_address;
 
      unlink("server_socket");
      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
      server_address.sin_family = AF_INET;
      server_address.sin_port = 21;
      server_address.sin_addr.s_addr = htonl(INADDR_ANY);
 
      server_len = sizeof(struct sockaddr_in);
 
      bind(server_sockfd, (struct sockaddr *) &server_address, server_len);
 }

Klockwork flags line 24, in which the code is binding to a struct sockaddr for which there is an associated INADDR_ANY keyword. The INADDR_ANY keyword in the server_address.sin_addr.s_addr field means that opportunistic code could bind to the same port and cause stolen packets or spoofed services.

Fixed code example

Copy
  #include <sys/types.h>
  
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <arpa/inet.h>
  
  void bind_socket(void) {
 
      int server_sockfd;
      int server_len;
      struct sockaddr_in server_address;
 
      unlink("server_socket");
      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
      server_address.sin_family = AF_INET;
      server_address.sin_port = 21;
      server_address.sin_addr.s_addr = inet_addr("192.168.1.10");
 
      server_len = sizeof(struct sockaddr_in);
 
      bind(server_sockfd, (struct sockaddr *) &server_address, server_len);
 }

In the fixed code example, the INADDR_ANY keyword has been replaced with a specific IP address.