Apostrophe encoding and XSS in modern browsers

During a bugbounty hunt Sebastian discovered a script-context XSS with the injection point being a string. As you know, all modern browsers like Firefox, Chromium, IE automatically encode the apostroph. However, this issue still remains exploitable.

The XSS

The vulnerable javascript part looked similar to this one:

1
2
3
<script>
var foo = 'bar [INJECTION]';
</script>

The value of a parameter - let’s call it ?foo= - was embedded in a javascript string as it is without decoding it. That means, that you can only exploit this issue by injecting a string like ';+alert(1)+', because all other approaches should fail. (If you know a cool bypass, please let us know :)) If you want to play around with an example take a look at our challenge. Sebastian wrote a small webserver in python which simulates the situation.

The problem

Most modern browsers (afaik FF, Chrome, IE, but not Safari) encode the apostrophe automatically due to security reasons. This bugs usually bughunter, because an application seems to be secure (to the vendor), but in real it’s still exploitable in some browsers.

You can easily check if you’re browser does automatically encode the apostrophe with the following two steps (in the console):

  • Run nc -l -p 1337 first
  • Connect to http://localhost:133/?foo=bar'
1
2
3
4
5
6
7
8
> nc -l -p 1337
GET /?foo=bar%27 HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

As you can see, the apostrophe changed from ' to %27. ( int(0x27) = 39 = apostrophe’s position in ASCII table)

The RFC 1738 states that the apostrophe doesn’t need to be encoded by default, because it isn’t a reserved URL-character.

Thus, only alphanumerics, the special characters “$-_.+!*’(),”, and
reserved characters used for their reserved purposes may be used
unencoded within a URL.

Taking a look at this bugreport @ Mozilla the developers argued that this “feature” would add another layer of security by preventing “apostroph”-based XSS attacks.

Next time you come across a XSS like this and the webapplication does not automatically decode the apostrophe for you, don’t forget that there might be other browsers in which the issue remains exploitable.

The List

We thought it’d be a nice idea to make a comprehensive list about which browsers do (not) encode the apostroph automatically.

If you know/discover any other browsers, please send a small tweet @internetwache and we’ll update the list :)

Encoding

  • Chrome/ium
  • IE (>=11)
  • Firefox
  • Opera

Not encoding

  • Arora
  • Dillo
  • Curl
  • Konqueror
  • Luakit
  • Midori
  • Safari

Happy hacking,

the team of internetwache.org