Unquoted Service Path Privilege Escalation in Razer Cortex - $750 USD

An unquoted search path in the Razer Cortex service (RzKLService.exe) lets a local attacker run code as SYSTEM.

Introduction

Razer Cortex Service version 7.3.23.124 ships with an unquoted service path. This is a classic Windows privilege escalation: a service running as SYSTEM launches a binary from a path containing spaces, without wrapping it in quotes. A local user who can write to the right directory can get their own binary executed with SYSTEM privileges.

Discovery

By default, RzKLService.exe runs as a system service and launches RazerCortex.exe. The path it uses is not quoted, which makes it vulnerable to search path hijacking.

The Problem

RzKLService.exe executes RazerCortex.exe with administrator privileges, but the path is passed without quotation marks. Because of how Windows parses an unquoted path with spaces, the following locations become candidate binaries:

C:\Program.exe and C:\Program Files (x86)\Razer\Razer.exe

An attacker who can write to one of these locations plants a malicious binary there and waits for the service to run it with administrator privileges.

Vulnerable Code

Looking at the decompiled RzKLService.exe, the RazerCortex.exe path is concatenated with the -systray argument without any surrounding quotes:

  print_log((int)L"Run main processex[0] %s %s", path_ptr, v33);
  sub_402FA0((void **)&v34, L"RazerCortex.exe");
  LOBYTE(v37) = 10;
  cancat((int)&path_ptr, (int)L" %s", v33);

Root Cause

RzKLService.exe executes RazerCortex.exe with -systray appended to its path. Because the path is not quoted, Windows interprets "C:\Program Files (x86)\Razer\Razer Cortex\RazerCortex.exe -systray" by splitting on spaces and trying each prefix in turn (C:\Program.exe, C:\Program Files (x86)\Razer\Razer.exe, and so on) before reaching the intended executable. If an attacker-controlled binary exists at one of those earlier paths, it runs instead.

Fix

The fix is to quote the path to RazerCortex.exe so Windows treats it as a single argument. In the string concatenation that builds the command line, wrap the path in escaped quotes:

cancat((int)&path_ptr, (int)L"\"%s\" %s", v33);

With the path quoted, spaces in the directory structure are no longer interpreted as argument separators, and the search path hijack is closed.

Reporting

I reported the finding on HackerOne. In the report I referenced a similar issue, Safebreach-Windows-Unquoted-Search-Path-CVE-2019-16647, as prior art. The bounty was $750 USD.