Implementación segura de MOR

Resumen

  • Comportamiento de MorLock, revisión 2

Última actualización

  • Agosto de 2020

Se aplica a

  • Windows 10

  • Oem y proveedores de BIOS que quieran admitir la característica Credential Guard de Windows 10.

Especificaciones oficiales

Información general

En este tema se describe el comportamiento y el uso de la MemoryOverwriteRequestControlLock variable UEFI, revisión 2.

Para evitar ataques avanzados de memoria, la mitigación de seguridad del BIOS del sistema existente MemoryOverwriteRequestControl se ha mejorado para admitir el bloqueo para defenderse contra nuevas amenazas. El modelo de amenazas se expande para incluir el kernel del sistema operativo host como adversario, por lo que los servicios en tiempo de ejecución ACPI y UEFI que se ejecutan en el nivel de privilegios del kernel no son de confianza. De forma similar a las implementaciones de arranque seguro, MorLock debe implementarse en un contexto de ejecución de firmware con privilegios que el kernel del sistema operativo del host no puede alterar (por ejemplo, modo de administración del sistema, TrustZone, BMC, etc.). La interfaz se basa en los servicios de variables UEFI, que se describen en la versión 2.5 de la especificación UEFI, sección 7.2 denominada "Servicios de variables".

Esta mitigación, denominada MorLock, debe implementarse en todos los nuevos sistemas y no solo se limita a los sistemas con módulos de plataforma segura. La revisión 2 agrega una nueva funcionalidad, desbloqueo, para mitigar los problemas de rendimiento de arranque, especialmente en sistemas de memoria grandes.

Con respecto al método de control ACPI _DSM para establecer el estado de bits MOR (como se describe en la sección 6 de la especificación de mitigación de ataques de restablecimiento de la plataforma de trabajo cliente de PC, versión 1.10 (descarga pdf)), se recomienda quitar este método _DSM de las implementaciones modernas del BIOS.

Sin embargo, si un BIOS implementa este método de _DSM, debe respetar el estado de MorLock. Si morLock está bloqueado, con o sin una clave, este método de _DSM debe no cambiar MOR y devolver un valor de 1 correspondiente a "Error general". No se define ningún mecanismo ACPI para desbloquear la revisión 2 de MorLock.

