How we exploited a code execution vulnerability in math.js
capacitorset.github.io
capacitorset.github.io
>If, anyway, you want to make math.eval resistant against arbitrary code execution, I think it would be best to have a whitelist of methods and constructs (i.e. you parse the code that is meant to be evaluated and ensure that every construct is allowed). I analyze JS malware in my free time (see [box-js](https://github.com/CapacitorSet/box-js)), and I found that it is virtually impossible to blacklist functions. For instance, if the parser forbids `[].map.constructor`, I could very well use `[].map["constructor"]`; and if you blacklist the word "constructor", I could use `[].map["rotcurtsnoc".split("").reverse().join("")]`, and so on, there's an infinity of methods one can come up with to avoid blacklists.
The examples didn't really work in math.js, but it turns out that there's still [quite a few ways to get around it](https://github.com/josdejong/mathjs/issues/821).
However, the trick is to make Javascript execute Function, through a function that math.js won't mind executing. What I found was simply using Function.apply and Function.call; the author found Function.bind, and someone in this thread found several more.
I'm curious why he didn't go down the whitelisting path in the first place. Basic maths don't require that many functions anyway, so he could've started with a small list, and expanded it as people asked for more. Alternatively he could have allowed for custom whitelists.
A first approach was to try to put security checks right before executing any function. That didn't work out since the parser doesn't have control over all function executions: for example not over the ones invoked by Array.forEach and Array.map. A second approach was to blacklist the "constructor" property since all issues did go via constructor and managed to call Function that way. That wasn't enough either. Current approach is to guard the values of symbols and properties (the places where unknown stuff can come in) and test whether there value equals Function. To be continued I think...
browsers do have isolated contexts these days, they're just cumbersome to use.
1. spawn an iframe with sandbox="allow-script" and srcdoc="...<meta http-equiv="Content-Security-Policy" ...><script>...</script>..."
2. use window.postMessage to communicate between the parent page and the iframe running in a null origin
3. send code to eval into that iframeAn unmatched left parenthesis creates an unresolved tension that will stay with you all day.
Math.js is available as a RESTful web service: http://api.mathjs.orgI was hoping vm to offer you an isolated v8 interpreter without bindings that could used as a sandbox, but this wasn't the case.