Lista de verificación de seguridad del conductor
En este artículo se proporciona una lista de comprobación de seguridad de controladores para que los desarrolladores de controladores ayuden a reducir el riesgo de que los controladores se vean comprometidos.
Introducción a la seguridad del controlador
Un error de seguridad es cualquier error que permite a un atacante hacer que un controlador funcione mal de forma que hace que el sistema se bloquee o se vuelva inutilizable. Además, las vulnerabilidades en el código de controlador pueden permitir que un atacante obtenga acceso al kernel, lo que crea una posibilidad de poner en peligro todo el sistema operativo. Cuando la mayoría de los desarrolladores trabajan en su controlador, su enfoque consiste en conseguir que el controlador funcione correctamente y no en si un atacante malintencionado intentará aprovechar vulnerabilidades dentro de su código.
Sin embargo, una vez que se lanza un controlador, los atacantes pueden intentar investigar e identificar errores de seguridad. Los desarrolladores deben tener en cuenta estos problemas durante la fase de diseño e implementación para minimizar la probabilidad de estas vulnerabilidades. El objetivo es eliminar todos los errores de seguridad conocidos antes de que se lance el controlador.
La creación de controladores más seguros requiere la cooperación del arquitecto del sistema (pensando conscientemente en posibles amenazas al controlador), el desarrollador que implementa el código (codificando de forma defensiva las operaciones comunes que pueden ser la fuente de vulnerabilidades de seguridad) y el equipo de prueba (intentando encontrar de forma proactiva puntos débiles y vulnerabilidades). Al coordinar correctamente todas estas actividades, la seguridad del conductor se mejora considerablemente.
Además de evitar los problemas asociados a un controlador que se está atacando, muchos de los pasos descritos, como el uso más preciso de la memoria del kernel, aumentarán la confiabilidad del controlador. Esto reducirá los costos de soporte técnico y aumentará la satisfacción del cliente con su producto. Completar las tareas de la lista de comprobación siguiente le ayudará a lograr todos estos objetivos.
Lista de comprobación de seguridad:Complete la tarea de seguridad descrita en cada uno de estos temas.
Confirme que se requiere un controlador de núcleo
Usar los marcos del controlador
Controlar el acceso solo a los controladores del software
No firmar el código del controlador de prueba de producción
Seguir las directrices de codificación segura del controlador
Implementar código compatible con HVCI
Seguir procedimientos recomendados de código específicos de la tecnología
Realizar una revisión del código del mismo nivel
Administrar el control de acceso del controlador
mejorar la seguridad de la instalación de dispositivos
Ejecutar la firma adecuada del controlador de versión
Utilizar CodeQL para comprobar el código del controlador
Agregar anotaciones SAL al código del controlador
Utilice el verificador de controladores para verificar vulnerabilidades
Comprobar código con el analizador binario BinSkim
Verificar código con las pruebas del programa de compatibilidad de hardware
Revisar recursos seguros de codificación
Revisar el Resumen de conclusiones clave
Confirmación de que se requiere un controlador de kernel
elemento de lista de comprobación de seguridad n.º 1:Confirmar que se requiere un controlador de kernel y que un enfoque de riesgo menor, como el servicio o la aplicación de Windows, no es una opción mejor.
Los controladores residen en el kernel de Windows, y tener un problema al ejecutarse en el kernel expone todo el sistema operativo. Si hay alguna otra opción disponible, es probable que sea menor el costo y tenga menos riesgo asociado que crear un nuevo controlador de kernel. Para obtener más información sobre el uso de los controladores de Windows integrados, consulte ¿Necesita escribir un controlador?.
Para obtener información sobre el uso de tareas en segundo plano, consulte Como apoyar su aplicación con tareas en segundo plano.
Para obtener información sobre el uso de servicios de Windows, vea Services.
Usar los marcos del controlador
Elemento de la lista de comprobación de seguridad n.º 2:Utiliza los frameworks de controladores para reducir el tamaño del código y aumentar su fiabilidad y seguridad.
Usa el Windows Driver Frameworks para reducir el tamaño de tu código y aumentar su confiabilidad y seguridad. Para empezar, revise Uso de WDF para desarrollar un controlador. Para obtener información sobre el uso del marco del controlador en modo de usuario de menor riesgo (UMDF), consulte Elección de un modelo de controlador.
Escribir un controlador Windows Driver Model (WDM) antiguo requiere más tiempo, es más costoso y casi siempre implica volver a crear el código que esté disponible en los marcos del controlador.
El código fuente de Windows Driver Framework es de código abierto y está disponible en GitHub. Este es el mismo código fuente desde el que se compila la biblioteca en tiempo de ejecución de WDF que se incluye en Windows 10. Puede depurar el controlador de forma más efectiva si puede seguir las interacciones entre el controlador y WDF. Descárguelo de https://github.com/Microsoft/Windows-Driver-Frameworks.
Controlar el acceso solo a los controladores del software
elemento de lista de comprobación de seguridad n.º 3:Si se va a crear un controlador de solo software, se debe implementar un control de acceso adicional.
Los controladores de kernel de solo software no usan plug-and-play (PnP) para asociarse con identificadores de hardware específicos y pueden ejecutarse en cualquier equipo. Este controlador podría usarse con fines distintos de los previstos originalmente, creando un vector de ataque.
Dado que los controladores de kernel de solo software contienen riesgos adicionales, deben limitarse a ejecutarse en hardware específico (por ejemplo, mediante un identificador de PnP único para habilitar la creación de un controlador PnP o comprobando la tabla SMBIOS para ver la presencia de hardware específico).
Por ejemplo, imagine que OEM Fabrikam quiere distribuir un controlador que permita una utilidad de overclocking para sus sistemas. Si este controlador de solo software se ejecutara en un sistema desde un OEM diferente, la inestabilidad del sistema o los daños podrían resultar. Los sistemas de Fabrikam deben incluir un identificador de PnP único para habilitar la creación de un controlador PnP que también es actualizable a través de Windows Update. Si esto no es posible y Fabrikam crea un controlador heredado, ese controlador debe encontrar otro método para comprobar que se está ejecutando en un sistema Fabrikam (por ejemplo, mediante el examen de la tabla SMBIOS antes de habilitar cualquier funcionalidad).
No firmar el código del controlador de prueba de producción
Elemento de la lista de comprobación de seguridad n.º 4:no firme el código de producción del controlador del kernel para el desarrollo, pruebas y fabricación.
El código del controlador de kernel que se usa para el desarrollo, las pruebas o la fabricación pueden incluir funcionalidades peligrosas que suponen un riesgo de seguridad. Este código peligroso nunca debe firmarse con un certificado de confianza para Windows. El mecanismo correcto para ejecutar código de controlador peligroso es deshabilitar el arranque seguro UEFI, habilitar bcD "TESTSIGNING" y firmar el código de desarrollo, prueba y fabricación mediante un certificado que no es de confianza (por ejemplo, uno generado por makecert.exe).
El código firmado por un Certificado de los Editores de Software (SPC) de confianza o una firma de Windows Hardware Quality Labs (WHQL) no debe facilitar la elusión de las tecnologías de seguridad e integridad de código de Windows. Antes de firmar el código con una firma SPC o WHQL confiable, primero asegúrese de que cumpla con las pautas de Creación de controladores en modo kernel confiables. Además, el código no debe contener comportamientos peligrosos, descritos a continuación. Para obtener más información sobre la firma del controlador, consulte Ejecución de la firma adecuada del controlador de versión más adelante en este artículo.
Entre los ejemplos de comportamiento peligroso se incluyen los siguientes:
- Proporcionar la capacidad de asignar memoria arbitraria del kernel, física o del dispositivo al modo de usuario.
- Proporcionar la capacidad de leer o escribir memoria arbitraria del kernel, física o del dispositivo, incluida la entrada y salida del puerto (E/S).
- Proporcionar acceso al almacenamiento que omite el control de acceso de Windows.
- Proporcionar la capacidad de modificar el hardware o el firmware que el controlador no se diseñó para administrar.
Realizar análisis de amenazas
Elemento de la lista de comprobación de seguridad n.º 5:modifique un modelo de amenazas de controlador existente o cree un modelo de amenazas personalizado para el controlador.
Al considerar la seguridad, una metodología común consiste en crear modelos de amenazas específicos que intentan describir los tipos de ataques que son posibles. Esta técnica es útil al diseñar un controlador porque obliga al desarrollador a tener en cuenta los posibles vectores de ataque contra un controlador de antemano. Después de identificar posibles amenazas, un desarrollador de controladores puede considerar los medios de defensa contra estas amenazas para reforzar la seguridad general del componente de controlador.
En este artículo se proporcionan instrucciones específicas del controlador para crear un modelo de amenazas ligero: Modelado de amenazas para controladores. En el artículo se proporciona un diagrama de modelo de amenazas de un controlador de ejemplo que se puede utilizar como punto de partida para su controlador.
Los procedimientos recomendados del ciclo de vida de desarrollo de seguridad (SDL) y las herramientas asociadas se pueden usar en IHD y OEM para mejorar la seguridad de sus productos. Para obtener más información, consulte Recomendaciones de SDL para OEM.
Seguir las directrices de codificación segura del controlador
elemento de lista de comprobación de seguridad n.º 6:Revise el código y quite las vulnerabilidades de código conocidas.
La actividad principal de la creación de controladores seguros es identificar áreas en el código que deben cambiarse para evitar vulnerabilidades de software conocidas. Muchas de estas vulnerabilidades de software conocidas tienen que ver con el mantenimiento de un seguimiento estricto del uso de la memoria para evitar problemas con terceros que sobrescriban o comprometan de otro modo las ubicaciones de memoria que utiliza su controlador.
Las herramientas de análisis de código, como CodeQL y pruebas específicas del controlador, se pueden usar para ayudar a localizar, algunas, pero no todas, de estas vulnerabilidades. Estas herramientas y pruebas se describen más adelante en este tema.
Búferes de memoria
Compruebe siempre los tamaños de los búferes de entrada y salida para asegurarse de que los búferes pueden contener todos los datos solicitados. Para obtener más información, consulte Error al comprobar el tamaño de los búferes.
Inicialice correctamente todos los búferes de salida con ceros antes de devolverlos al autor de la llamada. Para obtener más información, vea Error al inicializar los búferes de salida.
Validar búferes de longitud variable. Para obtener más información, consulte Error al validar búferes de longitud variable Para obtener más información sobre cómo trabajar con búferes y usar ProbeForRead y ProbeForWrite para validar la dirección de un búfer, consulte Control de búferes.
Usar el método adecuado para acceder a los búferes de datos con ICTL
Una de las principales responsabilidades de un controlador de Windows es transferir datos entre las aplicaciones en modo de usuario y los dispositivos de un sistema. Los tres métodos para acceder a los búferes de datos se muestran en la tabla siguiente.
Tipo de búfer IOCTL | Resumen | Para obtener más información |
---|---|---|
METHOD_BUFFERED | Recomendado para la mayoría de las situaciones | Uso de E/S almacenada en búfer |
METHOD_IN_DIRECT o METHOD_OUT_DIRECT | Se utiliza en algunas E/S de hardware de alta velocidad | Uso de E/S directa |
METHOD_NEITHER | Evitar si es posible | Sin uso de búfer ni E/S directa |
En general, se recomienda la E/S almacenada en búfer, ya que proporciona los métodos de almacenamiento en búfer más seguros. Pero incluso cuando se usa la E/S almacenada en búfer existen riesgos, como punteros integrados, que deben mitigarse.
Para obtener más información sobre cómo trabajar con búferes en ioCTLs, consulte métodos de para acceder a búferes de datos.
Errores en el uso de E/S con búfer IOCTL
Compruebe el tamaño de los búferes relacionados con IOCTL. Para obtener más información, consulte Error al comprobar el tamaño de los búferes.
Inicialice correctamente los búferes de salida. Para obtener más información, vea Error al inicializar los búferes de salida.
Valide correctamente los búferes de longitud variable. Para obtener más información, consulte Error al validar búferes de longitud variable
Al usar E/S almacenada en búfer, asegúrese de devolver la longitud adecuada para OutputBuffer en el campo Información de estructura IO_STATUS_BLOCK. No solo devuelva directamente la longitud directamente desde una solicitud READ. Por ejemplo, considere una situación en la que los datos devueltos del espacio de usuario indican que hay un búfer 4K. Si el controlador en realidad solo debería devolver 200 bytes, pero en lugar de eso devuelve 4K en el campo Información, se ha producido una vulnerabilidad de divulgación de información. Este problema se produce porque en versiones anteriores de Windows, el búfer que utiliza el Administrador de E/S para la E/S almacenada en búfer no se inicializa a cero. Por lo tanto, la aplicación de usuario recupera los 200 bytes de datos originales más 4K-200 bytes de lo que había en el búfer (contenido del grupo no paginado). Este escenario puede producirse con todos los usos de E/S almacenados en búfer y no solo con IOCTL.
Errores en la E/S directa de IOCTL
Maneje correctamente los búferes de longitud cero. Para obtener más información, consulte Errores en E/S directa.
Errores al hacer referencia a direcciones de espacio de usuario
Valide punteros insertados en solicitudes de E/S almacenadas en búfer. Para obtener más información, consulte Errores al hacer referencia a direcciones de espacio de usuario.
Valide cualquier dirección en el espacio de usuario antes de intentar usarla, mediante API como ProbeForRead y ProbeForWrite cuando corresponda.
Lecturas y escrituras de registros específicos del modelo MSR
Los intrínsecos del compilador, como __readmsr y __writemsr se pueden usar para acceder a los registros específicos del modelo. Si se requiere este acceso, el conductor siempre debe comprobar que el registro que se va a leer o escribir esté restringido al índice o rango esperados.
Para obtener más información y ejemplos de código, consulte Proporcionar la capacidad de lectura y escritura de MSR en Procedimientos recomendados para restringir el comportamiento con privilegios elevados en los controladores del modo kernel.
Vulnerabilidades de TOCTOU
Existe una posible vulnerabilidad de tiempo de verificación a tiempo de uso (TOCTOU) cuando se usa E/S directa (para IOCTL o para lectura y escritura). Tenga en cuenta que el controlador accede al búfer de datos de usuario, el usuario puede acceder simultáneamente a él.
Para administrar este riesgo, copie los parámetros que necesiten validarse desde el búfer de datos de usuario a la memoria que sea accesible únicamente desde el modo kernel (como la pila o el grupo). Después, una vez que la aplicación de usuario no pueda acceder a los datos, valide y, a continuación, trabaje con los datos que fueron proporcionados.
El código del controlador debe hacer un uso correcto de la memoria
Todas las asignaciones del grupo de controladores deben estar en un grupo que no sea ejecutable (NX). El uso de grupos de memoria NX es intrínsecamente más seguro que el uso de grupos ejecutables no paginados (NP) y proporciona una mejor protección contra ataques de desbordamiento.
Los controladores de dispositivo deben manejar correctamente diversas solicitudes en modo usuario, así como solicitudes de E/S de kernel a kernel.
Para permitir que los controladores admitan la virtualización de HVCI, hay requisitos de memoria adicionales. Para obtener más información, consulte Implementación de código compatible con HVCI más adelante en este artículo.
Asas
- Valide los identificadores pasados entre la memoria en modo usuario y en modo kernel. Para obtener más información, consulte Administración de identificadores y Error al validar identificadores de objeto.
Objetos de dispositivo
Proteger objetos del dispositivo. Para obtener más información, consulte Asegurar objetos de dispositivo.
Valide los objetos de dispositivo. Para obtener más información, consulte Error al validar objetos de dispositivo.
IRP
WDF e IRP
Una ventaja de usar WDF es que los controladores WDF normalmente no acceden directamente a los IRP. Por ejemplo, el marco convierte los IRP de WDM que representan operaciones de control de E/S de lectura, escritura y dispositivo a objetos de solicitud de marco que KMDF/UMDF reciben en colas de E/S.
Si va a escribir un controlador WDM, revise las instrucciones siguientes.
Administrar correctamente los búferes de E/S de IRP
En los artículos siguientes se proporciona información sobre cómo validar los valores de entrada de IRP:
DispatchReadWrite mediante E/S almacenadas en búfer
Errores en E/S almacenada en búfer
DispatchReadWrite mediante E/S directa
Los Problemas de Seguridad de los Códigos de Control de E/S
Considere la posibilidad de validar los valores asociados a un IRP, como las direcciones y las longitudes del búfer.
Si elige usar Neither E/S, tenga en cuenta que, a diferencia de Lectura y Escritura, y a diferencia de E/S Almacenada en Búfer y E/S Directa, cuando se utiliza Neither E/S IOCTL, el Administrador de E/S no valida los punteros y longitudes del búfer.
Control correcto de las operaciones de finalización de IRP
Un controlador nunca debe completar un IRP con un valor de estado de STATUS_SUCCESS a menos que realmente admita y procese el IRP. Para obtener información sobre las formas correctas de controlar las operaciones de finalización de IRP, consulte Finalización de IRP.
Administración del estado pendiente del IRP del controlador
El controlador debe marcar el IRP como pendiente antes de almacenarlo y debe asegurarse de incluir tanto la llamada a IoMarkIrpPending como la asignación como parte de una secuencia interbloqueada. Para obtener más información, consulte Error al comprobar el estado de un controlador y Retener los IRP entrantes cuando un dispositivo está en pausa.
Manejar las operaciones de cancelación de IRP adecuadamente
Las operaciones de cancelación pueden ser difíciles de codificar correctamente porque normalmente se ejecutan de forma asincrónica. Los problemas en el código que controla las operaciones de cancelación pueden pasar desapercibidos durante mucho tiempo, ya que este código normalmente no se ejecuta con frecuencia en un sistema en ejecución. Asegúrese de leer y comprender toda la información proporcionada en Cancelación de IRP. Preste especial atención a la sincronización de la cancelación de IRP y a los puntos a tener en cuenta al cancelar IRP.
Una forma recomendada de minimizar los problemas de sincronización asociados con las operaciones de cancelación es implementar una cola IRP segura para la cancelación.
Control correcto de las operaciones de limpieza y cierre de IRP
Asegúrese de que comprende la diferencia entre las solicitudes IRP_MJ_CLEANUP y IRP_MJ_CLOSE. Las solicitudes de limpieza llegan después de que una aplicación cierre todos los identificadores de un objeto de archivo, pero a veces antes de que se hayan completado todas las solicitudes de E/S. Las solicitudes de cierre llegan después de que se hayan completado o cancelado todas las solicitudes de E/S para el objeto de archivo. Para obtener más información, consulte los artículos siguientes:
Rutinas DispatchCreate, DispatchClose y DispatchCreateClose
Errores en el Control de las Operaciones de Limpieza y Cierre
Para obtener más información sobre el control correcto de IRP, consulte Errores adicionales en el control de IRP.
Otros problemas de seguridad
Use un bloqueo o una secuencia entrelazada para evitar condiciones de carrera. Para obtener más información, vea errores de en un entorno multiprocesador.
Asegúrese de que los controladores de dispositivo controlan correctamente varios modos de usuario, así como el kernel a las solicitudes de E/S del kernel.
Asegúrese de que ni el controlador ni los paquetes de software asociados instalen filtros TDI o LSP durante la instalación o el uso.
Uso de funciones seguras
Use funciones de cadena seguras. Para obtener más información, consulte Using Safe String Functions.
Use funciones aritméticas seguras. Para obtener más información, consulte Rutinas de biblioteca de enteros seguras.
Usar funciones de conversión seguras.
Vulnerabilidades de código adicionales
Además de las posibles vulnerabilidades que se describen aquí, este artículo proporciona información adicional sobre cómo mejorar la seguridad del código de controlador en modo kernel: Creación de controladores fiables Kernel-Mode.
Para obtener más información sobre la codificación segura de C y C++, consulte Recursos de codificación seguros al final de este artículo.
Administrar el control de acceso del controlador
Elemento de la lista de comprobación de seguridad n.º 7:revise el controlador para asegurarse de que controla el acceso correctamente.
Administración del control de acceso del controlador: WDF
Los controladores deben funcionar para evitar que los usuarios accedan de forma inapropiada a los dispositivos y archivos de un equipo. Para evitar el acceso no autorizado a dispositivos y archivos, debe:
Asigne un nombre a los objetos de dispositivo solo cuando sea necesario. Los objetos de dispositivo con nombre generalmente solo son necesarios por motivos heredados, por ejemplo, si tiene una aplicación que espera abrir el dispositivo con un nombre en particular o si está utilizando un dispositivo que no sea PNP o un dispositivo de control. Tenga en cuenta que los controladores WDF no necesitan asignar un nombre FDO al dispositivo PnP para crear un vínculo simbólico mediante WdfDeviceCreateSymbolicLink.
Proteger el acceso a los objetos e interfaces del dispositivo.
Para permitir que las aplicaciones u otros controladores WDF accedan al PDO del dispositivo PnP, debe usar interfaces de dispositivo. Para obtener más información, consulte Uso de interfaces de dispositivos. Una interfaz de dispositivo actúa como un vínculo simbólico al PDO de la pila de dispositivos.
Una de las mejores formas de controlar el acceso al PDO es especificando una cadena SDDL en el INF. Si la cadena SDDL no está en el archivo INF, Windows aplicará un descriptor de seguridad predeterminado. Para obtener más información, consulte Protección de objetos de dispositivo y SDDL para objetos de dispositivo.
Para obtener más información sobre el control del acceso, consulte los siguientes artículos:
Control del acceso a dispositivos en controladores KMDF
Nombres, descriptores de seguridad y clases de dispositivo: hacer que los objetos de dispositivo sean accesibles... and SAFE desde enero, febrero 2017 The NT Insider Newsletter publicado por OSR.
Administración del control de acceso del controlador: WDM
Si está trabajando con un controlador WDM y ha usado un objeto de dispositivo con nombre, puede usar IoCreateDeviceSecure y especificar un SDDL para protegerlo. Al implementar IoCreateDeviceSecure, especifique siempre un GUID de clase personalizado para DeviceClassGuid. No debe especificar aquí un GUID de clase existente. Si lo hace, puede interrumpir la configuración de seguridad o la compatibilidad con otros dispositivos que pertenecen a esa clase. Para obtener más información, vea WdmlibIoCreateDeviceSecure.
Para obtener más información, consulte los artículos siguientes:
Control del acceso al dispositivo
Control del acceso al espacio de nombres del dispositivo
modelo de seguridad de Windows para desarrolladores de controladores
Jerarquía de riesgos de identificadores de seguridad (SID)
En la sección siguiente se describe la jerarquía de riesgos de los SID comunes que se usan en el código de controlador. Para obtener información general sobre SDDL, consulte SDDL para objetos de dispositivo, Cadenas SID y la sintaxis de cadenas SDDL.
Es importante comprender que si se permite que los autores de llamadas con privilegios inferiores accedan al kernel, se aumenta el riesgo de código. En este diagrama de resumen, el riesgo aumenta a medida que se permite el acceso de los SIDs de menor privilegio a la funcionalidad de su controlador.
SY (System)
\/
BA (Built-in Administrators)
\/
LS (Local Service)
\/
BU (Built-in User)
\/
AC (Application Container)
Después del principio general de seguridad de privilegios mínimos, configure solo el nivel mínimo de acceso necesario para que el controlador funcione.
Control de seguridad IOCTL pormenorizado de WDM
Para administrar aún más la seguridad cuando los autores de llamadas en modo de usuario envían IOCTL, el código de controlador puede incluir la función IoValidateDeviceIoControlAccess. Esta función permite a un controlador comprobar los derechos de acceso. Al recibir un IOCTL, un controlador puede llamar a IoValidateDeviceIoControlAccess, especificando FILE_READ_ACCESS, FILE_WRITE_ACCESS o ambos.
La implementación de un control de seguridad IOCTL pormenorizado no reemplaza la necesidad de administrar el acceso de los controladores mediante las técnicas descritas anteriormente.
Para obtener más información, consulte los artículos siguientes:
Definir Códigos de Control de E/S
Implementación de código compatible con HVCI
elemento de lista de comprobación de seguridad n.º 8:Validar que el controlador usa memoria para que sea compatible con HVCI.
Uso de memoria y compatibilidad con HVCI
HVCI usa tecnología de hardware y virtualización para aislar la función de toma de decisiones de integridad de código (CI) del resto del sistema operativo. Cuando se utiliza la seguridad basada en virtualización para aislar CI, la única forma en que la memoria del kernel se puede convertir en ejecutable es mediante una verificación de CI. Esto significa que las páginas de memoria del kernel nunca pueden ser grabables y ejecutables (W+X) y el código ejecutable no se puede modificar directamente.
Para implementar código compatible con HVCI, asegúrese de que el código de controlador haga lo siguiente:
- Participa en NX de forma predeterminada
- Usa las API o marcas de NX para la asignación de memoria (NonPagedPoolNx)
- No usa secciones que son grabables y ejecutables
- No intenta modificar directamente la memoria del sistema ejecutable
- No usa código dinámico en kernel
- No carga archivos de datos como ejecutables
- La alineación de sección es un múltiplo de 0x1000 (PAGE_SIZE). Por ejemplo, DRIVER_ALIGNMENT=0x1000
Para obtener más información sobre el uso de la herramienta y una lista de llamadas a memoria incompatibles, consulte Implementación de código compatible con HVCI.
Para obtener más información sobre la prueba de seguridad de los aspectos básicos del sistema relacionados, consulte Prueba de preparación de integridad de código de HyperVisor e Integridad del código protegido por hipervisor (HVCI).
Seguir prácticas recomendadas de codificación específicas para la tecnología
Elemento de la lista de comprobación de seguridad n.º 9:revise la siguiente guía tecnológica específica para el controlador.
Sistemas de archivos
Para obtener más información, acerca de la seguridad del controlador del sistema de archivos, consulte los artículos siguientes:
Introducción a la seguridad de los sistemas de archivos
problemas de seguridad del sistema de archivos
Características de seguridad para sistemas de archivos
Coexistencia con otros controladores de filtro del sistema de archivos
NDIS: redes
Para obtener información sobre la seguridad del controlador NDIS, consulte Cuestiones de Seguridad para Controladores de Red.
Display
Para obtener información sobre la seguridad del controlador de visualización, consulte <Contenido pendiente>.
Impresoras
Para obtener información relacionada con la seguridad del controlador de impresora, consulte Consideraciones de seguridad del controlador de impresora V4.
Problemas de seguridad para controladores de adquisición de imágenes de Windows (WIA)
Para obtener información sobre la seguridad de WIA, consulta Problemas de seguridad de los controladores WIA de adquisición de imágenes de Windows.
Mejora de la seguridad de la instalación de dispositivos
Elemento de la lista de comprobación de seguridad n.º 10:revise las instrucciones de creación e instalación del controlador para asegurarse de que sigue los procedimientos recomendados.
Al crear el código que instala el controlador, debe asegurarse de que la instalación del dispositivo siempre se realizará de forma segura. Una instalación segura de dispositivos es una que hace lo siguiente:
- Limita el acceso al dispositivo y a sus clases de interfaz de dispositivo.
- Limita el acceso a los servicios de controlador que se crearon para el dispositivo.
- Protege los archivos de controlador de la modificación o eliminación
- Limita el acceso a las entradas del Registro del dispositivo.
- Limita el acceso a las clases WMI del dispositivo.
- Usa las funciones SetupAPI correctamente
Para obtener más información, consulte los artículos siguientes:
Creación de Instalaciones Seguras de Dispositivos
Directrices para el uso de setupAPI
Uso de funciones de instalación de dispositivos
Temas avanzados de instalación de dispositivos y controladores
Realizar una revisión del código del mismo nivel
elemento de lista de comprobación de seguridad n.º 11:Realizar revisión del código del mismo nivel, para buscar problemas no expuestos por las otras herramientas y procesos
Busque revisores de código con conocimientos para buscar problemas que puede haber perdido. Un segundo conjunto de ojos a menudo verá problemas que puede haber pasado por alto.
Si no tiene personal adecuado para revisar el código internamente, considere contratar ayuda externa para este propósito.
Ejecutar la firma adecuada del controlador de versión
Elemento de la lista de comprobación de seguridad n.º 12:use el portal de asociados de Windows para firmar correctamente el controlador para su distribución.
Antes de liberar un paquete de controladores al público, se recomienda enviar el paquete para su certificación. Para obtener más información, consulte Prueba de rendimiento y compatibilidad, Introducción al programa de Hardware, Servicios del Panel de Control de Hardwarey firma de atestación de un controlador de kernel para la versión pública.
Uso de CodeQL para comprobar el código del controlador
Elemento de la lista de comprobación de seguridad n.º 13:use CodeQL para comprobar si hay vulnerabilidades en el código de controlador.
CodeQL, de GitHub, es un motor de análisis de código semántico y la combinación de un amplio conjunto de consultas de seguridad junto con una plataforma sólida lo convierten en una herramienta inestimable para proteger el código de controlador. Para obtener más información, consulte CodeQL y Static Tools Logo Test.
Añade anotaciones SAL a tu código de controlador
Elemento de la lista de comprobación de seguridad n.º 14:agregue anotaciones SAL a en el código de controlador.
El lenguaje de anotación de código fuente (SAL) proporciona un conjunto de anotaciones que puede usar para describir cómo una función usa sus parámetros, las suposiciones que realiza sobre ellos y las garantías que realiza cuando finaliza. Las anotaciones se definen en el archivo de encabezado sal.h
. El análisis de código de Visual Studio para C++ usa anotaciones SAL para modificar su análisis de funciones. Para obtener más información sobre el desarrollo de controladores SAL 2.0 para Windows, consulta Anotaciones de SAL 2.0 para controladores de Windows y Usar anotaciones SAL para reducir defectos de código de C/C++.
Para obtener información general sobre SAL, consulte este artículo disponible en OSR. https://www.osr.com/blog/2015/02/23/sal-annotations-dont-hate-im-beautiful/
Uso del comprobador de controladores para comprobar si hay vulnerabilidades
elemento de lista de comprobación de seguridad n.º 15:Usar comprobador de controladores para comprobar si hay vulnerabilidades en el código de controlador.
El Comprobador de controladores usa un conjunto de reglas de interfaz y un modelo del sistema operativo para determinar si el controlador interactúa correctamente con el sistema operativo Windows. DV encuentra defectos en el código de controlador que podrían apuntar a posibles errores en los controladores.
El Comprobador de controladores permite realizar pruebas en vivo del controlador. El comprobador de controladores supervisa los controladores del modo kernel de Windows y los controladores de gráficos para detectar llamadas o acciones de función no válidas que podrían dañar el sistema. El Comprobador de controladores puede someter los controladores de Windows a una variedad de tensiones y pruebas para encontrar un comportamiento incorrecto. Para obtener más información, consulte Comprobador de controladores.
Tenga en cuenta que solo ciertos tipos de controladores son compatibles con DV. Para obtener más información sobre los controladores que DV puede comprobar, consulte controladores compatibles. Consulte las páginas siguientes para obtener información sobre las pruebas DV disponibles para el tipo de controlador con el que está trabajando.
- Reglas para controladores WDM
- Reglas para controladores KMDF
- Reglas para controladores NDIS
- Reglas para controladores Storport
- Reglas para controladores de audio
- Reglas para controladores AVStream
Para familiarizarse con DV, puede usar uno de los controladores de ejemplo (por ejemplo, el ejemplo de toaster destacado: https://github.com/Microsoft/Windows-driver-samples/tree/main/general/toaster/toastDrv/kmdf/func/featured).
Comprobación del código con el Analizador binario binSkim
elemento de lista de comprobación de seguridad n.º 16:Siga estos pasos para usar BinSkim para comprobar que las opciones de compilación y compilación están configuradas para minimizar los problemas de seguridad conocidos.
Use BinSkim para examinar los archivos binarios para identificar las prácticas de codificación y creación que pueden representar potencialmente la vulnerabilidad binaria.
BinSkim comprueba si:
- Uso de conjuntos de herramientas del compilador obsoletos: los archivos binarios deben compilarse en los conjuntos de herramientas del compilador más recientes siempre que sea posible para maximizar el uso de mitigaciones de seguridad proporcionadas por el compilador y del sistema operativo actuales.
- Configuración de compilación no segura: los archivos binarios deben compilarse con la configuración más segura posible para habilitar mitigaciones de seguridad proporcionadas por el sistema operativo, maximizar los errores del compilador y los informes de advertencias accionables, entre otras cosas.
- Problemas de firma: los archivos binarios firmados deben firmarse con algoritmos criptográficos seguros.
BinSkim es una herramienta de código abierto y genera archivos de salida que usan el formato de intercambio de resultados de análisis estáticos (formato SARIF). BinSkim reemplaza la herramienta anterior BinScope.
Para obtener más información sobre BinSkim, consulte Usar BinSkim para comprobar los binarios y la Guía del Usuario de BinSkim.
Comprobación del código con las pruebas del programa de compatibilidad de hardware
elemento de lista de comprobación de seguridad n.º 17:Use las pruebas del programa de compatibilidad de hardware relacionadas con la seguridad para comprobar si hay problemas de seguridad.
El programa de compatibilidad de hardware incluye pruebas relacionadas con la seguridad se puede usar para buscar vulnerabilidades de código. El Programa de compatibilidad de hardware de Windows aprovecha las pruebas del Kit de laboratorio de hardware de Windows (HLK). Las pruebas de aspectos básicos del dispositivo HLK se pueden usar en la línea de comandos para ejercer el código del controlador y sondear si hay puntos débiles. Para obtener información general sobre las pruebas fundamentales del dispositivo y el programa de compatibilidad de hardware, consulte Windows Hardware Lab Kit.
Las siguientes pruebas son ejemplos de pruebas que pueden resultar útiles para comprobar el código de controlador para ver algunos comportamientos asociados a vulnerabilidades de código:
DF: Prueba aproximada de IOCTL aleatoria (confiabilidad)
DF: Prueba aproximada de aperturas relativas (confiabilidad)
DF: Prueba aproximada FSCTL de búfer de longitud cero (confiabilidad)
DF: Prueba aproximada de FSCTL aleatoria (confiabilidad)
DF: Prueba aproximada de Misc API (confiabilidad)
También puede usar la pruebas de vulnerabilidad ante datos aleatorios o inesperados de demora en la sincronización del kernel que se incluye con el comprobador de controladores.
Las pruebas CHAOS (hardware simultáneo y sistema operativo) ejecutan varias pruebas de controladores PnP, pruebas aproximadas del controlador de dispositivo y pruebas del sistema de energía simultáneamente. Para obtener más información, consulte Pruebas CHAOS (aspectos básicos del dispositivo).
Las pruebas de penetración de los fundamentos del dispositivo realizan varias formas de ataques de entrada, que son un componente crítico de las pruebas de seguridad. Las pruebas de ataque y penetración pueden ayudar a identificar vulnerabilidades en las interfaces de software. Para obtener más información, consulte Pruebas de penetración (aspectos básicos del dispositivo).
Utilice el Device Guard: Prueba de Cumplimiento, junto con las otras herramientas descritas en este artículo, para confirmar que su controlador es compatible con HVCI.
Herramientas de prueba personalizadas y específicas del dominio
Considere el desarrollo de pruebas de seguridad específicas del dominio personalizadas. Para desarrollar pruebas adicionales, recopile información de los diseñadores originales del software, así como de recursos de desarrollo externos familiarizados con el controlador específico que se está desarrollando y de una o más personas que conozcan el análisis y la prevención de intrusiones de seguridad.
Comprender cómo se notifican los controladores mediante el Centro de informes de controladores vulnerables y malintencionados de Microsoft
Elemento de lista de comprobación de seguridad n.º 18: comprenda cómo se notifican los controladores mediante el Centro de informes de controladores vulnerables y malintencionados de Microsoft
Cualquier persona puede enviar un controlador interrogable mediante el Centro de informes de controladores vulnerables y malintencionados de Microsoft. Consulte esta entrada de blog para obtener información sobre cómo se envían los controladores para su análisis: Mejorar la seguridad del kernel con el nuevo Centro de informes de controladores vulnerables y malintencionados de Microsoft
El Centro de informes puede examinar y analizar controladores de Windows creados para arquitecturas x86 y x64. Los controladores analizados vulnerables y malintencionados se marcan para su análisis e investigación por parte del equipo de controladores vulnerables de Microsoft. Una vez confirmados los controladores vulnerables, se emite una notificación adecuada y se añaden a la lista de bloqueos de controladores vulnerables. Para obtener más información sobre esto, consulte reglas de bloqueo de controladores recomendadas por Microsoft. Estas reglas se aplican de forma predeterminada a los dispositivos habilitados para integridad de código protegido por hipervisor (HVCI) y Windows 10 en modo S.
Revisión de los recursos de codificación seguros
Elemento de la lista de comprobación de seguridad n.º 19:revise estos recursos para ampliar la comprensión de los procedimientos recomendados de codificación segura aplicables a los desarrolladores de controladores.
Directrices de codificación de controladores en modo kernel seguro
Crear controladores fiables Kernel-Mode
Protección de las organizaciones de codificación
Carnegie Mellon University SEI CERT
Estándar de codificación C De la Universidad Carnegie Mellon: Reglas para desarrollar sistemas seguros, confiables y seguros (edición 2016).
MITRE - Debilidades Abordadas por el Estándar de Codificación Segura CERT C
Creación de seguridad en el modelo de madurez (BSIMM): https://www.bsimm.com/
SAFECode: https://safecode.org/
OSR
OSR proporciona servicios de consultoría y aprendizaje para el desarrollo de controladores. Estos artículos del boletín OSR destacan los problemas de seguridad de los controladores.
Debe usar la protección: seguridad interna del controlador & del dispositivo
Bloqueo de controladores: una encuesta sobre técnicas
Meltdown y Spectre: ¿qué pasa con los controladores?
Estudio de casos
Libros
24 pecados mortales de seguridad de software: errores de programación y cómo corregirlos por Michael Howard, David LeBlanc y John Viega
el arte de la evaluación de seguridad de software: identificación y prevención de vulnerabilidades de software, Mark Dowd, John McDonald y Justin Schuh
Escribir Software Seguro Segunda Edición, de Michael Howard y David LeBlanc
The Art of Software Security Assessment: Identificación y prevención de vulnerabilidades de software, Mark Dowd y John McDonald
codificación segura en C y C++ (serie SEI en ingeniería de software) 2ª edición, Robert C. Seacord
Programar el Modelo de Controlador de Microsoft Windows (2ª Edición), Walter Oney
Desarrollar controladores con Windows Driver Foundation (Referencia del desarrollador), Penny Orwick y Guy Smith
Adiestramiento
El entrenamiento educativo de controladores de Windows está disponible en proveedores como los siguientes:
El entrenamiento en línea de codificación segura está disponible desde una variedad de orígenes. Por ejemplo, este curso está disponible en coursera en:
Identificar vulnerabilidades de seguridad en la programación de C/C++.
SAFECode también ofrece entrenamiento gratuito:
Certificación profesional
CERT ofrece una certificación de Profesional en Codificación Segura .
Resumen de las conclusiones clave
La seguridad del conductor es una tarea compleja que contiene muchos elementos, pero estos son algunos puntos clave que se deben tener en cuenta:
Los controladores residen en el kernel de Windows y tener un problema cuando se ejecutan en el kernel expone todo el sistema operativo. Por este motivo, preste mucha atención a la seguridad y al diseño de los controladores teniendo en cuenta la seguridad.
Aplique el principio de privilegios mínimos:
a. Usar una cadena SDDL estricta para restringir el acceso al controlador
b. Restringir aún más los IOCTL individuales
Cree un modelo de amenazas para identificar vectores de ataque y considere si algo se puede restringir más.
Tenga cuidado con los punteros incrustados que se pasan desde el modo de usuario. Es necesario probarlos, acceder a ellos dentro de try except y son propensos a vulnerabilidad de tiempo de verificación a tiempo de uso (ToCToU) a menos que se capture y compare el valor del búfer.
Si no está seguro, use METHOD_BUFFERED como método de almacenamiento en búfer IOCTL.
Use utilidades de análisis de código para buscar vulnerabilidades de código conocidas y corregir los problemas identificados.
Busque revisores de código con conocimientos para buscar problemas que puede haber perdido.
Use comprobadores de controladores y pruebe el controlador con varias entradas, incluidos casos extremos.