Wednesday, April 14, 2010

Beating JavaScript obfuscators with Firebug

Today I encountered a very pleasant 'crackme' challenge from Paweł Goleń. The purpose is to find out what is the purpose of demo page set up by Paweł.

Visiting this page with e.g. Firebug enabled (or with any HTTP proxy) quickly shows that a POST request is sent upon visiting. You didn't submit any form manually so it must be JavaScript sending it. So, you just need to view the source of the page to find the JS code. And this is where the fun starts. The code looks like this:


Obfuscation

Not really readable... This code is obfuscated - modifed to make its analysis difficult. This is the technique widely used with malware software.
The encoded software usually tries to hack into the machine, so it can:
  • download even more code from a remote URL
  • send some data to a remote (attacker) server
  • exploit a browser vulnerability to execute a code on the machine
  • scan the internal network
  • hack into your router and convert it to a spam server
Obfuscating code sometimes prevents the software from being detected by antivirus/malware scans, but it is mainly used to make it harder to determine what the script actually does (and e.g. prepare antivirus signature for it).
In JavaScript obfuscation is usually based on heavy usage of unescape, String.fromCharCode and eval functions.

Luckily, JavaScript itself, with the help of Firebug, has tools that enable you to decode such obfuscated script, so it is only a matter of time to reverse engineer it.

Function overloading

JavaScript is a functional language, so - in plain words - the function itself can be written to variable, passed as an argument etc. And - as a variable - it can be reassigned. So it is possible to change the behaviour of any JavaScript function. Example:

<html><head>
</head>
<body><div id="alert"></div>
<script type="text/javascript">
window.alert = function() { 
  document.getElementById('alert').innerHTML = arguments[0] 
};
alert('hello world');
</script>
</body></html>

Here we overload widely used alert function - instead of a message box it will insert a given message to a <div id="alert"> element. Two things to note:
  • alert is in fact window.alert because JS in browsers has a global object named window
  • arguments is an array-like object containing parameters passed to the function, so in this case it's ['hello world']

Let's decode

Analysing any obfuscated script will be much easier if you overloaded the key functions: unescape, String.fromCharCode and eval. But, for the script to actually work, our overloaded functions must call the original ones:

var oldunescape = window.unescape;
window.unescape = function() {
  var u = oldunescape.apply(this,arguments); // this calls the old function
  console.log('unescape ', arguments, u);
  return u;
}

var oldCharCode = String.fromCharCode;

String.fromCharCode = function() {
  var u = oldCharCode.apply(this,arguments);
  console.log('charcode ', arguments, u);
  return u;
}

var oldeval = window.eval;
window.eval = function() {
  var args = arguments;
  console.log('eval ', arguments, u);
  var u = oldeval.apply(this,arguments);
  debugger; // here the debugger (e.g. Firebug) will kick in 
  return u;
}

With this code you may start decoding the script, consistently replacing obfuscated code in HTML with decoded one coming from Firebug console. You can also insert the debugger; line anywhere in a JS to add a breakpoint.

One thing to note - when debugging malware, be sure to make it in a safe environment (e.g. a separate virtual machine, some sort of sandbox), because otherwise there is a risk you'll become its victim.

We're finished...?

Unfortunately, that's only the first part of analyzing the software. After getting the plaintext version we need to understand what it actually does (and that's usually intentionally hidden in many functions, variables, exceptions, browser differences and strange program flow). It is hard and requires both patience and a bit of JavaScript knowledge, but it is, I think, one of the fastest and most exciting ways to learn. So, go grab your Firebugs and try for yourself - what does this page do?

2 comments:

Anonymous said...

Here's a nice obfuscator ;-)

http://utenti.multimania.it/ascii2hex/

Bn said...

0x4e9d=["\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65","\x77\x72\x69\x74\x65"];document[_0x4e9d[0x1]](String[_0x4e9d[0x0]](0x3c,0x62,0x75,0x74,0x74,0x6f,0x6e,0x20,0x6f,0x6e,0x63,0x6c,0x69,0x63,0x6b,0x3d,0x27,0x6a,0x61,0x76,0x61,0x73,0x63,0x72,0x69,0x70,0x74,0x3a,0x69,0x66,0x20,0x28,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x22,0x70,0x61,0x73,0x73,0x22,0x29,0x2e,0x76,0x61,0x6c,0x75,0x65,0x3d,0x3d,0x22,0x6a,0x30,0x30,0x77,0x31,0x6e,0x22,0x29,0x7b,0x61,0x6c,0x65,0x72,0x74,0x28,0x22,0x59,0x6f,0x75,0x20,0x57,0x49,0x4e,0x21,0x22,0x29,0x3b,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2e,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x2b,0x3d,0x20,0x22,0x3f,0x6c,0x76,0x6c,0x5f,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64,0x3d,0x22,0x2b,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x22,0x70,0x61,0x73,0x73,0x22,0x29,0x2e,0x76,0x61,0x6c,0x75,0x65,0x7d,0x65,0x6c,0x73,0x65,0x20,0x7b,0x61,0x6c,0x65,0x72,0x74,0x28,0x22,0x57,0x52,0x4f,0x4e,0x47,0x21,0x20,0x54,0x72,0x79,0x20,0x61,0x67,0x61,0x69,0x6e,0x21,0x22,0x29,0x7d,0x27,0x3e,0x43,0x68,0x65,0x63,0x6b,0x20,0x50,0x61,0x73,0x73,0x77,0x6f,0x72,0x64,0x3c,0x2f,0x62,0x75,0x74,0x74,0x6f,0x6e,0x3e));

Thank you mutantsrus