Monday, August 31, 2015

Exploiting XSS (Script Site Scripting) vulnerability when using eval() for JSON parsing

Disclaimer:
This article is just for information purposes and I don't endorse/promote its content or will be responsible for malicious use of the below technique under any circumstance.


Today I carried out a security audit on one of our third party libraries used on our hardware product (which has a JavaScript based UI platform), my instructions were to look for any security vulnerabilities that could compromise the hardware product.

I'm not a security expert but I am pretty well versed with JavaScript so I started to look for the obvious security culprit. i.e. legacy or bad coding which opens the door for XSS (Script Site Scripting).



XSS (Script Site Scripting) is basically the ability to "inject" execution code into a user's scope / session, effectively running remote code in the active user's session.

My discover of a potentially major issue related to a legacy method of using JavaScript eval() to parse JSON.

You are probably asking yourself, why would anyone use eval() to parse a String into JSON when JSON.parse() was baked into the browser specifically for this?

Some possible reasons:
  • JSON.parse() is not supported in many legacy browsers, so the libraries that allow JSON parsing as a polyfill internally used eval(), therefore developers just stick to eval() so make their code run on all browsers.
  • Developers could be unaware of JSON.parse() and are stuck in the old way of doing things.

The downside of using eval() vs JSON.parse() is as follows:
  • JavaScript execution speed: Your JavaScript code runs in a optimised execution environment, once your code is set to execute in the browser the JavaScript engine does a "inspection" prior to executing your code and if it sees potential optimal execution issues (like eval() for example) it puts your code in "slow" execution path (as apposed to the "fast" execution path). This could potential slow your code by around 10X (based on what I've read)
  • Using eval() opens your code to XSS attacks (see below)

Let's have a quick example on how you can conduct an XSS attack when eval() is used.

Most people use AJAX in their applications; and when they get a JSON response from the server they need to parse it into JSON so it can be used locally. Most people use JSON.parse() for this but eval() can also be used.

Look at this simple code example to illustrate this major problem:

// Lets say your get this JSON a response from your AJAX call
var res =  '{"name":"flower","img":"http://her.com/rose.jpg","desc":alert("XSS")}';

// The safe way to convert this to JSON is like so, this will fail as JSON.parse has internal detection of XSS
var safe = JSON.parse(res);

// The dangerous way to do it would be like so
var danger = eval('('+res+')')

When you run this code, the eval() code is executed and expected to be converted to JSON, but because there is a inline JavaScript code block [alert("XSS")] this is executed in the current scope and you will see the alert pop up.

No imagine you replace the simple alert into something malicious like a redirect or an infinite loop (if your goal was to crash the user's device)

So be careful and avoid eval() for JSON parsing!

Happy coding my friends...



Update 02/09/2015
I did more thinking about this and I still don't agree with eval() being used to parse JSON from a String, but in the example code above:


var res =  '{"name":"flower","img":"http://her.com/rose.jpg","desc":alert("XSS")}';

I can see that it would not validate as JSON as the alert("XSS") is not within quotes, i.e it should have been "desc":"alert('XSS')" for it to parse as valid JSON.

So this example of an XSS attack vector using JSON and eval() may not be entirely accurate/valid, unless of course invalid JSON is being pushed out from your server to your client.

But using eval() is still dangerous for this kind of situation, and if this is not of concern then at least knowing that your JavaScript code will execute slower should deter you. i.e. if you use eval() your code could execute a lot slower.


No comments:

Post a Comment

Fork me on GitHub