A while ago my colleague Fredrik mentioned that Safari allows special characters in the domain name. He shared this in the Detectify Crowdsource Slack channel and I thought it sounded very interesting, so I decided to look into it.

It should be noted that Safari exists on iOS in addition to OS X, making it one of the most popular browsers out there.

After reading the shared blog post (which since has been translated to English) I went to HackerOne and Bugcrowd, took most programs that offered bounties and threw all the domains into a text file. Manually done, swearing over not saving the list from last time, so could have missed some. All and all about 420 domains.

I then wrote a quick Python function to loop through the domains, saving all the domains with a record for asdf.[domain]. Those can be assumed to support wildcards and I ended up with roughly 80 domains.

def wildcard(d): if subprocess.Popen(["dig", "asdf."+d, "+short"], stdout=subprocess.PIPE).communicate()[0]: return True

Looking through that list it was clear that most just redirected *.[domain] to either [domain] or www.[domain], so let automate this using Python again to narrow our list.

requests.packages.urllib3.disable_warnings() def check(d): try: r = requests.get("http://asdf." + d, verify=False) if re.match("^http(s)*:\/\/(www.)*"+d, r.url): return False except: print "Error: " + d return True

At this time we got little under 50 different domains, few enough to go through them all manually.

Many redirected to a default page (eg., paypal-forward.com always redirects to paypal.com), while others responded with a server error if you placed funny characters in the request. A few actually HTML-encoded the URL. All things considered, I found three different interesting sites.

First unnamed service

This is probably the most straightforward XSS caused by special characters in the domain name.

Similarly to how each company gets their own [company].slack.com, using this service you get your own subdomain. Going to the domain when logged out means a login form is presented, including the subdomain. Looking something like this:

<form action="https://subdomain.chatservice.com" method="post"> <input id="user" autofocus> <input id="pass"> </form>

The first problem that occurs is that we cannot simply insert a script-tag as the injection. While Safari allows some special characters there are ones that are not allowed. In addition to characters that make the domain invalid (such as /), I soon discovered that the service removed some on their own.

I started to read up on all parameters that the form-tag supports and ended up injecting

"onfocusin="alert(1)"d="

(onfocusin is different from onfocus and works fine in a form where a input field is focused).

Now we just have the XSS auditor left to bypass. As this payload only works in Safari, it becomes rather worthless if we cannot also bypass the XSS auditor. Fortunately for us, all we need to do is just remember that the service removes some characters, and change our payload accordingly.

"onfo%0ccusin="alert(1)"d="

Shopify

Shopify was the next target on the list. They had a wildcard on *.shopify .com and *.myshopify.com, both leading to the same page. Looking at the source code and the Safari host thingie in mind it becomes rather clear what we are going to do.

We must begin with tricking the regex check to not understand we are at *.shopify.com. This is easily done by just appending a period to the domain, such as hehehe.shopify.com./

The hostname is then added through jQuery’s ().html. At first I wanted to inject a payload similar to <svg•onload=alert(1)>, but it turns out the server refuses to answer when sending any character I tried to use instead of space (eg., %0c).

Playing around with the ().html function I ended up with the following solution:

http://as<script>eval(location.hash.substring(1));df<!--.sectest42.shopify.com./#alert(document.domain)

This did not result in a bounty because script execution on subdomains of shopify.com and myshopify.com did not result in any additional security risk; Shopify already allows customers to upload files to cdn.shopify.com, and to host arbitrary content on subdomains of myshopify.com.

With that said, they handled the report very well and wanted me to emphasize that they encourage public disclosure of vulnerabilities on their platforms after they have been dealt with. Overall a pleasant experience and we have now covered how this can result in XSS through both classic reflected XSS and by using JavaScript.

Asian based webstore

When using special characters in the subdomain we were greeted by a seemingly standard error that is actually vulnerable to XSS.

However, I never took this any longer than HTML injection. All the payloads got stuck in the XSS auditor, which is no good for a Safari-only vulnerability.

(I actually wrote another script to try all characters from %00 to %FF to confirm no characters are filtered out server side which would have allowed the same bypass as for the first example in this write-up)

A Christmas story of errors, beers and passwords

While playing around with all this I accidentally discovered that the certificate error page in Safari is also vulnerable against this. One of many ways this error can be triggered is on wildcards where the certificate is for *.example.com but the web server supports *.*.example.com. Compare x.slack.com and x.y.slack.com for example.

Another way to trigger this is for every website is if we were to MITM the victim, as we then can redirect all requests to a faulty certificate. The most common way this is done on a small scale is if the attacker and victim use the same wireless network.

At first this looked like a UXSS, but it turns out that Safari changes the origin. An XSS being executed in another context is not much fun.

I played around with this a bit but was unable to make anything fun out of it. Reported it to Apple (CVE-2018-4133) for the sake of it, and then went to take a few beers. This finding happened to coincide with Detectify’s Christmas party, as all interesting findings tend to do.

Another hour or so and an idea struck me making me curious enough to go back to my laptop, Safari Extensions! Sure enough, the browser changed the origin but the tabs API used by extensions remained. Do any password managers blindly trust this?

Safari supports more password managers than I could test, so I took the same approach as before to test the ones with Bug Bounty or Responsible Disclosure and got a way shorter list.

One of the most popular password managers, who asked to not be named here, supports autofill and also just check the location with the tabs API. That means that I could steal the password for any website this Safari error could be triggered on (which is a lot, and given certain circumstances: all). This was not possible to reproduce on iOS due to how they handle extensions. It also served as a great reminder that autofill really should be disabled.

Another password manager, who also asked not to be named here, was also vulnerable against the same thing. However, this one does not support autofill which greatly limits the impact. At best (or worst), this could be used to aid in phishing as it would be possible to control the suggested password but not silently steal anything. They decided to not fix this as they thought the bug was not on their side.

Want to join Linus and other ethical hackers in our Detectify Crowdsource network? Sign up for Crowdsource and help us make the internet a safer place by submitting your findings that will then be built into the Detectify scanner!