CVE-2018-1000006 Electron User-Defined Protocol Injection

0x01 What is Electron and what's wrong with it?

Electron is an open source library developed by GitHub for building cross-platform desktop applications with HTML, CSS, and JavaScript. Electron accomplishes this by combining Chromium and Node.js into a single runtime and apps can be packaged for Mac, Windows and Linux.

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://"
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

bingo bingo2

0x03 Patches

Here is the Electron's patch link
I'm a rookie in C/C++, but I can find they add a blacklist there.

The mitigation (append user input to the --) published by Electron is based on chromium:
chromium There, if someone put --gpu-launcher in the URL, it will parse it as a filename, but not execute it.