0x01 What is Electron and what's wrong with it?
Electron published a bug fixed version in Jan 22, mentioned there was a remote code execution vulnerability, when the vulnerable desktop applications register their User-Defined protocol, attackers can take advantage of those "protocol", in context like browser execute system command through URL, and completely control the victim's computer. It's a powerful vulnerability due to its payload is easy and simple.
There are lot's of desktop applications written by Electron, there is a list of applications.
If for some reason you are unable to upgrade your Electron version, you can append -- as the last argument when calling app.setAsDefaultProtocolClient, which prevents Chromium from parsing further options. The double dash -- signifies the end of command options, after which only positional parameters are accepted.
app.setAsDefaultProtocolClient(protocol, process.execPath, [ '--your-switches-here', '--' ])
0x02 why this happened?
Applications using Electron framework can use user-defined URL protocol, browser can launch those desktop applications through those "protocols", for example, Slack register the protocol "slack://"
However, this mechanism is supported by Windows, Linux and MacOS, but this vulnerability only occurs on Windows platform. Thus, we can say it's Microsoft's problem.
Before we talk about this vulnerability, we can check MSDN through this Registering an Application to a URI Scheme, in this article, there is a great example:
If we want to register a protocol names
alert: to a application named alert.exe, we will create a register structure in Windows:
HKEY_CLASSES_ROOT alert (Default) = "URL:Alert Protocol" URL Protocol = "" DefaultIcon (Default) = "alert.exe,1" shell open command (Default) = "C:\Program Files\Alert\alert.exe" "%1"
The %1 is placeholder in command line, which means we can send URL through argv to application. The Electron provide a API app.setAsDefaultProtocolClient(protocol[, path, args]) to achieve this function. If alert.exe is not launched, then the operating system will try to open this alert:// through command line:
"C:\Program Files\Alert\alert.exe" "alert:Hello%20World"
Notice: the Internet Explorer will execute a URL decode before execute it as command.
According to this article:
Because Internet Explorer will decode all percent-encoded octets in the URI before passing the resulting string to ShellExecute, URIs such as alert:%3F? will be given to the alert application pluggable protocol handler as alert:??. The handler won't know that the first question mark was percent-encoded. To avoid this issue, pluggable protocol handlers and their associated URI scheme must not rely on encoding. If encoding is necessary, protocol handlers should use another type of encoding that is compatible with URI syntax, such as Base64 encoding. Double percent-encoding is not a good solution either; if the application protocol URI isn't processed by Internet Explorer, it will not be decoded. When Win32 applications try to deal with local file and URL, they will use same Win32 API -- ShellExecute(Ex).
For example, if we want to open a local file named "test.txt"
ShellExecuteW(NULL, L"open", L"c:\\test.txt", NULL, NULL , SW_SHOW );
ShellExecute has problems:
1. The URL can be parsed as local path: it will lead to open local file or even execute files
2. The "" which wrap the %1 in command line can be enclosed.
The article in MSDN also mentioned how to mitigate it:
1. Avoid spaces, quotes, or backslashes in your URI 2. Quote the %1 in the registration ("%1" as written in the 'alert' example registration)
Which means, wen can inject something like:
alert: hello" --OurCommand "hello
Thus, the command line will be:
"C:\Program Files\Alert\alert.exe" "alert: hello" --OurCommand "hello"
Electron is based on Chromium, which means we can execute command through chromium by commands in exploitdb poc --gpu-launcher, but according to command that chromium supported
command like: --renderer-cmd-prefix can trigger RCE too.
In my virtual machine, I use --renderer-cmd-prefix run C:/Program Files/system32/cmd.exe through slack verion 3.3.0
The mitigation (append user input to the --) published by Electron is based on chromium:
There, if someone put --gpu-launcher in the URL, it will parse it as a filename, but not execute it.