Recently, colleagues from Yandex shared with us a sample of an interesting Trojan, as we reported in
this news. This malware does not come across often, so we decided to take a closer look at it, and at the same time talk about why we rarely find such samples.
The Trojan is a multi-component backdoor written in JavaScript that uses Node.js to run. Its main elements are worker and updater, which are downloaded and installed into the system by the loader. The payload can be any, but in this case the Trojan is installed by the miner xmrig. At the time of the study, the developer used the miner for the mining of cryptocurrency TurtleCoin.
MonsterInstall is distributed through sites with cheats for popular video games. Most of these resources belong to the Trojan’s developer, but we have found several more infected files on other similar sites. The owner of one of them regularly monitors updates of competitors and replenishes its resource with fresh content. For this, he uses the parser.php script, which through a proxy is looking 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 Fate/Extella Link: ўЂµ№ЅµЂ +13 v04.09.2019 {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 Dead Effect 2: ўЂµ№ЅµЂ +8 v190401 {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 - a large selection of cheats, but for all the links will be given the same archive. If you try to download any of the files from the malware site, the user will receive a Trojan.MonsterInstall. Some parameters of the Trojan can be guessed from the download link:
https://<malicious_site>/fc/download.php?name=Borderlands%20GOTY%20Enhanced:%20%D0%A2%D1%80%D0%B5%D0%B9%D0%BD%D0%B5%D1%80%20+16%20v1.0%20{CheatHappens.com}&link=https://<malicious_site>//r.php?site=http://gtrainers.com/load/0-0-1-7081-20&password=<malicious_site>/&uid=101&sid1=1&sid2=1&charset=utf-8
- name - the name of the archive and exe in the archive;
- link - link to the file that the user wanted to download (sewn into data.json);
- password - archive password.
Let's say we chose the right cheat and downloaded a 7zip archive with a promising name “ExtrimHack.rar” from the developer’s website of the Trojan’s developer. Inside it are the executable file, the configuration file, the 7zip library, and the bin-archive with the native C ++ libraries and scripts run using the Node.js binary.
An example of the contents of the archive:
- 7z.dll;
- data.bin;
- data.json;
- ESP cheat for CS GO.exe.
When launching the executable file, the Trojan will install all the components necessary for its operation, and will also download the cheat needed by the user, using information from the data.json file with parameters.
An example of the contents of data.json:
{"source":[5,10,11,43],"dataVersion":[0,0,0,115],"link":"http:\/\/clearcheats.ru\/images\/dl\/csgo\/ESP_csgo.dll"}
In order to exclude the work of several copies of its process, the Trojan creates a mutex "cortelMoney-suncMutex" and is installed in the directory "% WINDIR% \ WinKit \". It then checks 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 up to date, nothing further does and ends.
After that, the Trojan unpacks the contents of data.bin to% WINDIR% \\ WinKit \\ and installs the service to start start.js.
Content data.bin:
- Daemon;
- node_modules;
- 7z.dll;
- msnode.exe;
- start.js;
- startDll.dll;
- update.js;
- updateDll.dll.
At the same time, msnode.exe is the Node.js executable file with a valid digital signature, and the node_modules directory contains the ffi, node-windows and ref libraries.
In start.js, the startDll.dll library is loaded and its export is called mymain, 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 invokes its export mymain. Nothing complicated.
In updateDll.dll, the Trojan will start to check the internet connection. To do this, he will send requests to google.com, yahoo.com, facebook.com every 10 seconds until all three return the 200 code. Then it sends to the
s44571fu [.] Bget [.] En / CortelMoney / enter.php POST server a request with configuration data:
{"login":"NULL","mainId":"PPrn1DXeGvUtzXC7jna2oqdO2m?WUMzHAoM8hHQF","password":"NULL","source":[0,0,0,0],"updaterVersion":[0,0,0,0],"workerVersion":[0,0,0,0]}
In this case, for the basic authorization, the pair “cortel: money” is used, and the User-Agent is set up with “USER AGENT”. For the basic authorization of subsequent requests will be used login: password, which will inform the server.
The server responds with a json of the following form:
{ "login": "240797", "password": "tdzjIF?JgEG5NOofJO6YrEPQcw2TJ7y4xPxqcz?X", "updaterVersion": [0, 0, 0, 115], "updaterLink": "http:\/\/s44571fu.bget.ru\/CortelMoney\/version\/0-0-0-115-upd.7z", "workerVersion": [0, 0, 3, 0], "workerLink": "http:\/\/s44571fu.bget.ru\/CortelMoney\/version\/0-0-3-0-work.7z" }
As you can see, the server’s response indicates the versions of the main elements of the Trojan. If the current version of the updater on the user's device is older than that reported by the server, the Trojan downloads the file at the specified link and unpacks the archive into the "% WINDIR% \\ WinKit \\\\" directory, where the value of the updaterVersion parameter from the server response will be specified .
The Trojan unpacks the worker file to the% WINDIR% \\ WinKit \\ SystemNode \\ directory, and then launches the "% WINDIR% \\ WinKit \\ SystemNode \\ sysnode% WINDIR% \\ WinKit \\ SystemNode \\ main.js".
Contents of the archive with the worker:
- node_modules;
- 7za.exe;
- codex;
- main.js;
- sysnode.exe.
The Trojan then deletes 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 recreates the “Windows Node” service, replacing the executable file with daemon \\ service.exe.
Next it forms service.xml with parameters:
<service><id>service.exe</id><executable>C:\Windows\\WinKit\0.0.0.115\msnode.exe</executable><arguments>"C:\Windows\\WinKit\0.0.0.115\start.js"</arguments></service>
Updater is installed in the “C: \ Windows \ Reserve Service” directory, prescribed by the service and launched with the Node.js binary. It also consists of several js scripts and native C ++ libraries. The main module is main.js.
Content archive with updater:
- main.js;
- start.js;
- crypto.dll;
- network.dll;
- service.exe.
First of all, the Trojan finds out the current date by sending a request to google.com, yandex.ru or
www.i.ua. He uses the received information a bit later. Then, using the crypto.dll library, it decrypts the contents of the bootList.json file.
Decryption algorithm:
key = '123' s = '' for i in range(len(d)): s += chr((ord(d[i]) - ord(key[i % len(key)])) & 0xff)
Receives 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.login = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "log"); WindowsNodeInfo.password = windowsLib.getStringRegKey("HLM\\SOFTWARE\\Microsoft\\Windows Node", "pass"); 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 pair “cortel: money”, and sends it by a POST request to the previously decrypted managing server.
In response, the server receives:
{ "data": { "updaterVersion": [0, 0, 0, 1], "updaterLink": "/upd.7z", "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 the current date received earlier is useful. The Trojan compares it with the dataTime parameter sent by the server. If the difference between the dates is more than a week (in millisecond terms), the Trojan will not execute commands. Also, the dataInfo parameter contains the data signature (data field), it is checked using the public key sewn into main.js. And the “bootList” parameter contains a list of servers that the Trojan encrypts and stores in “bootList.json”.
After that, the Trojan compares its version with the one specified in the updaterVersion parameter. If the installed version is not lower than the latest one, the Trojan launches "upd \\ upd.exe", passing it through the "main.js" parameter. If the version from the server response is newer, then the Trojan downloads the updater archive with the update from the “updaterLink” parameter, checks its signature and unpacks it. Then it writes the update version of the [HKLM \\ SOFTWARE \\ Microsoft \\ Reserve System] 'updaterVersion' to the registry, after which it launches again “upd \\ upd.exe”, passing it through the “main.js” parameter.
The Trojan Worker verifies that the components have already been installed, and makes decisions about the need to install applications. First, it creates a MoonTitleWorker mutex, then decrypts the codeX file 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"}}
This information is sent by a POST request to http: // <malicious_site> [.] Xyz: 1001 / getApps (for the sake of decency, we do not specify a domain name, but you can find it
here .) The server response may contain information about the applications that need to be installed.
Sample answer:
{ "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 there is no such application on the device, the Trojan downloads it by sending a POST request to the URL http: // <malicious_site> [.] Xyz: 1001 /, where the value of the link parameter for the corresponding application from the server response will be indicated instead. If there is such an application, but an older version, it is updated to the latest.
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 saved in the registry [HKLM \\ SOFTWARE \\ Microsoft \\ MoonTitle \\ apps \\].
At the moment, with the help of a backdoor, the miner xmrig is put. Depending on the system capacity, the Trojan downloads an xmr-1.7z or xmr-1-64.7z archive. In start.js it loads the xmrig.dll library and calls the export mymain, where it expands 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 xmrig.exe is located next to it, 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 file “dump” in the same directory, then it decrypts it in the same way, starts windows-update.exe and embeds the decrypted payload into it.
The Trojan collects and sends a 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:
{"maxCpuLoad":1000,"minCpuLoad ":0,"algo":"cryptonight-pico/trtl","av":0,"background":false,"donate-level":1,"max-cpu-usage":75,"retries":5,"retry-pause":5,"cpu-priority":1,"pools":[{"url":"185.224.133.91:5511","keepalive":true,"nicehash":true}]}
After the Trojan saves the configuration in config.json, it will automatically start and start mining.
MonsterInstall has other modifications. For example, besides cheats for games, the developer Malvari distributed it under the guise of the installer of the Chrome browser and the 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, in the bootloader of one of the versions of the Trojan, there is even a link to the license agreement located on the developer’s domain of the Trojan.
(Questions about the legal validity 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).
findingsNode.js is not the most practical solution for virus writers. If the size of such a Trojan can be small, the Node.js binding (executable file and libraries) will be much “heavier” than the standard Malvar. What dictated this choice? As a rule, developers choose tools with which they are well acquainted. Therefore, even in the case of employees, 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 is rarely suspicious.
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 .