swoops / eval_villain

A Firefox Web Extension to improve the discovery of DOM XSS.
GNU General Public License v3.0
249 stars 35 forks source link

Direct vs indirect eval #2

Open mikesamuel opened 5 years ago

mikesamuel commented 5 years ago

This is more of an fyi since I have no suggested fix.

applyEvalVillain("eval") turns direct eval into indirect eval

https://github.com/swoops/eval_villain/blob/8c49852dee59d2541dcb4a5cede68b76c0878caf/src/js/switcheroo.js#L385

Since eval !== %eval%, all eval becomes direct eval.

You can see the difference in

const x = 'indirect';
(() => {
  const x = 'direct';
  console.log(`eval(x) => ${ eval('x') }`);  // -> indirect
  console.log(`(0, eval)(x) => ${ (0, eval)('x') }`);  // -> direct
})();

This happens because of step 6.a in 12.3.4.1

  1. If Type(ref) is Reference and IsPropertyReference(ref) is false and GetReferencedName(ref) is "eval", then a. If SameValue(func, %eval%) is true, then

when evaluating function calls where the function is the identifier eval.

swoops commented 5 years ago

I was unaware of this behavior.

This could lead to false positives/negatives or breaking sites. It could also be used to identify when Eval Villain is hooking eval in the page.

Thanks

mikesamuel commented 5 years ago

It could also be used to identify when Eval Villain is hooking eval in the page.

Yeah.

function isEvalHooked() {
  var Object = 0;  // Mask the global.
  return eval('typeof Object') !== 'number';
}

console.log(isEvalHooked());  // -> false
eval = new Proxy(eval, {});
console.log(isEvalHooked());  // -> true