We have an XSS in a desktop application, what happens next? How can you escalate it to remote code execution? Let's see.
Modern desktop applications are mostly1 based on Chromium. There are three major frameworks:
- Electron: The most popular one.
- Chromium Embedded Framework.
- QtWebEngine: A part of the Qt framework (pronounced like
There also some miscellaneous frameworks like NW.js. I have only seen a single commercial app using this framework and it was six years ago when I was still doing consulting at good ole' Cigital.
There are two kinds of browser-based desktop applications:
- Just displays a website in Electron, e.g., Trello.
- Also interacts with the machine, e.g., Steam.
XSS Happens (lol)
"But I am not gonna have XSS, Parsia." You will, my friend. Even if you do everything right, you might get hit by a framework bypass.
As is tradition, we're gonna review public bugs. That's how I learn.
Razer Comms - CEF
Years ago (probably around 2015), I looked at Razer Comms. Think of it as the precursor to Discord. Razer Comms was a CEF app and I managed to get a few trivial XSS instances there.
I never disclosed them and published a post after it was retired:
Origin XSS to RCE - QtWebEngine
Disclosure: I work for EA and Origin is one of our products.
I have used this bug numerous times. There are a few reasons:
- It's a cool bug.
- It's one of the few public Origin bugs I can talk about.
- I know Origin like the back of my hand (at least I think so).
XSS happened because of an AngularJS sandbox bypass. This is one of those
situations when you can do everything correctly but get hit. We see a typical
But the last section named The Third Bug (RCE) explores
Origin.client.desktopServices API is available. The weapon of choice is
asyncOpenUrl which allows us to pass a scheme (including
file:/// to execute
files), but no parameters.
Overwolf XSS to RCE - CEF
This is a new one by Joel Noguera of SwordBytes Security. You should read it:
I am not gonna go through the blog post, but here's a summary (quoting myself again lol):
Let's focus on the
bridge provides a openUrlInDefaultBrowser(url) which is
similar to what we have seen before. We can open URL/file or execute files
But there's also writeFileContents which allows writing a file to disk. The rest of the path is clear, write a bat file (or an HTA file if you feel fancy) and then execute it with the previous API.
Electron - Not Again!
I have purposefully not talked about Electron in this post. Electron has the
nodeIntegration. I have talked about it a lot.
Even, when it's disabled, RCE happens (this is a great writeup,
btw). With the Electron defaults becoming more secure, we need to start using
the techniques in this blog.
Here's a ton of examples (including two of mine):
What Did We Learn Here Today?
I say almost because I might be missing some but I have never seen desktop apps based on another browser. ↩︎