These days, web is getting bit secure by the help of CSP, which turns XSS into HTML injection (or really nothing). Even if we find XSS in modern web apps without CSP, sometimes we can't make interesting exploit with an XSS.
But what if there is a way to install an app with browser's native UI, by using just an HTML injection?
Progressive Web Apps
PWA is a web app which has responsive UI and offline capability (using Service Worker, Cache API, etc). And this means that it's very close to native app.
But wait, we could do this with Application Cache too right? Well, PWA is installable. With the use of Web App Manifest.
Progressive Web Attack
Web App Manifest is really special. It has ability to trigger PWA installation prompt with Browser's UI. Simply just with link tag, pointing to manifest file which can be served from cross-origin (with any MIME type) 😆
Let see how we can abuse this feature!
Suppose Victim site has offline capability, and there is an XSS in webpage which is inside the scope of Service Worker. But Victim site uses a production-quality strict CSP.
And here is how to trigger installation prompt.
First, make sure to access main page so that Service Worker is registered. And then, If you access above url with Chrome on Android, you should see below.
Sorry, my phone is Japanese, but clicking on "Add" button will download contents and create home icon in your phone. If you open the app, you will see below page.
This page simply frames attacker page. Since start page of the app is controlled by Attacker's manifest and app only has navigation capability provided by attacker (no address bar and no back or forward button), user is totally controlled by attacker. And goodbye to Victim site, user will use the app from now on!
This is all done by just an HTML injection 😆
BTW, I feel that installation prompt provided by browser isn't very good. It only shows Domain when prompting user. So any website which allows uploading user contents to subdomain (such as Shopify) might be used for phishing attack.
Anyways, there are some limitation of this technique.
- Link tag which points to manifest needs to be inside head tag.
- start_url needs to be on same-origin as the Victim site's origin.
- Navigating top document to cross-origin site would trigger address bar to show up even inside an app.
Last but not least, I think manifest should only be accepted when served from same origin. Specification needs to be more carefully thought (and should be changed, hopefully).
To protect against this kind of attack, make sure to set CSP manifest-src to 'none' if you don't use PWA (and AppCache) or any appropriate source if you use it.
Hope you enjoyed it!