- used some onerror handlers to run the code
- tried (unsuccessfully) to beat my function overloading
- used multi-level obfuscation
And all I did was to replace eval('code') with code. To be more specific, that is the actual code:
<img onerror="eval('code;') // ok" src="http://i.dont.exist" /> <img onerror="code; //gives errors" src="http://i.dont.exist" />
Such operation usually has no side effects - after all, eval is meant to immediately evaluate the passed code. But my eval was overloaded (check my previous post to see how I achieved this) and this caused problems. What's even worse - it turned out overloaded eval will not always work as expected and you cannot avoid it!
Eval() is special
The 'original' eval turned out to be a very special function (just like arguments being a very special array) - it has its own execution context and you cannot emulate it with any other function. See the below example:<html> <head> <script type="text/javascript"> var y = 'Klaatu barada nikto'; var eval2 = eval; console.log('in global: ',y,this); </script> <body> <img src="about:blank" onerror="console.log('in event handler:',y,this)"> <img src="about:blank" onerror="eval("console.log('in eval:',y,this)")"> <img src="about:blank" onerror="eval2("console.log('in eval2:',y,this)")"> </body> </html>
Here we define a global variable y and we try to read the value of y from
- global context (<script> element)
- an event handler
- eval() function inside an event handler
- eval2() which is just a reference to 'original' eval (let's call it dummy overload ;))
1st case works as expected (this is window, and global y is accessed), so is the 2nd (this is img, y is local), eval() does not change the scope nor variable visibility. But eval2()suddenly sees our global variable, even though it's in the context of <img>! WTF??
So there is a slight difference between original and overloaded eval() - although the context stays the same (thanks to Function.apply I used in original overloading), variable visibility is different - so one could potentially detect that eval() is overloaded.
We're doomed?
I tried to overcome this using various known techniques (wrapping in anonymous function, playing with scopes etc.) but to no avail. I cannot emulate eval without getting this strange behaviour.Luckily, malware authors are is the same position - they usually obfuscate eval call by using some intermediate function (in other words, there is eval2 = eval equivalent somewhere in their code). But still, I'd rather have a perfect emulation... Is there any?
No comments:
Post a Comment