Unrelated prehistory: Few weeks ago I was trying to XSS m.facebook.com location.hash validation with a timing attack.
(/^#~?!(?:\/?[\w\.-])+\/?(?:\?|$)/).test(location.hash)&&location.replace(...
I was trying to craft *long enough* regexp argument so I could get a spare second to replace the location.hash just before location.replace happens.
I'm no browser expert and don't comprehend how it works on low level - it didn't work out anyway, because it is single-threaded (with setTimeout timing attack works fine - try to XSS this page.)
The side-research is more interesting!
pic unrelated. |
When I was testing FF i did notice, for huge payloads JS simply returns "false". For "/a/a..N times" it still was true but for N+1 times all of a sudden - false
Yeah, JS was like saying "TL;DR, hopefully it's false".
Wait, what?! Regexp can't just return a wrong result only because of the argument's length! Let's double check:
In Chrome
z=Array(999999).join('a');
console.log(/^([\w])+$/.test(z),z.length);
//true 999998
z=Array(999999+1).join('a');
console.log(/^([\w])+$/.test(z),z.length);
//true 999999
In FF
z=Array(999999).join('a');
console.log(/^([\w])+$/.test(z),z.length);
//true 999998
z=Array(999999+1).join('a');
console.log(/^([\w])+$/.test(z),z.length);
//false 999999
Apparently, thing is, after catching 999 998 regexp ([\w]) groups FF "gets tired" and returns false instead of finishing the work or raising an exception like Chrome does (RangeError: Maximum call stack size exceeded).
To turn it into an exploitable vulnerability you would need a JS regexp leading to something bad in "false" case - totally unlikely. But good place to start FF regexp "quirks" investigation.
P.S. Please fix me if I did not correctly understand the issue.