{
	"id": "64b1b00a-9afd-403c-9746-b782bd498ced",
	"created_at": "2026-04-06T00:19:45.991132Z",
	"updated_at": "2026-04-10T03:29:35.417908Z",
	"deleted_at": null,
	"sha1_hash": "3e252b8f39925c443158215b2a18dec0fa0a82b9",
	"title": "Evolution of UNC4990: Uncovering USB Malware's Hidden Depths",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2396448,
	"plain_text": "Evolution of UNC4990: Uncovering USB Malware's Hidden Depths\r\nBy Mandiant\r\nPublished: 2024-01-30 · Archived: 2026-04-05 18:21:00 UTC\r\nWritten by: Diana Ion, Jae Young Kim, Muhammad Umair, Panagiotis Antoniou, Yash Gupta\r\nMandiant Managed Defense has been tracking UNC4990, an actor who heavily uses USB devices for initial infection.\r\nUNC4990 primarily targets users based in Italy and is likely motivated by financial gain. Our research shows this campaign\r\nhas been ongoing since at least 2020.\r\nDespite relying on the age-old tactic of weaponizing USB drives, UNC4990 continues to evolve their tools, tactics and\r\nprocedures (TTPs). The actor has moved from using seemingly benign encoded text files to hosting payloads on popular\r\nwebsites such as Ars Technica, GitHub, GitLab, and Vimeo.\r\nThe legitimate services abused by UNC4990 (including Ars Technica, GitHub, GitLab, and Vimeo) didn’t involve exploiting\r\nany known or unknown vulnerabilities in these sites, nor did any of these organizations have anything misconfigured to\r\nallow for this abuse. Additionally, the content hosted on these services posed no direct risk for the everyday users of these\r\nservices, as the content hosted in isolation was completely benign. Anyone who may have inadvertently clicked or viewed\r\nthis content in the past was not at risk of being compromised.\r\nMandiant has observed UNC4990 leverage EMPTYSPACE (also known as VETTA Loader and BrokerLoader), a\r\ndownloader that can execute any payload served by the command and control (C2) server, and QUIETBOARD, which is a\r\nbackdoor that was delivered using EMPTYSPACE.\r\nInfection Lifecycle\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 1 of 21\n\nFigure 1: Infection chain\r\nInitial Compromise: USB LNK\r\nIn all instances of the infection which Mandiant Managed Defense responded to, the infection began with the victim double-clicking a malicious LNK shortcut file on a removable USB device. The naming convention for the LNK file typically\r\nconsisted of the vendor of the USB device and the storage size in brackets, for example:  KINGSTON (32GB).lnk . Mandiant\r\nalso observed instances where, instead of the vendor name, the drive label was used, for example:  D (32GB).lnk .\r\nIn addition to this, the icon of the LNK file was set to the Microsoft Windows default icon for drives. This was likely done\r\nto entice unsuspecting users to double click the file, ultimately triggering the functionality embedded in the LNK file.\r\nFigure 2: Malicious LNK file\r\nUpon double clicking, the PowerShell script  explorer.ps1 is executed via the following LNK shortcut target:\r\nC:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -windowstyle\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 2 of 21\n\nhidden -NoProfile -nologo -ExecutionPolicy ByPass -File explorer.ps1\r\nExplorer.ps1 \r\nFrom the investigations conducted by Mandiant Managed Defense, Mandiant identified multiple iterations of a malicious\r\nPowerShell script called  explorer.ps1 . This is an encoded PowerShell script that ultimately downloads and decodes an\r\nadditional payload, which, in the cases investigated by Mandiant, has been the EMPTYSPACE downloader. \r\nMandiant suspects the earlier versions of  explorer.ps1 were not encoded; however, more recent variants were loaded into\r\nmemory as a reverse Base64 encoded string, similar to the one shown in Figure 3.\r\nFigure 3: explorer.ps1 (SHA256: 6fb4945bb73ac3f447fb7af6bd2937395a067a6e0c0900886095436114a17443)\r\nThe earliest version of  explorer.ps1 which we identified ( SHA256:\r\n72f1ba6309c98cd52ffc99dd15c45698dfca2d6ce1ef0bf262433b5dfff084be ) checks whether a  Hangul Filler Unicode\r\ncharacter ( E3 85 A4  in UTF-8) labeled directory exists at the current path and only continues with the execution of the\r\nfollowing sequence in the case the condition is true (Hangul Filler is a special Unicode character (U+3164) used in the\r\nKorean writing system, Hangul. It is typically not possible to use a whitespace as a file or directory name in Windows.\r\nHowever, using the Hangul Filler character, which is rendered as a whitespace, this restriction can be bypassed):\r\nTriggers the default action associated with the item pointed to by Hangul Filler named directory.\r\nSome newer instances of the script contain a unique UUID value, different for each infection. The identifier is saved\r\nto a file named from_machine_uuid.dat in the APPDATA directory. Mandiant determined that this UUID variable\r\nwas not present in the script from the beginning of the campaign and only added later on as a new capability to track\r\ninfected hosts.\r\nThe script fetches a resource from a URL stored in the script,  hxxps://lucaespo.altervista[.]org/updater.php?\r\nfrom=USB1 , and saves it as  Runtime Broker.exe a.k.a. EMPTYSPACE in the TEMP directory.\r\nIn later versions (such as \r\nSHA256: 99d9dfd8f1c11d055e515a02c1476bd9036c788493063f08b82bb5f34e19dfd6 ), the script was updated with an\r\nintermediary stage hosted at the URL:  hxxps://eldi8.github[.]io/src.txt . The  src.txt  ( SHA256:\r\nb38dbaea648ef7da1c639f4fdaac0d88f03306ea42f0edc9af512c613dbdb7e1 ) file contains a pattern of three characters:\r\nTAB:  09 , Space: 20 and Line Feed:  0A . In a traditional text editor,  src.txt would appear as a blank file.\r\nMandiant observed the same src.txt had been previously hosted on GitLab:  hxxps://evh001.gitlab[.]io/src.txt .\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 3 of 21\n\nFigure 4: src.txt as viewed in a HEX editor\r\nA custom decoding scheme is then applied to the src.txt file, consisting of the following sequence of operations:\r\nCharacter replacement\r\n1. Spaces are replaced with 1s\r\n2. Tab characters are replaced with 0s\r\n3. New line characters are replaced with spaces\r\nThis transformation changes the original string into a new format that resembles a binary string (composed of\r\n1s and 0s).\r\nThe transformed string is then split into an array of substrings. Each substring represents a sequence of 1s and\r\n0s.\r\nEach substring is converted from a binary representation to its corresponding character.\r\nThe resulting characters are joined back together into a single string.\r\nThe newly constructed string is the final URL from where the executable  Runtime Broker.exe is downloaded: \r\nhxxps://wjecpujpanmwm[.]tk/updater.php?from=USB1 . This URL was serving EMPTYSPACE from at least early\r\n2022 through to July 2023, as Mandiant has also observed it in updated versions of  explorer.ps1 . \r\nOnce EMPTYSPACE has been downloaded, the script continuously checks for the existence of the\r\nfile  pythonw.exe , under the directory  %ProgramFiles%\\Winsoft Update Service\\  and will proceed to execute the\r\nnewly downloaded malware every second only if the  pythonw.exe file is not present at the specified path.\r\nUse of Third-Party Websites for Payload Hosting\r\nStarting in 2023, the use of GitHub was replaced by a new payload hosted on Vimeo, a video sharing website, with the new\r\nURL being also hard-coded in explorer.ps1 as  hxxps://vimeo[.]com/api/v2/video/804838895.json . The encoded\r\npayload was inserted into the description of a Pink Floyd-related video uploaded to Vimeo on March 5, 2023. At the time of\r\npublishing this post, the video was removed from Vimeo.\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 4 of 21\n\nFigure 5: Vimeo video description\r\nFigure 6: JSON object pulled from the hard-coded Vimeo URL\r\nThis change from the previously discussed version has been coupled with an upgrade from the custom decoding scheme to\r\nthe use of AES in CBC mode and Base64 encoding.\r\nThe script fetches the Vimeo JSON blob which contains the attacker payload between the delimiter characters  ::??\r\nand  ?:?: . The payload is then Base64 decoded and decrypted with a hard-coded AES-256-CBC key shown as follows:\r\n92 f7 6b 7d 6a e7 3f 41 b5 8f 41 e5 14 fb 68 de c8\r\ne8 4a 2d c1 6f a2 71 f3 f3 1d 9f 3c 99 b7 4d\r\nFrom November 27, 2023, Mandiant Managed Defense observed yet another shift in TTPs with regard to third-party\r\nwebsites used as C2. As the Vimeo video was taken down, the threat actor switched to using a well-known news forum, Ars\r\nTechnica. In the updated instances of  explorer.ps1 , Mandiant observed the following hard-coded URL:\r\nhxxps://arstechnica[.]com/civis/members/frncbf22.1062014/about/ . \r\nAs with the previous payload hosted on Vimeo, the Ars Technica URL employs the exact same technique down to even the\r\nsame delimiter characters and encryption key, so there would be no other changes required in the  explorer.ps1 script\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 5 of 21\n\nbesides the URL. However, now the encoded blob was appended to the image URL contained in the About section of the\r\nuser  frncbf2 . This user became a member on the Ars Technica forum on November 23, 2023.\r\nFigure 7: User profile of frncbf2 on the Ars Technica forum\r\nFigure 8: Payload appended to image URL\r\nAs of mid December 2023, the photo hosted on Ars Technica was removed together with the intermediary payload.\r\nFrom mid-2023, the threat actor also updated the URL serving EMPTYSPACE. Recent infections revealed the new URL to\r\nbe  hxxps://evinfeoptasw.dedyn[.]io/updater.php?from=USB1 . The final URL is formed by appending the string \" \u0026user=\r\n\u003cuuid\u003e \", UUID being the unique identifier mentioned previously. \r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 6 of 21\n\nThe different versions of  explorer.ps1 that Mandiant encountered during the research process showed how the script was\r\nincrementally changed. Initially, the script only focused on downloading EMPTYSPACE from an encoded URL. It then\r\nadded an intermediary stage for constructing the final URL using payloads hosted on third party websites. Later on, the\r\ncapability to track infections was added. Mandiant observed the presence of a variable storing a unique identifier (UUID)\r\nwhich is appended to the URL from where EMPTYSPACE is downloaded. Figure 9 shows the major changes undergone by\r\nthe script.\r\nFigure 9: Evolution of explorer.ps1\r\nEMPTYSPACE\r\nEMPTYSPACE is a downloader that communicates with its C2 server over HTTP. It downloads and executes an executable\r\npayload served by the C2 server. The EMPTYSPACE beacon response is parsed as JSON containing a list of tasks, each of\r\nwhich specify a file to download to disk and execute.\r\nMandiant has identified multiple variants of EMPTYSPACE, typically named  Runtime Broker . These variants have been\r\nwritten in Node.js, .NET and Python. Yoroi noted an additional Go variant in their research.\r\nNODE.JS version\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 7 of 21\n\nThis version of  Runtime Broker.exe (SHA256: a4f20b60a50345ddf3ac71b6e8c5ebcb9d069721b0b0edc822ed2e7569a0bb40 )\r\nis  a downloader compiled with nexe, a utility that bundles a Node.js app into a single executable. The executable consists of\r\nNode.js runtime executable version 12.9.1 and the following items in the file overlay section:\r\nSHA256  4814393285c2afcd671dbdd53b3b2021963c32a09745f83ed894e5ae4e2764b8  at file offset  0x16B6E00 :\r\nJavaScript, the initialization component of  nexe .\r\nSHA256:  461d580a16cf1fa67b4ac751dfe9d36b2de3f13c97670b3b12641f20246ce4b3  at file offset  0x16BAC3A : DLL\r\nreferred to as drivelist.node. Its sole purpose appears to be to produce a drive listing for use in the JavaScript\r\npayload. \r\nSHA256  fae6192a0648a892c845d9498002ca79497ea58e5315d277f65f7b243f7110e4  at file offset  0x171683A : Main\r\nJavaScript payload referred to as  index.js ; bundled by webpack.\r\nRuntime Broker.exe will execute \" net session \" to determine whether the current process has elevated permissions. If\r\nrunning as an elevated process, the sample uses the named pipe  \\\\?\\pipe\\installSrvUniqID to ensure that only a single\r\ninstance of the executable is running.\r\nThe sample extracts and drops the overlay DLL (SHA256:\r\n461d580a16cf1fa67b4ac751dfe9d36b2de3f13c97670b3b12641f20246ce4b3 ) to  \u003ccurrent_directory\u003e/build/Release/drivelist.node .\r\nThe sample invokes the  drivelist.node  module to produce a drive listing. The sample iterates this listing to search for a\r\nremovable and readable/writeable drive whose mount point path contains the  Hangul Filler  character ( E3 85 A4  in\r\nUTF-8). This is possibly to determine whether the instance of the malware is the initial infection from a USB. The sample\r\nonly proceeds with the remaining functionality if such a path is found.\r\nIf not running as an elevated process, the sample sets the registry\r\nvalue  HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\\\\Node_Run  to the executable path and attempts to run\r\nas an elevated process. If already running as an elevated process, the sample deletes the aforementioned registry value and\r\nsends an HTTP POST request to  hxxps[:]//bobsmith[.]apiworld[.]cf/license.php  with a Base64-encoded beacon\r\ncontaining basic host information such as hostname, username, and localtime. The sample refers to itself as  CINSTALLER1  in\r\nthis beacon. The beacon response is parsed as JSON containing a list of tasks, each of which specify a file to download to\r\ndisk and execute.\r\nThe malware may additionally drop two batch files,  execute.bat and command.bat, to  %TEMP% during the process of\r\nattempting to run the sample as an elevated process.\r\n.NET version\r\nThis variant (SHA256: 8a492973b12f84f49c52216d8c29755597f0b92a02311286b1f75ef5c265c30d ) is an obfuscated .NET\r\nbased downloader. The malware can download and execute payloads from the C2 server, restart itself with elevated\r\nprivileges, delete downloaded payloads, and communicate system information to the C2 server. The malware, when\r\nexecuted, optionally expects the following command line argument: \r\nelevated_true\r\nIf the argument is provided, the malware will attempt to restart itself with elevated privileges. Otherwise, the malware\r\ncreates and checks for the following mutex to prevent multiple executions:\r\ncinstaller_2022\r\nThe malware then checks if a removable drive is mounted, and proceeds to find a directory labeled with the Hangul Filler\r\ncharacter ( E3 85 A4 ). At this point, the execution only proceeds if the directory exists. The next step is a download loop\r\nfor which a JSON object with the following structure is generated:\r\n{\r\n\"from\": \"CINSTALLER1\",\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 8 of 21\n\n\"path\": \"Malware path\",\r\n\"username\": \"\u003ccurrent user's Windows username\u003e\",\r\n\"cwd\": \"\u003ccurrent working directory\u003e\",\r\n\"time\": \"\u003cnumber of seconds since Unix epoch (January 1, 1970)\u003e\",\r\n\"temp\": \"Temporary path\",\r\n\"programs\": \"Program Files path\"\r\n}\r\nThe malware will then base64 encode the generated JSON and send it in a POST request to the C2 server. The configured\r\nC2 server for this sample is as follows:\r\nhxxps://bobsmith.apiworld[.]cf/license.php\r\nThe base64 string is prepended with \"AA\" such that the POST data looks as follows:\r\n\"AA\" \u003cbase64 encoded JSON\u003e \"==\"\r\nThe malware expects the C2 server to return a collection of objects. For each object in the collection, it extracts specific\r\ndata: a link, a path, a command (cmd), arguments for the command, and a deletion flag (delete).\r\nFor each object in the received collection, if a URL and path are provided, the program attempts to download a file from the\r\nURL to the specified path. This download is retried indefinitely every 5 seconds in case of failure. If a command (cmd) is\r\nspecified, the program attempts to execute it with the provided arguments, running it in a hidden window and without\r\ncreating a new window. If the deletion flag (delete) is set and both the URL and path are provided, the program attempts to\r\ndelete the downloaded file after execution.\r\nIn at least one investigation, Mandiant has observed this version of EMPTYSPACE relaying on additional resources on the\r\nhost, most likely dropped during the initial infection. These are bootstrap.pyc, which is a Python compiled version of\r\nEMPTYSPACE with a similar capability of communicating with a list of embedded C2 domains and the QUIETBOARD\r\nbackdoor. EMPTYSPACE interacts with these files via an intermediary executable, a Python wrapper named\r\n\" RuntimeBroker .exe \" (vs \" Runtime Broker.exe \") located in C:\\Windows.\r\nPython Version (Bootstrap.pyc)\r\nOne of the versions analyzed by Mandiant Managed Defense for  bootstrap.pyc is shown in Figure 10 (decompiled code).\r\nThe BOOTSTRAP_VERSION is set to ‘PYBOOTSTRAP4’, suggesting the existence of other versions. With this in mind,\r\nmore open source research revealed three other versions, each containing essentially the same code but with different\r\ndomains.\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 9 of 21\n\nFigure 10: bootstrap.pyc V4\r\nThe code continuously attempts to reach a specific URL ( hxxp://google[.]com/generate_204 ) with a 30-second timeout.\r\nIf unsuccessful, it retries after 2 seconds. This check likely verifies internet connectivity before proceeding.\r\nNext, it creates a variable  request_data containing encoded information:\r\nEncodes a JSON dictionary with user details, including username and path of the executable file.\r\nAdds \"AA\" and \"==\" at the beginning and end of the encoded data, exactly the same way the .NET version of\r\nEMPTYSPACE is formatting the data before sending it to the C2 server.\r\nOnce data is prepared, the code iterates over a list of URLs, attempting to send POST requests containing\r\nthe  request_data .  \r\nUpon successful communication, it attempts to decode the server's response using Base64 and then deserialize it using\r\nthe marshal.loads function. It executes the deserialized data using the exec function.\r\nVersion 1\r\nhxxp[://]google[.]com/generate_204\r\nhxxps[://]lucaespo[.]altervista[.]org/updater[.]php\r\nhxxp[://]studiofotografico35mm[.]altervista[.]org/updater[.]php\r\nhxxp[://]wjecpujpanmwm[.]tk/updater[.]php\r\nVersion 2\r\nhxxp[://]google[.]com/generate_204\r\nhxxps[://]captcha[.]grouphelp[.]top/updater[.]php\r\nhxxps[://]captcha[.]tgbot[.]it/updater[.]php\r\nhxxps[://]wjecpujpanmwm[.]tk/updater[.]php\r\nhxxp[://]studiofotografico35mm[.]altervista[.]org/updater[.]php\r\nhxxp[://]ncnskjhrbefwifjhww[.]tk/updater[.]php\r\nhxxp[://]geraldonsboutique[.]altervista[.]org/updater[.]php\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 10 of 21\n\nVersion 3\r\nhxxp[://]google[.]com/generate_204\r\nhxxps[://]monumental[.]ga/wp-admin[.]php\r\nhxxp[://]studiofotografico35mm[.]altervista[.]org/updater[.]php\r\nhxxp[://]ncnskjhrbefwifjhww[.]tk/updater[.]php\r\nhxxp[://]geraldonsboutique[.]altervista[.]org/updater[.]php\r\n Version 4\r\nhxxp[://]google[.]com/generate_204\r\nhxxps[://]luke[.]compeyson[.]eu[.]org/wp-admin[.]php\r\nhxxp[://]studiofotografico35mm[.]altervista[.]org/updater[.]php\r\nhxxps[://]davebeerblog[.]eu[.]org/wp-admin[.]php\r\nhxxp[://]geraldonsboutique[.]altervista[.]org/updater[.]php\r\nTable 1: URLs contained in the bootstrap.pyc versions\r\nQUIETBOARD (Program.pyz)\r\nQUIETBOARD is a Python based pre-compiled multi-component backdoor capable of arbitrary command execution,\r\nclipboard content manipulation for crypto currency theft, USB/removable drive infection, screenshotting, system\r\ninformation gathering, and communication with the C2 server. Additionally, the backdoor has the capability of modular\r\nexpansion and running independent Python based code/modules. All these capabilities are provided and managed via its\r\nvarious components: start, coronausb, cboard, runservice, executer, info and connection.\r\nThe aforementioned modules are initiated via the primary component start, which creates multiple threads to manage each\r\nof these components in parallel. Following is a breakdown of what each component entails.\r\nstart\r\nThe start module in the malware framework serves as an orchestrator or initializer for the other components. During its\r\nexecution, the module: \r\n1. Checks for the existence of a lock file (program.lock) in the current directory. If this lock file exists, it's deleted. If it\r\ncannot be deleted, the script exits immediately, which is likely a mechanism to prevent multiple instances of the\r\nmalware from running simultaneously.\r\n2. Checks if a file named overload exists in the current directory. If it does, the script reads the content of this file,\r\ndecodes it from Base64, unmarshals it, and executes it using the executer module.\r\n3. Checks if a directory named runs exists; if not, it creates one. If it exists, the script iterates through all files contained\r\nin this directory. Each file is treated as a script: it's read, decoded, unmarshalled, and executed similarly to\r\nthe overload file. This directory could be used for executing multiple scripts, possibly allowing for modular\r\nexpansion of the malware’s capabilities.\r\nStarts the coronausb, cboard, and runservice modules in separate threads and begins the operation of the connection\r\nmodule synchronously.\r\ncoronausb\r\nThis component monitors and infects removable drives. It creates a hidden folder in the attached removable drives, moves\r\nexisting data into the newly created folder, and creates a deceptive LNK shortcut that is made to look like the default\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 11 of 21\n\nMicrosoft Windows drive icon. The name of the shortcut can be either of two patterns depending on whether a volume label\r\nis present or not:\r\n\u003cvolume_label\u003e (\u003ctotal_size_in_gb\u003eGB).lnk\r\n\u003cdrive_letter\u003e (\u003ctotal_size_in_gb\u003eGB).lnk\r\nThis shortcut is linked to a PowerShell script that is written inside the USB drive and is named explorer.ps1.\r\nThe hidden folder is created as follows:\r\nPython\r\nempty_character = ''\r\nhidden_folder = drive + '\\\\' + empty_character\r\nThis empty_character mechanism results in the generation of the Hangul Filler character ( E3 85 A4 ) which visually\r\nshows up as a whitespace making the directory path appear as \" D:\\ \" (assuming D to be the removable drive).\r\nThere is also a mechanism which checks if an older version of  explorer.ps1 already exists on any of detected USB drives\r\nand removes it, replacing it with a new version. This ensures the “update” of older infected removable drives.\r\ncboard\r\nThis component acts as a crypto stealer by continuously monitoring and altering the clipboard content. It tries to detect\r\nknown patterns for crypto wallet addresses and replace them with its own wallet addresses with the intention of stealing\r\ncrypto from any transaction the victim might conduct.\r\nThe following table lists a general breakdown of the patterns matched, and the replaced wallet addresses:\r\nTargeted\r\nCryptocurrency\r\n(likely)\r\nMatching Pattern Replacement Wallet Address\r\nTotal asset value ($) as\r\nof January 29th, 2023\r\nMonero\r\n[48][1-9A-HJ-NP-Za-km-z]{93}\r\n49FEMQZdLSJXtv6EoRPRhzjHfcihJKDy\r\n9bLBv8dvF5HPdyKSimV9MpfgU8A35orn\r\nNF87NGgVHTsYTBmsMXN8XFT7FghFy3F\r\nN/A\r\nEthereum 0x[a-fA-F0-9]{40}\r\n0xeA1b0564456cdA8fE1\r\nD17306D7D5a59Ca1fC83E6\r\n$5,571.20\r\nDogecoin\r\nD{1}[5-9A-HJ-NP-U]\r\n{1}[1-9A-HJ-NP-Za-km-z]{32}\r\nDHhrFwsiHhm4GWN\r\n9Fn4tkGXiJUmfigso7Q\r\n$224.09\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 12 of 21\n\nBitcoin\r\n(bc1\\|[13])[a-zA-HJ-NP-Z0-9]{25,39}bc1qk55vk7wjgzg3pmxl\r\nh59rv5dlgewd9jem5nrt4w\r\n$50,042.15.\r\nTable 2: Wallet addresses embedded in the cboard module\r\nAdditionally, Mandiant has observed the Bitcoin address bc1qk55vk7wjgzg3pmxlh59rv5dlgewd9jem5nrt4w  being injected in\r\nthe HTML code of multiple Italian websites, mainly connected to Italian universities, substantiating the financial motives\r\nbehind the threat actors’ actions.\r\nThe Ethereum and Doge addresses had their first transaction on the same date, within one hour of each other, on January 10,\r\n2022. The Bitcoin address was first used towards the end of 2022, on December 11.\r\nrunservice\r\nThis component is primarily meant to dynamically fetch and execute additional Python code from the C2 server. The\r\nmalware generates the following JSON based on information gathered by the info module:\r\njson\r\n{\r\n\"uuid\": \u003cunique_computer_id\u003e,\r\n\"username\": \u003cusername\u003e,\r\n\"install_date\": \u003cinstall_data\u003e,\r\n\"start_time\": \u003cinfection_time\u003e,\r\n\"installed_from\": \u003csource-machine-uuid\u003e,\r\n\"specs\": \u003chardware_specs\u003e,\r\n\"wifi\": \u003cwifi_ssid\u003e,\r\n\"coronausb\": \u003ccoronausb_boolean_flag\u003e # set to True by default\r\n}\r\nThe JSON is Base64 encoded and AES encrypted with the following key in CBC mode:\r\nKey:  4lZYQ/POapYTZka0gVM/rg==\r\nThe malware then proceeds to send the encrypted JSON in a POST request to the following C2 server.\r\nhxxps://luke.compeyson.eu[.]org/runservice/api/public.php\r\nThe malware expects to receive Python code in response, which it executes and communicates back the result of to the\r\nfollowing URL in a post request.\r\nhxxps://luke.compeyson.eu[.]org/runservice/api/public_result.php\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 13 of 21\n\nThis fetch and execute operation continues indefinitely until the server responds with data containing a \"continue\" flag set to\r\nFalse.\r\nexecuter\r\nThis component contains the functionality to dynamically execute Python code and is used by the runservice module to\r\nexecute the received Python payloads.\r\ninfo\r\nThe info component of the malware is designed to gather and assemble various pieces of information about the infected\r\ncomputer. It then structures this information into a JSON object, which is later used in the runservice component, and is\r\nalso communicated back to the C2 server by the connection component.\r\nThe module compiles the following host information:\r\nGenerates a unique id for the system and stores it in a file named \" cUuid.dat \" (if one already does not exist).\r\nAttempts to read the installation date from a file named \" instDate.dat \", and creates and writes to it if one is not\r\nalready available.\r\nRetrieves system specifications by executing the following WMI queries: \r\n1. Select * from Win32_OperatingSystem \r\n2. Select * from Win32_ComputerSystem \r\n3. Select * from Win32_Processor \r\n4. Select * from Win32_VideoController\r\nRetrieves WIFI SSIDs by running the command \" netsh wlan show interfaces \"\r\nRetrieves BSSID information by running the command \" netsh wlan show networks mode=bssid \"\r\nAttempts to geo locate the infected computer by querying the URL:\r\nhxxps://www.googleapis[.]com/geolocation/v1/geolocate?key=AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw\r\nAttempts to read a UUID from a file named \" from_machine_uuid.dat \" which from context might contain the UUID\r\nof the source infection machine.\r\nconnection\r\nThe connection component communicates back all the gathered information from the victim system (generated by the info\r\nmodule) to the C2 server, optionally including a screenshot of the system. It can further keep operating in a loop with a sleep\r\ntime specified by the C2 server, and which is by default set to 0.1s. Moreover, the connection module can execute arbitrary\r\nPython code received from the C2 server in the same loop using the executer module, similar to runservice. However, this\r\nmodule has the added functionality of either executing the received code synchronously or asynchronously, in a newly\r\ngenerated thread, based on the setting received from the configured C2 server: \r\nhxxps://eu1.microtunnel[.]it/c0s1ta/index.php\r\nMandiant identified multiple versions of QUIETBOARD as well. One earlier version contained only the coronausb module,\r\nwhile another had all the modules previously described except for runservice. This might suggest the order in which the\r\nthreat actor has developed each module, starting with the capability of infecting USB drives and adding more functionality\r\non top of it. Having the runservice module as a last addition is telling of how the threat actor evolved, gained confidence\r\nand updated the code with a C2 capability.\r\nIn one particular infection, after months of just beaconing activity, QUIETBOARD dropped an open-source coinminer,\r\nfurther supporting the financial gain angle for the threat actor. \r\nThreat Actor Spotlight: UNC4990\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 14 of 21\n\nMandiant has collected intelligence surrounding a campaign and additional likely related activity conducted by UNC4990\r\ntargeting organizations located in Italy, but based in Europe and the U.S,. across multiple industries, including health,\r\ntransportation, construction, and logistics. Italian organizations appear to be primarily impacted by this activity. \r\nMandiant assesses with medium confidence that UNC4990 is a financially motivated threat actor operational since at least\r\n2020. Based on the extensive use of Italian infrastructure throughout UNC4990 operations, including using Italian blogging\r\nplatforms for C2, we believe this actor to be operating out of Italy. \r\nThough the group’s TTPs have evolved over time, UNC4990 operations generally involve widespread USB infection\r\nfollowed by the deployment of the EMPTYSPACE downloader. During these operations, the cluster relies on third-party\r\nwebsites such as GitHub, Vimeo, and Ars Technica to host encoded additional stages, which it downloads and decodes via\r\nPowerShell early in the execution chain. \r\nIt is unclear whether UNC4990 is responsible only for initial access and foothold. In at least one investigation, Mandiant has\r\nobserved the deployment of a Coinminer following months of inactivity, leaving the end goal for UNC4990 operations\r\nopen. \r\nConclusion\r\nMandiant observed a clear evolution of the TTPs from the early stages of the campaign to its current form.\r\nStarting off with the initial payload served in explorer.ps1, where a custom decoding scheme was developed to the point\r\nwhere it got replaced with asymmetric encryption and the addition of the capability to track infected devices.\r\nFurthermore, the analysis of both EMPTYSPACE and QUIETBOARD suggests how the threat actors took a modular\r\napproach in developing their toolset. QUIETBOARD started by only having one module and then more functionality was\r\nincrementally added. Similarly, the Python variant of EMPTYSPACE shows clear signs of versioning. The use of multiple\r\nprogramming languages to create different versions of the EMPTYSPACE downloader and the URL change when the\r\nVimeo video was taken down show a predisposition for experimentation and adaptability on the threat actors’ side. \r\nDetection Opportunities\r\nDetection\r\nOpportunity\r\nMITRE\r\nATT\u0026CK®\r\nTechnique\r\nEvent Details\r\nLNK shortcut file\r\nspawning\r\nPowerShell script\r\nfrom command\r\nline\r\nT1204\r\nT1059.001\r\nParent Process: C:\\Windows\\explorer.exe\r\nProcess: C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\r\nCommand Line Examples:\r\n\"powershell.exe\" -windowstyle hidden -NoProfile -nologo -\r\nExecutionPolicy ByPass -File explorer.ps1\r\npowershell.exe -windowstyle hidden -NoProfile -nologo -ExecutionPolicy\r\nByPass -File explorer.ps1\r\n\"C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -\r\nwindowstyle hidden -NoProfile -nologo -ExecutionPolicy ByPass -File\r\nexplorer.ps1\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 15 of 21\n\nSuspicious\r\nPowerShell\r\nnetwork\r\nconnections\r\nT1071\r\nT1059.001\r\nPowershell connections to vimeo[.]com and arstechnica[.]com \r\nRuntime\r\nBroker.exe binary\r\nfile writes with\r\nwhitespaces within\r\nthe binary name or\r\nbefore the file\r\nextension\r\nT1036.005\r\nFile Write: \r\nC:\\Users\\\u003cuser\u003e\\AppData\\Local\\Temp\\Runtime Broker.exe\r\nC:\\Windows\\RuntimeBroker .exe\r\nYARA-L Rules\r\nrule M_YARAL_UNC4990_NETWORK_INDICATORS\r\n{\r\n meta:\r\n author = \"Mandiant\"\r\n description = \"This rule is for hunting purposes\r\nonly and has not been tested to run in a production environment.\"\r\n severity = \"Low\"\r\n reference =\r\n\" https://cloud.google.com/chronicle/docs/detection/yara-l-2-0-overview\"\r\n events:\r\n (\r\n $e.metadata.event_type = \"NETWORK_CONNECTION\" or\r\n $e.metadata.event_type = \"NETWORK_DNS\" or\r\n $e.metadata.event_type = \"NETWORK_HTTP\"\r\n ) and\r\n (\r\n (\r\n $e.target.hostname = `bobsmith.apiworld.cf` nocase and\r\n re.regex($e.target.url, `license\\.php`) nocase and\r\n $e.network.http.method = `POST` nocase\r\n ) or\r\n (\r\n re.regex($e.target.url, `/updater\\.php\\?from=USB1`)\r\nnocase and\r\n (\r\n $e.target.hostname = `evinfeoptasw.dedyn.io` nocase or\r\n $e.target.hostname = `wjecpujpanmwm.tk` nocase\r\n )\r\n ) or\r\n (\r\n re.regex($e.principal.process.file.full_path, `powershell\\.exe$`)\r\nnocase and\r\n (\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 16 of 21\n\nre.regex($e.target.hostname, `vimeo\\.com`) nocase or\r\n re.regex($e.target.hostname, `arstechnica\\.com`) nocase\r\n )\r\n ) or\r\n (\r\n re.regex($e.principal.process.file.full_path, `powershell\\.exe$`)\r\nnocase and\r\n (\r\n $e.network.dns.questions.name = `vimeo.com` nocase or\r\n $e.network.dns.questions.name = `arstechnica.com` nocase\r\n )\r\n )\r\n )\r\n condition:\r\n $e\r\n}\r\nrule M_YARAL_UNC4990_HOST_INDICATORS_1\r\n{\r\n meta:\r\n author = \"Mandiant\"\r\n description = \"This rule is for hunting purposes only\r\nand has not been tested to run in a production environment.\"\r\n severity = \"Low\"\r\n reference =\r\n\" https://cloud.google.com/chronicle/docs/detection/yara-l-2-0-overview\"\r\n events:\r\n (\r\n $e.metadata.event_type = \"FILE_CREATION\" or\r\n $e.metadata.event_type = \"FILE_MODIFICATION\" or\r\n $e.metadata.event_type = \"REGISTRY_CREATION\" or\r\n $e.metadata.event_type = \"REGISTRY_DELETION\" or\r\n $e.metadata.event_type = \"REGISTRY_MODIFICATION\"\r\n ) and\r\n (\r\n re.regex($e.target.file.full_path, `RuntimeBroker\\s\\.exe`)\r\nnocase or\r\n re.regex($e.target.file.full_path, `\\\\Windows\\\\RuntimeBroker \\.exe`)\r\nnocase or\r\n re.regex($e.target.file.full_path, `Temp\\\\Runtime Broker\\.exe`)\r\nnocase or\r\n re.regex($e.target.file.full_path, `WinSoft Update Service`)\r\nnocase or\r\n re.regex($e.target.registry.registry_key,\r\n`HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\\\\Node_Run`)\r\nnocase\r\n \r\n )\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 17 of 21\n\ncondition:\r\n $e\r\n}\r\nrule M_YARAL_UNC4990_HOST_INDICATORS_2\r\n{\r\n meta:\r\n author = \"Mandiant\"\r\n description = \"This rule is for hunting purposes only\r\nand has not been tested to run in a production environment.\"\r\n severity = \"Low\"\r\n reference =\r\n\" https://cloud.google.com/chronicle/docs/detection/yara-l-2-0-overview\"\r\n events:\r\n $e.metadata.event_type = \"PROCESS_LAUNCH\"\r\n re.regex($e.target.process.file.full_path, `powershell\\.exe$`)\r\nnocase and\r\n re.regex($e.principal.process.file.full_path, `explorer\\.exe$`)\r\nnocase and\r\n re.regex($e.target.process.command_line, `\\-windowstyle hidden\r\n\\-NoProfile \\-nologo \\-ExecutionPolicy ByPass \\-File explorer\\.ps1`) nocase\r\n condition:\r\n $e\r\n}\r\nIndicators of Compromise\r\nHost-Based IOCs\r\nIOC SHA-256\r\nAssociated\r\nMalware\r\nFamily\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 18 of 21\n\nexplorer.ps1\r\n72f1ba6309c98cd52ffc99dd15c45698dfca2d6ce1ef0bf262433b5dfff084be\r\n98594dfae6031c9bdf62a4fe2e2d2821730115d46fca61da9a6cc225c6c4a750\r\nd09d1a299c000de6b7986078518fa0defa3278e318c7f69449c02f177d3228f0\r\n7c793cc33721bae13e200f24e8d9f51251dd017eb799d0172fd647acab039027\r\n6fb4945bb73ac3f447fb7af6bd2937395a067a6e0c0900886095436114a17443\r\nPowerShell\r\nScript\r\n%TEMP%\\Runtime\r\nBroker.exe\r\na4f20b60a50345ddf3ac71b6e8c5ebcb9d069721b0b0edc822ed2e7569a0bb40\r\nEMPTYSPA\r\nDownloader\r\n(Node.JS\r\nVariant)\r\nRuntime Broker.exe 8a492973b12f84f49c52216d8c29755597f0b92a02311286b1f75ef5c265c30d\r\nEMPTYSPA\r\nDownloader\r\n(.NET Varia\r\nC:\\Program Files\r\n(x86)\\WinSoft Update\r\nService\\bootstrap.pyc\r\nV1:\r\n060882f97ace7cb6238e714fd48b3448939699e9f085418af351c42b401a1227\r\nV2:\r\n8c25b73245ada24d2002936ea0f3bcc296fdcc9071770d81800a2e76bfca3617\r\nV3:\r\nb9ffba378d4165f003f41a619692a8898aed2e819347b25994f7a5e771045217\r\nV4:\r\n84674ae8db63036d1178bb42fa5d1b506c96b3b22ce22a261054ef4d021d2c69\r\nEMPTYSPA\r\nDownloader\r\n(Python\r\nVariant)\r\nC:\\Program Files\r\n(x86)\\WinSoft Update\r\nService\\program.pyz\r\n15d977dae1726c2944b0b4965980a92d8e8616da20e4d47d74120073cbc701b3\r\n26d93501cb9d85b34f2e14d7d2f3c94501f0aaa518fed97ce2e8d9347990decf\r\n26e943db620c024b5e87462c147514c990f380a4861d3025cf8fc1d80a74059a\r\nQUIETBOA\r\nBackdoor\r\nC:\\windows\\runtimebroker\r\n.exe\r\n71c9ce52da89c32ee018722683c3ffbc90e4a44c5fba2bd674d28b573fba1fdc\r\nQUIETBOA\r\nassociated fi\r\nC:\\Program Files\r\n(x86)\\pyt37\\python37.zip\r\n539a79f716cf359dceaa290398bc629010b6e02e47eaed2356074bffa072052f\r\nQUIETBOA\r\nassociated fi\r\nNetwork-Based IOCs\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 19 of 21\n\nURL\r\nhxxps://bobsmith.apiworld[.]cf/license.php\r\nhxxps://arstechnica[.]com/civis/members/frncbf22.1062014/about/\r\nhxxps://evinfeoptasw.dedyn[.]io/updater.php\r\nhxxps://wjecpujpanmwm[.]tk/updater.php?from=USB1\r\nhxxps://eldi8.github[.]io/src.txt\r\nhxxps://evh001.gitlab[.]io/src.txt\r\nhxxps://vimeo[.]com/api/v2/video/804838895.json\r\nhxxps[://]monumental[.]ga/wp-admin[.]php\r\nhxxp[://]studiofotografico35mm[.]altervista[.]org/updater[.]php\r\nhxxp[://]ncnskjhrbefwifjhww[.]tk/updater[.]php\r\nhxxp[://]geraldonsboutique[.]altervista[.]org/updater[.]php\r\nhxxps[://]wjecpujpanmwm[.]tk/updater[.]php\r\nhxxps[://]captcha[.]grouphelp[.]top/updater[.]php\r\nhxxps[://]captcha[.]tgbot[.]it/updater[.]php\r\nhxxps://luke.compeyson.eu[.]org/runservice/api/public.php\r\nhxxps[://]luke[.]compeyson[.]eu[.]org/wp-admin[.]php\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 20 of 21\n\nhxxps://luke.compeyson.eu[.]org/runservice/api/public_result.php\r\nhxxps://eu1.microtunnel[.]it/c0s1ta/index.php\r\nhxxps[://]davebeerblog[.]eu[.]org/wp-admin[.]php\r\nhxxps://lucaespo.altervista[.]org/updater.php\r\nhxxps://lucaesposito.herokuapp[.]com/c0s1ta/index.php\r\nhxxps://euserv3.herokuapp[.]com/c0s1ta/index.php\r\nMandiant Security Validation Actions\r\nOrganizations can validate their security controls using the following actions with Mandiant Security Validation.\r\nVID Name\r\nA106-893 Host CLI - UNC4990, EMPTYSPACE, Persistence via Registry\r\nA106-896 Malicious File Transfer - UNC4990, EMPTYSPACE, Download, Variant #1\r\nA106-898 Command and Control - UNC4990, EMPTYSPACE, DNS Query, Variant #1\r\nA106-901 Command and Control - UNC4990, DNS Query, Variant #1\r\nA106-905 Protected Theater - UNC4990, EMPTYSPACE, Execution\r\nAcknowledgement\r\nBlas Kojusner, Dimiter Andonov, Elvis Miezitis, Mike Hunhoff, Moritz Raabe, Mustafa Nasser, Nikolay Marinov\r\nPosted in\r\nThreat Intelligence\r\nSource: https://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nhttps://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware\r\nPage 21 of 21",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MISPGALAXY",
		"Malpedia"
	],
	"references": [
		"https://www.mandiant.com/resources/blog/unc4990-evolution-usb-malware"
	],
	"report_names": [
		"unc4990-evolution-usb-malware"
	],
	"threat_actors": [
		{
			"id": "b9d57799-0e71-4c6e-9b95-4c0cf0970366",
			"created_at": "2024-02-02T02:00:04.030607Z",
			"updated_at": "2026-04-10T02:00:03.531892Z",
			"deleted_at": null,
			"main_name": "UNC4990",
			"aliases": [],
			"source_name": "MISPGALAXY:UNC4990",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434785,
	"ts_updated_at": 1775791775,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/3e252b8f39925c443158215b2a18dec0fa0a82b9.pdf",
		"text": "https://archive.orkl.eu/3e252b8f39925c443158215b2a18dec0fa0a82b9.txt",
		"img": "https://archive.orkl.eu/3e252b8f39925c443158215b2a18dec0fa0a82b9.jpg"
	}
}