# Backdoor on Node.js: why, why and how it works

Recently, colleagues from Yandex shared with us a sample of an interesting Trojan, which we reported in this news. Such a malware does not come across often, so we decided to disassemble it in more detail, and at the same time talk about why we rarely encounter such samples.

The Trojan is a multi-component backdoor written in JavaScript and using Node.js. to run it. Its main elements are worker and updater, which are downloaded and installed into the system by the bootloader. The payload can be any, but in this case, the Trojan installs the xmrig miner. At the time of the study, the developer used the miner to mine the TurtleCoin cryptocurrency.

MonsterInstall is distributed through sites with cheats for popular video games. Most of these resources belong to the developer of the Trojan, but we found several more infected files on other similar sites. The owner of one of them regularly monitors the updates of competitors and replenishes his resource with fresh content. To do this, he uses the parser.php script, which through a proxy searches for new cheats on cheathappens.com.

Proxy parse done, total: 1
Use sox 84.228.64.133:1080
Error: CURL error(#52), attempts left: 10
Use sox 84.228.64.133:1080
Posts found: 30!
[33mPage Satisfactory: РўСЂРµР№РЅРµСЂ +8 vCL#96731 {CheatHappens.com} already in base[0m
[33mPage Borderlands: The Pre-Sequel - РўСЂРµР№РЅРµСЂ +28 v1.2019 {LinGon} already in base[0m
[33mPage Borderlands - Game of the Year Enhanced: РўСЂРµР№РЅРµСЂ +19 v1.0.1 {LinGon} already in base[0m
[33mPage Star Wars: Battlefront 2 (2017): РўСЂРµР№РЅРµСЂ +4 v01.04.2019 {MrAntiFun} already in base[0m
[36mPage Far Cry 5: РўСЂРµР№РЅРµСЂ +23 v1.012 (+LOST ON MARS/DEAD LIVING ZOMBIES) {CheatHappens.com} added 2019-Apr-09[0m
[36mPage Superhot: РўСЂРµР№РЅРµСЂ +3 v2.1.01p { MrAntiFun} added 2019-Apr-09[0m
[36mPage Dawn of Man: РўСЂРµР№РЅРµСЂ +7 v1.0.6 {CheatHappens.com} added 2019-Apr-08[0m
[36mPage Borderlands 2: РўСЂРµР№РЅРµСЂ +14 v06.04.2019 {MrAntiFun} added 2019-Apr-08[0m
[36mPage Borderlands: The Pre-Sequel - РўСЂРµР№РЅРµСЂ +17 v06.04.2019 {MrAntiFun} added 2019-Apr-08[0m
[36mPage Tropico 6: РўСЂРµР№РЅРµСЂ +9 v1.01 {MrAntiFun} added 2019-Apr-08[0m
[36mPage Operencia: The Stolen Sun - РўСЂРµР№РЅРµСЂ +20 v1.2.2 {CheatHappens.com} added 2019-Apr-08[0m
[36mPage Enter the Gungeon: РўСЂРµР№РЅРµСЂ +6 v2.1.3 {MrAntiFun} added 2019-Apr-07[0m
[36mPage The Guild 3: РўСЂРµР№РЅРµСЂ +2 v0.7.5 {MrAntiFun} added 2019-Apr-07[0m
[36mPage Assassin's Creed: Odyssey - РўСЂРµР№РЅРµСЂ +26 v1.2.0 {FLiNG} added 2019-Apr-07[0m
[36mPage Assassin's Creed: Odyssey - РўСЂРµР№РЅРµСЂ +12 v1.2.0 {MrAntiFun} added 2019-Apr-06[0m
[36mPage Super Dragon Ball Heroes: World Mission - РўСЂРµР№РЅРµСЂ +11 v1.0 {FLiNG} added 2019-Apr-05[0m
[36mPage Tropico 6: РўСЂРµР№РЅРµСЂ +7 v1.02 97490 {CheatHappens.com} added 2019-Apr-05[0m
[36mPage Risk of Rain 2: РўСЂРµР№РЅРµСЂ +10 Build 3703355 {CheatHappens.com} added 2019-Apr-05[0m
[36mPage Sid Meier's Civilization 6 - Rise and Fall: РўСЂРµР№РЅРµСЂ +12 v1.0.0.314 {MrAntiFun} added 2019-Apr-05[0m
[36mPage Sid Meier's Civilization 6 - Gathering Storm: РўСЂРµР№РЅРµСЂ +12 v1.0.0.314 {MrAntiFun} added 2019-Apr-05[0m
[36mPage Sid Meier's Civilization 6: РўСЂРµР№РЅРµСЂ +12 v1.0.0.314 {MrAntiFun} added 2019-Apr-05[0m
[36mPage Borderlands GOTY Enhanced: РўСЂРµР№РЅРµСЂ +16 v1.0 {CheatHappens.com} added 2019-Apr-05[0m
[36mPage Borderlands Game of the Year Enhanced: РўСЂРµР№РЅРµСЂ +13 v1.00 {MrAntiFun} added 2019-Apr-04[0m
[36mPage Assassin's Creed: Odyssey: РўСЂРµР№РЅРµСЂ +24 v1.2.0 (04.04.2019) {CheatHappens.com} added 2019-Apr-04[0m
[36mPage Sekiro: Shadows Die Twice - РўСЂРµР№РЅРµСЂ +24 v1.02 {FLiNG} added 2019-Apr-04[0m
[36mPage Hearts of Iron 4: РўСЂРµР№РЅРµСЂ +24 v1.6.2 {MrAntiFun} added 2019-Apr-04[0m
[36mPage Wolcen: Lords of Mayhem - РўСЂРµР№РЅРµСЂ +5 v1.0.2.1 {MrAntiFun} added 2019-Apr-04[0m
[36mPage Devil May Cry 5: РўСЂРµР№РЅРµСЂ +18 v1.0 (04.03.2019) {CheatHappens.com} added 2019-Apr-04[0m
Parse done

On the developer's sites there is a large selection of cheats, but the same archive will be returned for all the links. If you try to download any of the files from the malware site, the user will receive Trojan.MonsterInstall. Some parameters of the Trojan can be guessed from the download link:

• name - the name of the archive and exe in the archive;

Suppose we select the desired cheat and download the password-protected 7zip archive with the promising name “ExtrimHack.rar” from the site of the Trojan’s developer. Inside it there is an executable file, a configuration file, a 7zip library, as well as a bin archive with native C ++ libraries and scripts launched using the Node.js binar.

Example archive content:

• 7z.dll;
• data.bin;
• data.json;
• ESP cheat for COP GO.exe.

When the executable is launched, the Trojan will install all the components necessary for its operation, and also download the cheat necessary for the user, using the information from the data.json file with parameters.

Example contents of data.json:

To exclude several copies of its process from working, the Trojan creates the “cortelMoney-suncMutex” mutex and installs it in the “% WINDIR% \ WinKit \” directory. Then it checks to see if it is in the registry ([HKLM \\ Software \\ Microsoft \\ Windows Node]). If so, it reads its parameters and compares the version with the one specified in data.json. If the version is current, it does nothing further and ends.

After that, the Trojan unpacks the contents of data.bin in% WINDIR% \\ WinKit \\ and installs the service to start start.js.

Content of data.bin:
• Daemon;
• node_modules;
• 7z.dll;
• msnode.exe;
• start.js;
• startDll.dll;
• update.js;
• updateDll.dll.

At the same time, msnode.exe is an executable file Node.js with a valid digital signature, and the node_modules directory contains the libraries “ffi”, “node-windows” and “ref”.

The startDll.dll library is loaded in start.js and its mymain export is called, in which it reads its parameters from the registry, starts "% WINDIR% \\ WinKit \\ msnode% WINDIR% \\ WinKit \\ update.js" and stops the service "Windows Node." The update.js script, in turn, loads the updateDll.dll library and calls its mymain export. Nothing complicated.

In updateDll.dll, the Trojan will begin to check your Internet connection. To do this, he will send requests to google.com, yahoo.com, facebook.com every 10 seconds, until all three return 200 code. Then send to s44571fu server[.] bget [.] ru / CortelMoney / enter.php POST request with configuration data:

In this case, for basic authorization, a pair of “cortel: money” is used, and the User-Agent is set to “USER AGENT”. For basic authorization of subsequent requests, login: password will be used, which will be reported by the server.

The server responds with json like this:

{
"updaterVersion": [0, 0, 0, 115],
"workerVersion": [0, 0, 3, 0],
}

As you can see, the server’s response contains versions of the main elements of the Trojan. If the current version of updater on the user's device is older than the one reported by the server, the Trojan downloads the file from the specified link and unpacks the archive into the directory "% WINDIR% \\ WinKit \\\\", where instead the value of the updaterVersion parameter from the server response will be indicated .

The Trojan unpacks the worker file into the% WINDIR% \\ WinKit \\ SystemNode \\ directory, and then launches "% WINDIR% \\ WinKit \\ SystemNode \\ sysnode% WINDIR% \\ WinKit \\ SystemNode \\ main.js".

The contents of the archive with the worker:
• node_modules;
• 7za.exe;
• codex;
• main.js;
• sysnode.exe.

The Trojan then removes the Windows Node Guard service, and then creates it again, replacing the executable file with the Windows Node service file. In the same way, it re-creates the Windows Node service, replacing the executable with daemon \\ service.exe.

Next forms service.xml with parameters:
service.exeC:\Windows\\WinKit\0.0.0.115\msnode.exe"C:\Windows\\WinKit\0.0.0.115\start.js"

Updater is installed in the "C: \ Windows \ Reserve Service" directory, registered by the service and launched by the Node.js. binary. It also consists of several js scripts and native C ++ libraries. The main module is main.js.

The contents of the archive with updater:
• main.js;
• start.js;
• crypto.dll;
• network.dll;
• service.exe.

The first thing the Trojan finds the current date, send a request to google.com, yandex.ru or www.i.ua . He uses the information received a little later. It then decrypts the contents of the bootList.json file using the crypto.dll library.

Decryption Algorithm:
key = '123'
s = ''
for i in range(len(d)):
s += chr((ord(d[i]) - ord(key[i % len(key)])) & 0xff)

Gets a list of management servers from there:
[{"node":"http://cortel8x.beget.tech/reserve","weight":10},{"node":"http://reserve-system.ru/work","weight":10}]

Then the Trojan reads information from the registry:
function getInfo()
{
var WindowsNodeInfo = new Object();
WindowsNodeInfo.mainId = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "mainId");
WindowsNodeInfo.source = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "source");
WindowsNodeInfo.updaterVersion = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "updaterVersion");
WindowsNodeInfo.workerVersion = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "workerVersion");
var ReserveSystemInfo = new Object();
ReserveSystemInfo.workerVersion = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Reserve System", "updaterVersion");
var myInfo = new Object();
myInfo.windowsNode = WindowsNodeInfo;
myInfo.reserveSystem = ReserveSystemInfo;
return JSON.stringify(myInfo);
}

Then it adds the HTTP header of the basic authorization corresponding to the “cortel: money” pair, and sends it with a POST request to the previously decrypted management server.

{
"data": {
"updaterVersion": [0, 0, 0, 1],
"updaterVerify": "£ñß(\u0012Ä\ti¾$ë5»\u001c²\u001c\fÙ=±÷ö´èUnÐÂBÔ\n\u001dW6?u½\u0005n\u000fp:üÍ\u0019\u0000\u000bSý«\u00137÷\u0013”’ì¥û§s7F\u0016ó\\\u000f%6ñê\"7î<ýoä0Æ%tñÅv­S¡\r\u001eÅÆ¡¿N)v\\f8\u0004F\fUS¯³§ oIõiÆîGÝª\u0017êH/8Ö1-°[P5E7XFø%SXÕ6Oþ=Vô :.3i\u000eÁù9Ã&¾M\u001eÛªé$\u0006#IèÞÛ\u0018À\u001b^è,ÁòÑCTXb\u001d$ç\u0004ð¶0UVÕ»e\u001f\b\u001e¡Ä¼è+Fjúÿoâz\r!çô3xØs_\u000b\u0017\u001fY]\u0001¥j^û\\W", "dateTime": 1534868028000, "bootList": [{ "node": "http://cortel8x.beget.tech/reserve/", "weight": 10 }, { "node": "http://reserve-system.ru/work/", "weight": 10 }] }, "dataInfo": "Iù@ÀP‘ÈcÊÛ´#ièÒ~\u0007<\u0001Ýìûl«ÔÆq\u0013àÛ\u0003\b\u0017ÑLÁ}ÿÚDS']\u0003bf\u0003!¿Cð¸q¸ÖÜ’B¢CÄAMÀA¤d\u001c5¨d-\u0013\u0011Ñ¼F‘|SB[¬°(Ü¹ÈÒÜ £L\u00071¾:\u001bìýKõ\"²¸$´3UºÅ¨J¨cf¿}r;Öeì¶xØKt¥47a\u001e¸Ôy\u0006\u001b\u0004ó\u001a\u0019\nu>¨)bkæ'\u00127@é7µæy3ÈNrS’Mð\u0018\u0019¾òÓ[å5H·¦k‘¿É&PÂÈîåÚ~M\u0010ðnáHæ“ªxÃv c×“\u0013TïÑÝ\t\u0018Æ\u00148$”Ôî" } And here comes the current date, obtained earlier. The Trojan checks it against the dataTime parameter passed by the server. If the difference between the dates is more than a week (in terms of milliseconds), the Trojan will not execute the commands. The dataInfo parameter also contains the data signature (data field), it is checked using the public key wired in main.js. And the “bootList” parameter contains a list of servers, which the Trojan encrypts and stores in “bootList.json”. After that, the Trojan checks its version against the one specified in the updaterVersion parameter. If the installed version is not lower than the latest one, the Trojan launches “upd \\ upd.exe” by passing the parameter “main.js”. If the version from the server’s response is newer, then the Trojan downloads the update archive using the link from the “updaterLink” parameter upd.7z, checks its signature and unpacks it. Then it writes to the registry the version of the update [HKLM \\ SOFTWARE \\ Microsoft \\ Reserve System] 'updaterVersion', after which it again launches “upd \\ upd.exe”, passing it with the parameter “main.js”. The Trojan’s Worker checks that one of the components has already been installed, and makes decisions about whether to install applications. First, he creates the MoonTitleWorker mutex, then decrypts the codeX file with an XOR with the string “xor” and executes it. After that forms json with information: {"userId": id, "starter": [], "worker": [], "source": [], "osInfo": {"isX64": True, "osString": "Windows 7 Enterprise"}} Sends this information with a POST request to http: //[.] xyz: 1001 / getApps (for the sake of decency, we do not specify the domain name, but it can be found here .) The server response may contain information about the applications that need to be installed. Answer example: { "body": { "apps": [{ "hash": "452f8e156c5c3206b46ea0fe61a47b247251f24d60bdba31c41298cd5e8eba9a", "size": 8137466, "version": [2, 0, 0, 2], "link": "xmr-1-64.7z", "path": "%pf%\\Microsoft JDX\\64", "runComand": "%path%\\moonlight.exe start.js", "name": "xmr64" }] }, "head": "O~¨^Óå+ßzIçsG¬üSÊ¶$êLLùÎ¸Z\f\u0019ÐÐ\u000e\u0004\u001cÀU¯\u0011)áUÚ\u001flß²A\u001fôÝÔì±y%\"DP»^¯«FUâ\u001cÔû\u001dµ´Jï#¬ÌÈ¹ÎÚª?\r]Yj·÷õ³\u001e°ÖÒ\\é¤dBT\u0019·¦FõVQ°Aç)\u001cõªµ¦ýûHlbÍ¸þ}é\u0000jvÔ%S;Ã×þA\u0011ßI[´\u0004ýÚ\u0007Z:ZÂ\nñz#ÈBö²2\u0007ÎJw±èTVoå\bÖR3½ù;ó\u0011ÉÌÅÖàð06ÓeÕþ­7Ù\u0011»¢5µgôÛc&L\u000fê.?!Çæ}¨\u001eÕJ#A¼_Ì\u0015càñb"
}

If the device does not have such an application, the Trojan downloads it by sending a POST request to the URL http: //[.] xyz: 1001 /, where instead the value of the “link” parameter will be indicated for the corresponding application from the server response. If there is such an application, but an older version, it is updated to the current one.

The Trojan checks the size and hash of the downloaded file with the information specified by the server in the hash and size parameters. If the data converges, it moves the file along the path from the path parameter and runs the command specified in the runCommand field. Information about the downloaded application is stored in the registry [HKLM \\ SOFTWARE \\ Microsoft \\ MoonTitle \\ apps \\].

At the moment, the xmrig miner is being set using the backdoor. Depending on the capacity of the system, the Trojan downloads an xmr-1.7z or xmr-1-64.7z archive. In start.js, it loads the xmrig.dll library and calls mymain export, where it deploys its environment variables and kills the processes:
• % sys32_86% \\ xmr;
• % sys32_86% \\ xmr64;
• % pf_86% \\ Microsoft JDX \\ 32 \\ windows-update.exe;
• % pf_86% \\ Microsoft JDX \\ 64 \\ windows-update.exe.

If the xmrig.exe file is located nearby, the Trojan loads it into the memory of the current process, erases the MZ signature, decrypts it using XOR with 0x39, and then saves its dump in the dump file. If the Trojan finds the “dump” file in the same directory, it decrypts it in the same way, launches windows-update.exe and embeds the decrypted payload into it.

The Trojan collects and sends by POST request to the URL: cherry-pot [.] Top / RemoteApps / xmr / main.php the following system information: {"action": "enter", "architecture": "INTEL", "cpuAES" : true, “cpuCache”: 8192, “cpuSpeed”: 3392.0, “cpuThreads”: 2, “cpuVendorString": "Intel® Core (TM) i5-4690S CPU @ 3.20GHz \ u0000", "hightPages": false, " login ":" null "," password ":" null "," ramPhysicalSize ": 3071," xmrigVersion ": [2,10,0]}

In response, the server sends the miner configuration:

After the Trojan saves the configuration in config.json, it will automatically start and start mining.

MonsterInstall has other modifications. For example, in addition to cheats for games, the Malvari developer distributed it under the guise of a Chrome browser installer and a program for checking files. In later versions of the Trojan, the developer thought about security and added string encryption, as well as the need to enter a password for some files. In addition, the bootloader of one of the versions of the Trojan even has a link to a license agreement hosted on the Trojan’s developer’s domain.

(Questions about the legal force of such agreements, unfortunately, are beyond the scope of this article, but if you would be interested to read material on this topic, let us know in the comments).

conclusions

Node.js is not the most practical solution for virus writers. If the size of such a Trojan can be small, then the Node.js binding (executable file and libraries) will be significantly “heavier” than the standard malvari. What dictated this choice? As a rule, developers choose tools that they are familiar with. Therefore, even in the case of the breeders, the choice of technology is more a matter of personal preference. However, Node.js has its advantages, one of which is a valid signature. In the system, such a process will be signed as Node.js, which rarely raises suspicions.

Summing up, it can be noted that, despite the interesting choice of tools, this did not give the backdoor developer any significant advantage. It is unlikely that in the future we will see more malware using Node.js.

As usual, we share indicators of compromise .