Compartir a través de


Problemas de seguridad para controladores de red

Para obtener una explicación general sobre cómo escribir controladores seguros, consulte Creación de controladores confiables Kernel-Mode.

Además de seguir los siguientes procedimientos de codificación seguros y las instrucciones generales del controlador de dispositivo, los controladores de red deben hacer lo siguiente para mejorar la seguridad:

  • Todos los controladores de red deben validar los valores que leen del Registro. En concreto, el autor de la llamada de NdisReadConfiguration o NdisReadNetworkAddress no debe realizar ninguna suposición sobre los valores leídos del Registro y debe validar cada valor del Registro que lea. Si el autor de la llamada de NdisReadConfiguration determina que un valor está fuera de los límites, debe usar un valor predeterminado en su lugar. Si el autor de la llamada de NdisReadNetworkAddress determina que un valor está fuera de los límites, debe usar la dirección de control de acceso medio permanente (MAC) o una dirección predeterminada en su lugar.

Problemas específicos del OID

Directrices de seguridad para la consulta de OID

La mayoría de los OID de consulta pueden ser emitidos por cualquier aplicación de modo de usuario en el sistema. Siga estas instrucciones específicas para los OID de consulta.

  1. Valide siempre que el tamaño del búfer sea lo suficientemente grande como para la salida. Cualquier controlador de OID de consulta sin una comprobación de tamaño de búfer de salida tiene un error de seguridad.

    if (oid->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        oid->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG);
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. Escriba siempre un valor correcto y mínimo en BytesWritten. Es una marca roja para asignar oid->BytesWritten = oid->InformationBufferLength como hace el ejemplo siguiente.

    // ALWAYS WRONG
    oid->DATA.QUERY_INFORMATION.BytesWritten = DATA.QUERY_INFORMATION.InformationBufferLength; 
    

    El sistema operativo copiará los BytesWritten de nuevo a una aplicación en modo de usuario. Si BytesWritten es mayor que el número de bytes que realmente escribió el controlador, el sistema operativo podría terminar copiando memoria de kernel no inicializada a modo usuario, lo cual sería una vulnerabilidad de divulgación de información. En su lugar, use código similar al siguiente:

    oid->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG);
    
  3. Nunca lea los valores de regreso del búfer. En algunos casos, el búfer de salida de un OID se asigna directamente a un proceso de modo de usuario hostil. El proceso hostil puede cambiar el búfer de salida después de que hayas escrito en él. Por ejemplo, se puede atacar el código siguiente, ya que un atacante puede cambiar NumElements después de escribirlo:

    output->NumElements = 4;
    for (i = 0 ; i < output->NumElements ; i++) {
        output->Element[i] = . . .;
    }
    

    Para evitar volver a leer desde el búfer, mantenga una copia local. Por ejemplo, para corregir el ejemplo anterior, introduzca una nueva variable de pila:

    ULONG num = 4;
    output->NumElements = num;
    for (i = 0 ; i < num; i++) {
        output->Element[i] = . . .;
    }
    

    Con este enfoque, el bucle for lee de nuevo de la variable num de pila del controlador y no de su búfer de salida. El controlador también debe marcar el búfer de salida con la volatile palabra clave para evitar que el compilador deshaga silenciosamente esta corrección.

Establecimiento de directrices de seguridad de OID

La mayoría de los identificadores de configuración (Set OIDs) se pueden emitir mediante una aplicación en modo de usuario que se ejecuta dentro de los grupos de seguridad de administradores o del sistema. Aunque generalmente son aplicaciones de confianza, el controlador de miniporte todavía no debe permitir daños en la memoria ni la inyección de código kernel. Siga estas reglas específicas para Establecer identificadores operativos:

  1. Valide siempre que la entrada sea lo suficientemente grande. Cualquier controlador de conjunto de OID sin una comprobación de tamaño de búfer de entrada tiene una vulnerabilidad de seguridad.

    if (oid->DATA.SET_INFORMATION.InformationBufferLength < sizeof(ULONG)) {
        return NDIS_STATUS_INVALID_LENGTH;
    }
    
  2. Siempre que valide un OID con un desplazamiento incrustado, debe validar que el búfer incrustado está dentro de la carga del OID. Esto requiere varias comprobaciones. Por ejemplo, OID_PM_ADD_WOL_PATTERN puede proporcionar un patrón incrustado, que debe comprobarse. La validación correcta requiere la comprobación:

    1. InformationBufferSize >= sizeof(NDIS_PM_PACKET_PATTERN)

      PmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
      {
          Status = NDIS_STATUS_BUFFER_TOO_SHORT;
          *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
          break;
      }
      
    2. Pattern->PatternOffset + Pattern->PatternSize no produce un desbordamiento

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternSize, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

      Estas dos comprobaciones se pueden combinar mediante código como el ejemplo siguiente:

      ULONG TotalSize = 0;
      if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN) ||
          !NT_SUCCESS(RtlUlongAdd(Pattern->PatternSize, Pattern->PatternOffset, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    3. InformationBuffer + Patrón->DesplazamientoDePatrón + Patrón->LongitudDePatrón no desborda

      ULONG TotalSize = 0;
      if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          (!NT_SUCCESS(RtlUlongAdd(TotalSize, InformationBuffer, &TotalSize) ||
          TotalSize > InformationBufferLength) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      
    4. Pattern-PatternOffset> + Pattern-PatternLength <>= InformationBufferSize

      ULONG TotalSize = 0;
      if(!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) ||
          TotalSize > InformationBufferLength)) 
      {
          return NDIS_STATUS_INVALID_LENGTH;
      }
      

Directrices de seguridad del método OID

Los OID de método se pueden emitir mediante una aplicación de modo de usuario que se ejecuta en los grupos de seguridad administradores o del sistema. Son una combinación de un conjunto y una consulta, por lo que ambas listas anteriores de instrucciones también se aplican a los OID de método.

Otros problemas de seguridad del controlador de red

  • Muchos controladores de miniporte NDIS exponen un dispositivo de control mediante NdisRegisterDeviceEx. Los que lo hacen deben auditar sus controladores de IOCTL, con todas las mismas reglas de seguridad que un controlador WDM. Para obtener más información, consulte Problemas de seguridad para códigos de control de E/S.

  • Los controladores de miniporte NDIS bien diseñados no deben confiar en ser invocados en un contexto de proceso específico, ni interactuar de manera estrecha con el modo de usuario, a excepción de IOCTLs y OIDs. Sería una señal de alerta ver que un minipuerto abriera identificadores de modo de usuario, realizara esperas de modo de usuario, o asignara memoria contra la cuota de modo de usuario. Ese código debe investigarse.

  • La mayoría de los controladores de miniporte NDIS no deben estar implicados en el análisis de cargas de paquetes. Sin embargo, en algunos casos, puede ser necesario. Si es así, este código debe auditarse cuidadosamente, ya que el controlador analiza los datos de un origen que no es de confianza.

  • Como es estándar al asignar memoria en modo kernel, los controladores NDIS deben usar los mecanismos adecuados del grupo de NX Opt-In. En WDK 8 y versiones posteriores, la familia de funciones NdisAllocate* está habilitada correctamente.