Ten en cuenta que Windows no ha invocado directamente este método _DSM desde Windows 7 y lo considera en desuso. Algunos BIOS invocan indirectamente este método de _DSM cuando Windows invoca ACPI _PTS como implementación de la detección automática mor de apagado limpio (como se describe en la sección 2.3 de especificación de mitigación de ataques de restablecimiento de la plataforma de grupo de trabajo cliente de PC, versión 1.10 (descarga en PDF).

Este ACPI _PTS implementación de la detección automática mor es deficiente para la seguridad y NO debe utilizarse.

MemoryOverwriteRequestControlLock

El BIOS que contiene la mitigación mejorada crea esta variable UEFI durante el arranque temprano:

VendorGuid:{BB983CCF-151D-40E1-A07B-4A17BE168292}

Nombre:MemoryOverwriteRequestControlLock

Atributos: NV+BS+RT

Valor GetVariable en el parámetro Data : 0x0 (desbloqueado); 0x1 (bloqueado sin llave); 0x2 (bloqueado con clave)

Valor SetVariable en parámetro Data : 0x0 (desbloqueado); 0x1 (bloqueado)

Bloqueo con SetVariable

En cada arranque, el BIOS se inicializará MemoryOverwriteRequestControlLock en un valor de un solo byte de 0x00 (que indica el desbloqueo) antes de la fase de selección de dispositivos de arranque (BDS) (DRIVER###, SYSPREP###, BOOT##, *RECOVERY*, ...). Para MemoryOverwriteRequestControlLock (y MemoryOverwriteRequestControl), el BIOS impedirá la eliminación de la variable y los atributos deben anclarse a NV+BS+RT.

Cuando se llama por primera vez a SetVariable para MemoryOverwriteRequestControlLock pasando un valor válido distinto de cero en Datos, el modo de acceso para y MemoryOverwriteRequestControlLockMemoryOverwriteRequestControl se cambia a solo lectura, lo que indica que están bloqueados.

Las implementaciones de la revisión 1 solo aceptan un solo byte de 0x00 o 0x01 para MemoryOverwriteRequestControlLock.

La revisión 2 acepta además un valor de 8 bytes que representa una clave secreta compartida. Si se especifica cualquier otro valor en SetVariable, se produce un error en la llamada con el estado EFI_INVALID_PARAMETER. Para generar esa clave, use un origen de entropía de alta calidad, como el módulo de plataforma segura o el generador de números aleatorios de hardware.

Después de establecer una clave, tanto el autor de la llamada como el firmware deben guardar copias de esta clave en una ubicación protegida con confidencialidad, como SMRAM en IA32/X64 o un procesador de servicios con almacenamiento protegido.

Obtención del estado del sistema

En la revisión 2, cuando las MemoryOverwriteRequestControlLock variables y MemoryOverwriteRequestControl están bloqueadas, las invocaciones de SetVariable (para esas variables) se comprueban primero con la clave registrada mediante un algoritmo de tiempo constante. Si ambas claves están presentes y coinciden, las variables vuelven a pasar a un estado desbloqueado. Después de este primer intento o si no hay ninguna clave registrada, los intentos posteriores de establecer esta variable producen un error con EFI_ACCESS_DENIED para evitar ataques por fuerza bruta. En ese caso, el reinicio del sistema será la única manera de desbloquear las variables.

El sistema operativo detecta la presencia de MemoryOverwriteRequestControlLock y su estado llamando a GetVariable. A continuación, el sistema puede bloquear el valor actual de MemoryOverwriteRequestControl estableciendo el MemoryOverwriteRequestControlLock valor en 0x1. Como alternativa, puede especificar una clave para habilitar el desbloqueo en el futuro después de que los datos secretos se purguen de forma segura de la memoria.

Llamar a GetVariable para MemoryOverwriteRequestControlLock devuelve 0x0, 0x1 o 0x2 para indicar desbloqueado, bloqueado sin clave o bloqueado con estados de clave.

La configuración MemoryOverwriteRequestControlLock no se confirma en flash (solo cambia el estado de bloqueo interno). Obtener la variable devuelve el estado interno y nunca expone la clave.

Ejemplo de uso por parte del sistema operativo:

if (gSecretsInMemory)
{
    char data = 0x11;
    SetVariable(MemoryOverwriteRequestControl, sizeof(data), &data);
}

// check presence
status = GetVariable(MemoryOverwriteRequestControlLock, &value);  

if (SUCCESS(status))
{
    // first attempt to lock and establish a key
    // note both MOR and MorLock are locked if successful

    GetRNG(8, keyPtr);
    status = SetVariable(MemoryOverwriteRequestControlLock, 8, keyPtr);

    if (status != EFI_SUCCESS)
    {
        // fallback to revision 1 behavior
        char data = 0x01;
        status = SetVariable(MemoryOverwriteRequestControlLock, 1, &data);
        if (status != EFI_SUCCESS) { // log error, warn user }
    }
}
else
{
    // warn user about potentially unsafe system
}

// put secrets in memory

// … time passes …

// remove secrets from memory, flush caches

SetVariable(MemoryOverwriteRequestControlLock, 8, keyPtr);

Flujo de implementación de MorLock

Estos diagramas de flujo muestran el comportamiento esperado de la implementación:

Inicialización

inicialización de morlock.

Flujo SetVariable

flujo de programación de morlock.

Flujo de estado desbloqueado para SetVariable

flujo desbloqueado de morlock.

Flujo de estado bloqueado para SetVariable

flujo de bloqueo de morlock.

Flow para GetVariable

morlock getvariable.

Consulte también

Requisitos de UEFI que se aplican a todas las ediciones de Windows en plataformas SoC

Especificación de mitigación de ataques de restablecimiento de la plataforma del grupo de trabajo cliente de PC, versión 1.10 (descarga en PDF)

Protección de BitLocker frente a ataques en frío (y otras amenazas)

Un tour beyond BIOS con la compatibilidad con UEFI TPM2 en EDKII

Proteger las credenciales de dominio derivadas con Credential Guard

Especificaciones de UEFI