From f0aecb06d9c01f9f91e96eb83fba817ba26551e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= Date: Wed, 21 Dec 2022 05:37:03 +0100 Subject: [PATCH] SEBWIN-633: Fixed ease of access exploit. --- .../ClientControllerTests.cs | 4 + SafeExamBrowser.Client/ClientController.cs | 48 ++++++++ SafeExamBrowser.Client/CompositionRoot.cs | 3 + SafeExamBrowser.I18n.Contracts/TextKey.cs | 6 +- SafeExamBrowser.I18n/Data/de.xml | 16 ++- SafeExamBrowser.I18n/Data/en.xml | 16 ++- SafeExamBrowser.I18n/Data/fr.xml | 22 +++- SafeExamBrowser.I18n/Data/it.xml | 22 +++- SafeExamBrowser.I18n/Data/zh.xml | 18 ++- SafeExamBrowser.Runtime/CompositionRoot.cs | 5 +- ...on.cs => ApplicationIntegrityOperation.cs} | 4 +- .../Operations/SessionIntegrityOperation.cs | 81 +++++++++++++ .../SafeExamBrowser.Runtime.csproj | 3 +- .../RegistryValueChangedEventHandler.cs | 15 +++ .../Registry/IRegistry.cs | 38 ++++++ .../Registry/RegistryKey.cs | 26 +++++ ...mBrowser.SystemComponents.Contracts.csproj | 3 + .../Registry/Registry.cs | 108 ++++++++++++++++++ .../SafeExamBrowser.SystemComponents.csproj | 1 + 19 files changed, 417 insertions(+), 22 deletions(-) rename SafeExamBrowser.Runtime/Operations/{IntegrityOperation.cs => ApplicationIntegrityOperation.cs} (91%) create mode 100644 SafeExamBrowser.Runtime/Operations/SessionIntegrityOperation.cs create mode 100644 SafeExamBrowser.SystemComponents.Contracts/Registry/Events/RegistryValueChangedEventHandler.cs create mode 100644 SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs create mode 100644 SafeExamBrowser.SystemComponents.Contracts/Registry/RegistryKey.cs create mode 100644 SafeExamBrowser.SystemComponents/Registry/Registry.cs diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs index f4c2be3b..17daad68 100644 --- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs +++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs @@ -33,6 +33,7 @@ using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Contracts.Data; using SafeExamBrowser.Settings; using SafeExamBrowser.Settings.Monitoring; +using SafeExamBrowser.SystemComponents.Contracts.Registry; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; @@ -60,6 +61,7 @@ namespace SafeExamBrowser.Client.UnitTests private Mock logger; private Mock messageBox; private Mock operationSequence; + private Mock registry; private Mock runtimeProxy; private Mock server; private Guid sessionId; @@ -92,6 +94,7 @@ namespace SafeExamBrowser.Client.UnitTests logger = new Mock(); messageBox = new Mock(); operationSequence = new Mock(); + registry = new Mock(); runtimeProxy = new Mock(); server = new Mock(); sessionId = Guid.NewGuid(); @@ -119,6 +122,7 @@ namespace SafeExamBrowser.Client.UnitTests logger.Object, messageBox.Object, operationSequence.Object, + registry.Object, runtimeProxy.Object, shutdown.Object, splashScreen.Object, diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index d4128b72..052f6075 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -33,6 +33,7 @@ using SafeExamBrowser.Monitoring.Contracts.System; using SafeExamBrowser.Server.Contracts; using SafeExamBrowser.Server.Contracts.Data; using SafeExamBrowser.Settings; +using SafeExamBrowser.SystemComponents.Contracts.Registry; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; @@ -55,6 +56,7 @@ namespace SafeExamBrowser.Client private readonly ILogger logger; private readonly IMessageBox messageBox; private readonly IOperationSequence operations; + private readonly IRegistry registry; private readonly IRuntimeProxy runtime; private readonly Action shutdown; private readonly ISplashScreen splashScreen; @@ -83,6 +85,7 @@ namespace SafeExamBrowser.Client ILogger logger, IMessageBox messageBox, IOperationSequence operations, + IRegistry registry, IRuntimeProxy runtime, Action shutdown, ISplashScreen splashScreen, @@ -101,6 +104,7 @@ namespace SafeExamBrowser.Client this.logger = logger; this.messageBox = messageBox; this.operations = operations; + this.registry = registry; this.runtime = runtime; this.shutdown = shutdown; this.splashScreen = splashScreen; @@ -167,6 +171,7 @@ namespace SafeExamBrowser.Client CloseShell(); DeregisterEvents(); UpdateSessionIntegrity(); + TerminateIntegrityVerification(); var success = operations.TryRevert() == OperationResult.Success; @@ -206,6 +211,7 @@ namespace SafeExamBrowser.Client ClientHost.ServerFailureActionRequested += ClientHost_ServerFailureActionRequested; ClientHost.Shutdown += ClientHost_Shutdown; displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged; + registry.ValueChanged += Registry_ValueChanged; runtime.ConnectionLost += Runtime_ConnectionLost; systemMonitor.SessionSwitched += SystemMonitor_SessionSwitched; taskbar.LoseFocusRequested += Taskbar_LoseFocusRequested; @@ -240,6 +246,7 @@ namespace SafeExamBrowser.Client applicationMonitor.ExplorerStarted -= ApplicationMonitor_ExplorerStarted; applicationMonitor.TerminationFailed -= ApplicationMonitor_TerminationFailed; displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged; + registry.ValueChanged -= Registry_ValueChanged; runtime.ConnectionLost -= Runtime_ConnectionLost; systemMonitor.SessionSwitched -= SystemMonitor_SessionSwitched; taskbar.QuitButtonClicked -= Shell_QuitButtonClicked; @@ -351,6 +358,8 @@ namespace SafeExamBrowser.Client }; timer.Interval = TEN_MINUTES + (new Random().NextDouble() * FIVE_MINUTES); timer.Start(); + + registry.StartMonitoring(RegistryKey.MachineHive.EaseOfAccess_Key, RegistryKey.MachineHive.EaseOfAccess_Name); } private void VerifySessionIntegrity() @@ -394,6 +403,11 @@ namespace SafeExamBrowser.Client } } + private void TerminateIntegrityVerification() + { + registry.StopMonitoring(); + } + private void ApplicationMonitor_ExplorerStarted() { logger.Info("Trying to terminate Windows explorer..."); @@ -681,6 +695,40 @@ namespace SafeExamBrowser.Client splashScreen.UpdateStatus(status, true); } + private void Registry_ValueChanged(object oldValue, object newValue) + { + logger.Warn($"The ease of access registry value has changed from '{oldValue}' to '{newValue}'! Attempting to show lock screen..."); + + if (!sessionLocked) + { + var message = text.Get(TextKey.LockScreen_EaseOfAccessMessage); + var title = text.Get(TextKey.LockScreen_Title); + var continueOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_EaseOfAccessContinueOption) }; + var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_EaseOfAccessTerminateOption) }; + + sessionLocked = true; + registry.StopMonitoring(); + + var result = ShowLockScreen(message, title, new[] { continueOption, terminateOption }); + + if (result.OptionId == continueOption.Id) + { + logger.Info("The session will be allowed to resume as requested by the user..."); + } + else if (result.OptionId == terminateOption.Id) + { + logger.Info("Attempting to shutdown as requested by the user..."); + TryRequestShutdown(); + } + + sessionLocked = false; + } + else + { + logger.Info("Lock screen is already active."); + } + } + private void Runtime_ConnectionLost() { logger.Error("Lost connection to the runtime!"); diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 944eb6bf..c4cc26ba 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -45,6 +45,7 @@ using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; using SafeExamBrowser.SystemComponents.Keyboard; using SafeExamBrowser.SystemComponents.Network; using SafeExamBrowser.SystemComponents.PowerSupply; +using SafeExamBrowser.SystemComponents.Registry; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; @@ -113,6 +114,7 @@ namespace SafeExamBrowser.Client var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); var fileSystemDialog = BuildFileSystemDialog(); var hashAlgorithm = new HashAlgorithm(); + var registry = new Registry(ModuleLogger(nameof(Registry))); var splashScreen = uiFactory.CreateSplashScreen(); var systemMonitor = new SystemMonitor(ModuleLogger(nameof(SystemMonitor))); @@ -149,6 +151,7 @@ namespace SafeExamBrowser.Client logger, messageBox, sequence, + registry, runtimeProxy, shutdown, splashScreen, diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index 82a2cc24..b45a251b 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -65,8 +65,11 @@ namespace SafeExamBrowser.I18n.Contracts LockScreen_ApplicationsMessage, LockScreen_ApplicationsTerminateOption, LockScreen_DisplayConfigurationContinueOption, - LockScreen_DisplayConfigurationTerminateOption, LockScreen_DisplayConfigurationMessage, + LockScreen_DisplayConfigurationTerminateOption, + LockScreen_EaseOfAccessContinueOption, + LockScreen_EaseOfAccessMessage, + LockScreen_EaseOfAccessTerminateOption, LockScreen_SessionIntegrityMessage, LockScreen_Title, LockScreen_UnlockButton, @@ -197,6 +200,7 @@ namespace SafeExamBrowser.I18n.Contracts OperationStatus_ValidateRemoteSessionPolicy, OperationStatus_ValidateVirtualMachinePolicy, OperationStatus_VerifyApplicationIntegrity, + OperationStatus_VerifySessionIntegrity, OperationStatus_WaitDisclaimerConfirmation, OperationStatus_WaitExplorerStartup, OperationStatus_WaitExplorerTermination, diff --git a/SafeExamBrowser.I18n/Data/de.xml b/SafeExamBrowser.I18n/Data/de.xml index 1f8457dd..2e56014f 100644 --- a/SafeExamBrowser.I18n/Data/de.xml +++ b/SafeExamBrowser.I18n/Data/de.xml @@ -153,11 +153,20 @@ Bildschirm-Konfiguration temporär erlauben. Dies gilt nur für die momentan laufende Sitzung! + + Eine verbotene Bildschirm-Konfiguration wurde detektiert. Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren. + Safe Exam Browser beenden. WARNUNG: Sie werden keine Möglichkeit haben, Daten zu speichern oder weitere Aktionen auszuführen, SEB wird sofort beendet! - - Eine verbotene Bildschirm-Konfiguration wurde detektiert. Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren. + + Barrierefreiheit-Konfiguration temporär erlauben. Dies gilt nur für die momentan laufende Sitzung! + + + Eine verbotene Barrierefreiheit-Konfiguration für den Windows Security Screen wurde detektiert. Bitte wählen Sie eine der verfügbaren Optionen aus und geben Sie das korrekte Passwort ein, um SEB zu entsperren. + + + Safe Exam Browser beenden. WARNUNG: Sie werden keine Möglichkeit haben, Daten zu speichern oder weitere Aktionen auszuführen, SEB wird sofort beendet! Die letzte Sitzung mit der momentan aktiven Konfiguration oder Start-URL wurde nicht ordnungsgemäss beendet! Geben Sie bitte das korrekte Passwort ein, um SEB zu entsperren. @@ -549,6 +558,9 @@ Überprüfe Integrität + + Überprüfe Integrität der Sitzung + Warte auf die Bestätigung des Hinweises zur Fernüberwachung diff --git a/SafeExamBrowser.I18n/Data/en.xml b/SafeExamBrowser.I18n/Data/en.xml index 503c9c18..c4c35e5d 100644 --- a/SafeExamBrowser.I18n/Data/en.xml +++ b/SafeExamBrowser.I18n/Data/en.xml @@ -153,11 +153,20 @@ Temporarily allow the display configuration. This applies only to the currently running session! + + A prohibited display configuration has been detected. In order to unlock SEB, please select one of the available options and enter the correct unlock password. + Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately! - - A prohibited display configuration has been detected. In order to unlock SEB, please select one of the available options and enter the correct unlock password. + + Temporarily allow the ease of access configuration. This applies only to the currently running session! + + + A prohibited ease of access configuration for the Windows Security Screen has been detected. In order to unlock SEB, please select one of the available options and enter the correct unlock password. + + + Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately! The last session with the currently active configuration or start URL was not terminated properly! Please enter the correct password to unlock SEB. @@ -549,6 +558,9 @@ Verifying integrity + + Verifying session integrity + Waiting for confirmation of the disclaimer diff --git a/SafeExamBrowser.I18n/Data/fr.xml b/SafeExamBrowser.I18n/Data/fr.xml index 837e5016..a630e7cd 100644 --- a/SafeExamBrowser.I18n/Data/fr.xml +++ b/SafeExamBrowser.I18n/Data/fr.xml @@ -148,17 +148,26 @@ Les applications sur liste noire énumérées ci-dessous ont été lancées et n’ont pas pu être automatiquement supprimées! Afin de débloquer SEB, veuillez sélectionner l'une des options disponibles et entrer le mot de passe de déblocage. - Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura pas de possibilité de sauvegarder les données ou d'effectuer d'autres actions, l'arrêt sera déclenché immédiatement! + Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement! Autoriser temporairement la configuration de l'affichage. Ceci s'applique uniquement à la session en cours! - - Terminez le navigateur Safe Exam. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder des données ou d'effectuer d'autres actions, l'arrêt sera déclenché immédiatement! - Une configuration d'affichage interdite a été détectée. Pour déverrouiller SEB, veuillez sélectionner l'une des options disponibles et saisir le mot de passe de déverrouillage correct. + + Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement! + + + Autoriser temporairement la configuration de la facilité d'accès. Ceci s'applique uniquement à la session en cours! + + + Une configuration de facilité d'accès interdite pour l'écran de sécurité de Windows a été détectée. Afin de déverrouiller le SEB, veuillez sélectionner l'une des options disponibles et saisir le mot de passe de déverrouillage correct. + + + Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement! + La dernière session avec la configuration ou l'URL de démarrage actuellement active n'a pas été terminée correctement! Afin de déverrouiller SEB, veuillez entrer le mot de passe de déverrouillage correct. @@ -175,7 +184,7 @@ L'utilisateur actif a changé ou l'ordinateur a été verrouillé! Afin de déverrouiller SEB, veuillez sélectionner une des options disponibles et entrer le mot de passe de déverrouillage. - Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura pas de possibilité de sauvegarder les données ou d'effectuer d'autres actions, l'arrêt sera déclenché immédiatement! + Terminer Safe Exam Browser. AVERTISSEMENT: Il n'y aura aucune possibilité de sauvegarder les données ou d'effectuer d'autres actions, la fermeture sera initiée immédiatement! Toujours au premier plan @@ -549,6 +558,9 @@ Vérification de l'intégrité + + Vérification de l'intégrité de la session + En attente de confirmation de la clause de non-responsabilité diff --git a/SafeExamBrowser.I18n/Data/it.xml b/SafeExamBrowser.I18n/Data/it.xml index af7ded6c..c916323b 100644 --- a/SafeExamBrowser.I18n/Data/it.xml +++ b/SafeExamBrowser.I18n/Data/it.xml @@ -148,17 +148,26 @@ Le applicazioni nella lista nera elencate di seguito sono state avviate e non è stato possibile terminare automaticamente! Per sbloccare SEB, seleziona una delle opzioni disponibili e inserisci la password di sblocco corretta. - Chiudi Safe Exam Browser. ATTENZIONE: non ci sarà la possibilità di salvare dati o eseguire ulteriori azioni, lo spegnimento verrà avviato immediatamente! + Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente! Consenti temporaneamente la configurazione del display. Questo vale solo per la sessione attualmente in esecuzione! - - Termina Browser esame sicuro. ATTENZIONE: non sarà possibile salvare i dati o eseguire ulteriori azioni, lo spegnimento verrà avviato immediatamente! - È stata rilevata una configurazione di visualizzazione vietata. Per sbloccare SEB, seleziona una delle opzioni disponibili e inserisci la password di sblocco corretta. + + Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente! + + + Consente temporaneamente la configurazione della facilità di accesso. Questo vale solo per la sessione in corso! + + + È stata rilevata una configurazione di facilità di accesso non consentita per la schermata di sicurezza di Windows. Per sbloccare SEB, seleziona una delle opzioni disponibili e inserisci la password di sblocco corretta. + + + Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente! + L'ultima sessione con la configurazione o l'URL di avvio attualmente attiva non è stata terminata correttamente! Per sbloccare SEB, inserisci la password di sblocco corretta. @@ -175,7 +184,7 @@ L'utente attivo è cambiato o il computer è stato bloccato! Per sbloccare SEB, seleziona una delle opzioni disponibili e inserisci la password di sblocco corretta. - Chiudi Safe Exam Browser. ATTENZIONE: non ci sarà la possibilità di salvare dati o eseguire ulteriori azioni, lo spegnimento verrà avviato immediatamente! + Terminare Safe Exam Browser. ATTENZIONE: Non sarà possibile salvare i dati o eseguire ulteriori azioni, la chiusura verrà avviata immediatamente! Sempre in cima @@ -549,6 +558,9 @@ Verifica dell'integrità + + Verifica dell'integrità della sessione + In attesa di conferma del disclaimer diff --git a/SafeExamBrowser.I18n/Data/zh.xml b/SafeExamBrowser.I18n/Data/zh.xml index 364cc5c1..72cec036 100644 --- a/SafeExamBrowser.I18n/Data/zh.xml +++ b/SafeExamBrowser.I18n/Data/zh.xml @@ -1,7 +1,7 @@ - 此应用程序受Mozilla Public License, 版本 2.0 的条款约束。汉化人:272881521@qq.com。防作弊考试专用浏览器使用以下框架和第三方知识库: + 此应用程序受Mozilla Public License, 版本 2.0 的条款约束。防作弊考试专用浏览器使用以下框架和第三方知识库: 版本 & 许可证信息 @@ -138,11 +138,20 @@ 暂时允许显示配置。 这仅适用于当前正在运行的会话! + + 检测到禁止的显示配置。 要解锁 SEB,请选择可用选项之一并输入正确的解锁密码。 + 终止安全考试浏览器。 警告:将无法保存数据或执行任何进一步操作,将立即启动关机! - - 检测到禁止的显示配置。 要解锁 SEB,请选择可用选项之一并输入正确的解锁密码。 + + 暂时允许轻松访问的配置。这只适用于当前运行的会话! + + + 检测到一个被禁止的Windows安全屏幕的访问方便配置。为了解锁SEB,请选择一个可用的选项并输入正确的解锁密码。 + + + 终止安全考试浏览器。警告:将没有可能保存数据或执行任何进一步的行动,关闭将立即启动! 当前激活的配置或启动URL的最后一个会话没有被正确终止! 请输入正确的密码以解锁SEB。 @@ -504,6 +513,9 @@ 验证完整性 + + 验证会话的完整性 + 等待确认免责声明 diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index ffb272d3..dff10cd2 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -32,6 +32,7 @@ using SafeExamBrowser.Server; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.SystemComponents; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Registry; using SafeExamBrowser.UserInterface.Desktop; using SafeExamBrowser.WindowsApi; @@ -73,6 +74,7 @@ namespace SafeExamBrowser.Runtime var messageBox = new MessageBoxFactory(text); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), ModuleLogger(nameof(ProxyFactory))); + var registry = new Registry(ModuleLogger(nameof(Registry))); var remoteSessionDetector = new RemoteSessionDetector(ModuleLogger(nameof(RemoteSessionDetector))); var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, new HostObjectFactory(), ModuleLogger(nameof(RuntimeHost)), FIVE_SECONDS); var runtimeWindow = uiFactory.CreateRuntimeWindow(appConfig); @@ -87,13 +89,14 @@ namespace SafeExamBrowser.Runtime bootstrapOperations.Enqueue(new I18nOperation(logger, text)); bootstrapOperations.Enqueue(new CommunicationHostOperation(runtimeHost, logger)); - bootstrapOperations.Enqueue(new IntegrityOperation(integrityModule, logger)); + bootstrapOperations.Enqueue(new ApplicationIntegrityOperation(integrityModule, logger)); sessionOperations.Enqueue(new SessionInitializationOperation(configuration, fileSystem, logger, runtimeHost, sessionContext)); sessionOperations.Enqueue(new ConfigurationOperation(args, configuration, new FileSystem(), new HashAlgorithm(), logger, sessionContext)); sessionOperations.Enqueue(new ServerOperation(args, configuration, fileSystem, logger, sessionContext, server)); sessionOperations.Enqueue(new DisclaimerOperation(logger, sessionContext)); sessionOperations.Enqueue(new RemoteSessionOperation(remoteSessionDetector, logger, sessionContext)); + sessionOperations.Enqueue(new SessionIntegrityOperation(logger, registry, sessionContext)); sessionOperations.Enqueue(new VirtualMachineOperation(vmDetector, logger, sessionContext)); sessionOperations.Enqueue(new DisplayMonitorOperation(displayMonitor, logger, sessionContext, text)); sessionOperations.Enqueue(new ServiceOperation(logger, runtimeHost, serviceProxy, sessionContext, THIRTY_SECONDS, userInfo)); diff --git a/SafeExamBrowser.Runtime/Operations/IntegrityOperation.cs b/SafeExamBrowser.Runtime/Operations/ApplicationIntegrityOperation.cs similarity index 91% rename from SafeExamBrowser.Runtime/Operations/IntegrityOperation.cs rename to SafeExamBrowser.Runtime/Operations/ApplicationIntegrityOperation.cs index f5583308..bd77fd18 100644 --- a/SafeExamBrowser.Runtime/Operations/IntegrityOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ApplicationIntegrityOperation.cs @@ -14,7 +14,7 @@ using SafeExamBrowser.Logging.Contracts; namespace SafeExamBrowser.Runtime.Operations { - internal class IntegrityOperation : IOperation + internal class ApplicationIntegrityOperation : IOperation { private readonly IIntegrityModule module; private readonly ILogger logger; @@ -22,7 +22,7 @@ namespace SafeExamBrowser.Runtime.Operations public event ActionRequiredEventHandler ActionRequired { add { } remove { } } public event StatusChangedEventHandler StatusChanged; - public IntegrityOperation(IIntegrityModule module, ILogger logger) + public ApplicationIntegrityOperation(IIntegrityModule module, ILogger logger) { this.module = module; this.logger = logger; diff --git a/SafeExamBrowser.Runtime/Operations/SessionIntegrityOperation.cs b/SafeExamBrowser.Runtime/Operations/SessionIntegrityOperation.cs new file mode 100644 index 00000000..455ce0d7 --- /dev/null +++ b/SafeExamBrowser.Runtime/Operations/SessionIntegrityOperation.cs @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Core.Contracts.OperationModel; +using SafeExamBrowser.Core.Contracts.OperationModel.Events; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Registry; + +namespace SafeExamBrowser.Runtime.Operations +{ + internal class SessionIntegrityOperation : SessionOperation + { + private readonly ILogger logger; + private readonly IRegistry registry; + + public override event ActionRequiredEventHandler ActionRequired { add { } remove { } } + public override event StatusChangedEventHandler StatusChanged; + + public SessionIntegrityOperation(ILogger logger, IRegistry registry, SessionContext context) : base(context) + { + this.logger = logger; + this.registry = registry; + } + + public override OperationResult Perform() + { + StatusChanged?.Invoke(TextKey.OperationStatus_VerifySessionIntegrity); + + return VerifyEaseOfAccessConfiguration(); + } + + public override OperationResult Repeat() + { + StatusChanged?.Invoke(TextKey.OperationStatus_VerifySessionIntegrity); + + return VerifyEaseOfAccessConfiguration(); + } + + public override OperationResult Revert() + { + return OperationResult.Success; + } + + private OperationResult VerifyEaseOfAccessConfiguration() + { + var result = OperationResult.Failed; + + logger.Info($"Attempting to verify ease of access configuration..."); + + if (registry.TryRead(RegistryKey.MachineHive.EaseOfAccess_Key, RegistryKey.MachineHive.EaseOfAccess_Name, out var value)) + { + if (value == default || (value is string s && string.IsNullOrWhiteSpace(s))) + { + result = OperationResult.Success; + logger.Info("Ease of access configuration successfully verified."); + } + else if (!Context.Next.Settings.Service.IgnoreService) + { + result = OperationResult.Success; + logger.Info($"Ease of access configuration is compromised ('{value}'), but service will be active in the next session."); + } + else + { + logger.Warn($"Ease of access configuration is compromised: '{value}'! Aborting session initialization..."); + } + } + else + { + logger.Error("Failed to verify ease of access configuration!"); + } + + return result; + } + } +} diff --git a/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj b/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj index 62f83b3c..fd64ff32 100644 --- a/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj +++ b/SafeExamBrowser.Runtime/SafeExamBrowser.Runtime.csproj @@ -106,13 +106,14 @@ - + + diff --git a/SafeExamBrowser.SystemComponents.Contracts/Registry/Events/RegistryValueChangedEventHandler.cs b/SafeExamBrowser.SystemComponents.Contracts/Registry/Events/RegistryValueChangedEventHandler.cs new file mode 100644 index 00000000..738a3eaa --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Registry/Events/RegistryValueChangedEventHandler.cs @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.SystemComponents.Contracts.Registry.Events +{ + /// + /// Indicates that a registry value has changed. + /// + public delegate void RegistryValueChangedEventHandler(object oldValue, object newValue); +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs b/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs new file mode 100644 index 00000000..674de19f --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.SystemComponents.Contracts.Registry.Events; + +namespace SafeExamBrowser.SystemComponents.Contracts.Registry +{ + /// + /// Provides functionality related to the Windows registry. + /// + public interface IRegistry + { + /// + /// Fired when a registry value previously registred via has changed. + /// + event RegistryValueChangedEventHandler ValueChanged; + + /// + /// Starts monitoring the specified registry value. + /// + void StartMonitoring(string key, string name); + + /// + /// Stops the monitoring of all previously registered registry values. + /// + void StopMonitoring(); + + /// + /// Attempts to read the value of the given name under the specified registry key. + /// + bool TryRead(string key, string name, out object value); + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/Registry/RegistryKey.cs b/SafeExamBrowser.SystemComponents.Contracts/Registry/RegistryKey.cs new file mode 100644 index 00000000..a52bb5f5 --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Registry/RegistryKey.cs @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.SystemComponents.Contracts.Registry +{ + /// + /// Defines registry keys and names used in conjunction with . Use the pattern "LogicalGroup_Key" resp. "LogicalGroup_Name" + /// to allow for a better overview over all keys, names and their usage (where applicable). + /// + public static class RegistryKey + { + /// + /// All registry keys and names located in the machine hive. + /// + public static class MachineHive + { + public const string EaseOfAccess_Key = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Utilman.exe"; + public const string EaseOfAccess_Name = "Debugger"; + } + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj index 9087e56b..59dfb14e 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj +++ b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj @@ -57,6 +57,8 @@ + + @@ -76,6 +78,7 @@ + diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs new file mode 100644 index 00000000..bdfae393 --- /dev/null +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; +using System.Collections.Concurrent; +using System.Timers; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Registry; +using SafeExamBrowser.SystemComponents.Contracts.Registry.Events; + +namespace SafeExamBrowser.SystemComponents.Registry +{ + public class Registry : IRegistry + { + private readonly ILogger logger; + private readonly ConcurrentBag<(string key, string name, object value)> values; + + private Timer timer; + + public event RegistryValueChangedEventHandler ValueChanged; + + public Registry(ILogger logger) + { + this.logger = logger; + this.values = new ConcurrentBag<(string key, string name, object value)>(); + } + + public void StartMonitoring(string key, string name) + { + const int ONE_SECOND = 1000; + + if (timer?.Enabled != true) + { + timer = new Timer(ONE_SECOND); + timer.AutoReset = true; + timer.Elapsed += Timer_Elapsed; + timer.Start(); + } + + if (TryRead(key, name, out var value)) + { + values.Add((key, name, value)); + logger.Debug($"Started monitoring value '{name}' from registry key '{key}'. Initial value: '{value}'."); + } + else + { + logger.Error($"Failed to start monitoring value '{name}' from registry key '{key}'!"); + } + } + + public void StopMonitoring() + { + while (!values.IsEmpty) + { + values.TryTake(out _); + } + + if (timer != null) + { + timer.Stop(); + logger.Debug("Stopped monitoring the registry."); + } + } + + public bool TryRead(string key, string name, out object value) + { + var success = true; + + value = default; + + try + { + value = Microsoft.Win32.Registry.GetValue(key, name, default); + } + catch (Exception e) + { + success = false; + logger.Error($"Failed to read value '{name}' from registry key '{key}'!", e); + } + + return success; + } + + private void Timer_Elapsed(object sender, ElapsedEventArgs e) + { + foreach (var item in values) + { + if (TryRead(item.key, item.name, out var value)) + { + if (item.value != value) + { + logger.Debug($"Value '{item.name}' from registry key '{item.key}' has changed from '{item.value}' to '{value}'!"); + ValueChanged?.Invoke(item.value, value); + } + } + else + { + logger.Error($"Failed to monitor value '{item.name}' from registry key '{item.key}'!"); + } + } + } + } +} diff --git a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj index f1619e73..179912cf 100644 --- a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj +++ b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj @@ -97,6 +97,7 @@ +