The core vulnerability here is a case where a DOM clobbering attack could be used to hijack a service worker.
The flow is a complicated, you start off with your web-app loading, on that page is an element, something like:
<div id="cdnDomain" style="display:none">example.com</div>
Also on the page is some javascript (my own examples, not directly from the post)
let cdn = document.getElementById("cdnDomain").innerText
navigator.serviceWorker.register("/sw.js?host=" + cdn)
And then finally in the service work itself would import scripts based off the host
param. So if one could control the cdnDomain
value they could control where the server worker loaded the core of its code from.
The most interesting part of the post comes in a couple discoveries regarding quirks of getElementById
. I’m not sure if these are entirely novel, but often with DOM clobbering attacks you want your DOM element that is doing the clobbering to exist earlier in the DOM than the one being clobbered. this is not always the case though, the author calls out a couple tags that will take precedence even if they occur later in the page: <html>
and <body>
tags. Even if it doesn’t quite make sense for those tags to be present, if injected it seems they will clobber other elements with the same ID. This includes if they are present inside of an <svg>
element.
The username
, from_name
and password
fields of the SMTP server configuration accept new-line characters that will be printed directly into the resulting configuration file. Using this it is possible to include configuration parameters that are not normally exposed. Using this one can set the rendering_args
for the Grafana Image Rendering plugin which through the --renderer-cmd-prefix
argument can result in command injection.
A long chain of issues that leads to XSS in the league of legends (LoL) account subdomain via easyXDM, which is a developer focused JS library that provides an interface for doing cross-origin communication using various protocols. easyXDM consists of a producer-consumer setup, where a producer page exports functions for the consumer page to invoke. In LoL’s case, they exported methods to send requests and responses cross-origin, as well as get and set cookies via the pm.html
page. These are dangerous functionalities of course, so there’s some protections here. The document.referrer
is checked against an allowlist of domains owned by riot games or their partners. On top of that, the message origin reported by easyXDM is also verified against this same list.
Open redirect to bypass referrer check
They managed to bypass the referrer check via an open redirect issue in easyXDM’s FrameElementTransport.js
class, which is used for passing variables using the frameelement
property on gecko browsers. One of the things it allows you to do is set the window top location to this xdm_e
parameter (aka config.remote
). They could force FrameElementTransport
to be used by setting xdm_p
(aka config.protocol
to 5). They abused this via the apollo
consumer, which is an allowlisted consumer.
Bypassing origin check
Now they could get attacker controlled code loaded, but it was still subject to the origin check by easyXDM. The second bug was one in HashTransport
for communicating across iframes via the window location.hash
. It’s a hacky technique which is fundamentally flawed somewhat as it’s impossible for the parent page to know who updated the location.hash
, and so they assume messages came from config.remote
, which can be controlled by an attacker.
This puts the attacker in a catch-22 though. They can set xdm_e
/config.remote
to an attacker domain to get their code loaded, but they’ll fail the origin check. They could set it to an allowed domain to bypass the origin check, but then they forfeit loading attacker code. So they had to revisit their original referrer bypass and rework it a bit. They essentially used HashTransport
again to get their page loaded in a nested iframe under the apollo
consumer and switch the parent location source to the pm.html
page after the fact. This allowed them to send requests to pm.html
, though they couldn’t get responses back.
Bypassing signing/verification + getting XSS easyXDM additionally tries to sign and verify incoming messages to prevent iframes being abused in this way. The problem is, they sign using a secret that’s set by the iframe assuming an attacker doesn’t have control of the second level iframe from the start. So an attacker can simply set their own secret and still gain access to those methods mentioned earlier.
XSS was achieved by using the ability to make XHR requests, and the fact that that jquery would implicitly load a URL as a JSONP call if it ends in =?
(at least until jquery v4). This finally got them XSS in accounts.leagueoflegends.com
.
An email normalization issue allowing for remote control of a vehicle.
Hyundai’s remote control API would use a JWT for authorization, the JWT would contain the user’s email. For the API request to unlock a vehicle, the JWT would be sent in a header, and in the body of the request would take a userName
field containing the same email and the vin
for the target vehicle.
It would check that the userName
(email) matched the email in the JWT and throw and error if not. The vulnerability comes from this comparision, as it would do some normalization, and registration would not require confirming ownership of the email.
So one could register with the email [email protected]%0d
(a carriage return at the end), but in the body of the request use [email protected]
. Due to normalization it would go ahead and treat your JWT as valid to the [email protected]
user name, allowing the attack to control the victims vehicle.