Malware

FrostyGoop’s Zoom-In: A Closer Look into the Malware Artifacts, Behaviors and Network Communications

Clock Icon 14 min read

Executive Summary

In July 2024, the operational technology (OT)-centric malware FrostyGoop/BUSTLEBERM became publicly known, after attackers used it to disrupt critical infrastructure. The outage occurred after the Cyber Security Situation Center (CSSC), affiliated with the Security Service of Ukraine, disclosed details [PDF] of an attack on a municipal energy company in Ukraine in early 2024.

FrostyGoop is the ninth reported OT-centric malware, but the first that used Modbus TCP communications to impact the power supply to heating services for over 600 apartment buildings. FrostyGoop can be used both within a compromised perimeter and externally if the target device is accessible over the internet. FrostyGoop sends Modbus commands to read or modify data on industrial control systems (ICS) devices, causing damage to the environment where attackers installed it.

Based on this reporting, we conducted a deeper analysis and uncovered new samples of FrostyGoop and other related indicators. These new indicators include configuration files and libraries used by the malware, as well as artifacts associated with an infection. We also investigate network communications and provide new insights based on open-source intelligence (OSINT) data and our own telemetry.

OT malware is an increasing concern of security professionals across the globe, and FrostyGoop provides a notable case study of this growing threat.

Palo Alto Networks customers are better protected from the threats discussed in this article through our products and services such as the following:

If you think you might have been compromised or have an urgent matter, contact the Unit 42 Incident Response team.

Related Unit 42 Topics JSON, IoT Security, Russia

Technical Analysis of FrostyGoop

Attackers employed this malware associated with Russian actors in a cyberattack that caused a two-day heating system outage affecting over 600 apartment buildings in Ukraine, during sub-zero temperatures.

According to an open-source report, attackers made the initial compromise through a vulnerability in a MikroTik router. However, we have not confirmed this delivery method and bad actors might instead have delivered the malware via OT devices exposed to the internet.

FrostyGoop makes use of the Modbus TCP protocol to interact directly with ICS/OT devices, and therefore it is considered an ICS-centric malware. This is the ninth known ICS-centric malware.

In addition, Modbus is one of the most common protocols used in critical infrastructure. During this attack, the adversaries dispatched Modbus commands to ENCO control devices, leading to inaccurate measurements and system malfunctions. Remediating these issues took nearly two days.

Although bad actors used the malware to attack ENCO control devices, the malware can attack any other type of device that speaks Modbus TCP. Our telemetry indicates that 1,088,175 Modbus TCP devices were exposed to the internet from Sept. 2-Oct. 2, 2024, and 6,211,623 devices were exposed overall.

The details needed by FrostyGoop to establish a Modbus TCP connection and send Modbus commands to a targeted ICS device can be provided as command-line arguments or included in a separate JSON configuration file.

Malware Samples Analysis

FrostyGoop is compiled using the Go programming language, sometimes referred to as Golang. The malware uses a relatively obscure open-source Modbus implementation.

Further analysis of the Modbus library revealed this implementation does not natively support supplying arguments using a JSON file, making this a strong identifier for the malware. Moreover, the JSON object structure follows a specific format based on the commands this malware supports. FrostyGoop also contains capabilities for logging the output to a console or to a JSON file.

Attackers can supply two types of parameters to FrostyGoop:

  • The first type of parameter consists of the possible operations an attacker can execute toward the registers of a Modbus device
  • The second parameter consists of timing configurations.

Figure 1 shows an example of the first type of parameter for an operation using Tasks and Iplist under the register for main::main.TaskList___runtime.structtype_fields.

Screenshot of a computer screen displaying code in Binary Ninja with highlighted sections and annotations pointing to specific lines, including terms like "main:main.TaskList," "Iplist," and "Tasks.
Figure 1. Binary Ninja showing FrostyGoop operations for Tasks and Iplist under the main::main.TaskList___runtime.structtype_fields register.

Figure 2 shows an example of an operation for Code, Address, Count, Value and State under the register for main::main.TaskList___runtime.structtype_fields.

Screenshot of code in Binary Ninja displaying hex code in blue text on a black background, annotated with labels such as 'Code', 'Count', 'Address', and 'Value' at various points.
Figure 2. Binary Ninja showing FrostyGoop operations for Code, Address, Count, Value and State under the main::main.TaskList___runtime.structtype_fields register.

Figure 3 shows the timing configuration for main.Cycle.getCycleConfig.

Screenshot of a computer code snippet in Binary Ninja featuring functions and variables related to time parsing in a programming environment.
Figure 3. Binary Ninja showing FrostyGoop timing configuration in the registry entry under main.Cycle.getCycleConfig(main.Cycle x,main.Cmd cmd).

FrostyGoop also leverages Goccy’s go-json library, a faster JSON encoder and decoder compatible with the Go programming language standard encoding/json package. In addition, it incorporates a specific open-source execution controller named queues. The relative obscurity of this code means it can serve as another possible indicator of FrostyGoop.

Figure 4 shows our analysis of a Windows executable file for FrostyGoop within the tool Binary Ninja. This analysis reveals URLs from open-source libraries for modbus, go-json and queues.

A table displaying rows of data with columns, presenting various example URLs from GitHub repositories.
Figure 4. Open-source libraries: Modbus, go-json and queues.

Although not all FrostyGoop samples contain the strings shown in Figure 4, other strings contained within those libraries can serve as part of the detection for this malware.

FrostyGoop also implements a debugger evasion technique by checking the BeingDebugged value in Windows' Process Environment Block (PEB). Figure 5 shows this method in the disassembled code from a FrostyGoop sample. This method provides an alternative way to check the PEB's BeingDebugged flag without calling IsDebuggerPresent(). Attackers use this technique to detect and avoid debuggers used by malware analysts.

A screenshot of computer code in a debugging program, showcasing lines of assembly language with specific annotations and highlights; a section is marked by a red arrow pointing to the reference "PEB_BeingDebugged" in the code.
Figure 5. Disassembled code from a FrostyGoop sample showing a check for the PEB's BeingDebugged flag.

Go-encrypt.exe Sample Analysis

Our investigation revealed a Windows executable sample named go-encrypt.exe written in Go that was not FrostyGoop, but it originally appeared on the same approximate date that other indicators of FrostyGoop were reported. Command-line options for this software reveal the file is used to encrypt and decrypt JSON files as illustrated in Figure 6.

Command line interface on a screen showing the usage instructions for 'go-encrypt.exe', including options for encryption, decryption, and specifying input and output files.
Figure 6. Command-line options for go-encrypt.exe.

After executing go-encrypt.exe using the -encrypt argument, it creates two files:

  • An encrypted JSON
  • A 32-byte file containing a decryption key named key

Figure 7 shows the encryption, decryption and the generated key.

A screenshot of a computer terminal displaying file encryption and decryption commands, including execution of "encrypt.exe" and "decrypt.exe" on various files in the 'Downloads' directory under the user 'Asher'. The terminal lists file details.
Figure 7. Using go-encrypt.exe to encrypt and decrypt a JSON file.

Figure 8 shows the content of an encrypted JSON file generated by go-encrypt.exe.

A screenshot displaying the contents of a binary file in a hex editor, showing hexadecimal values alongside the corresponding decoded ASCII text on the right side.
Figure 8. An encrypted JSON file viewed in a hex editor.

Figure 9 shows a filtered list of processes generated by go-encrypt.exe in Process Monitor. We have highlighted when go-encrypt.exe created the decryption file named key and the 32 character content of this key file.

Screenshot of Process Monitor software showing a list of system processes and file operations, with focus on a registry change. A separate file explorer window is open displaying the contents of the Downloads folder. Red arrows point from the process monitor to the Downloads folder, and then to the key folder.
Figure 9. Process Monitor showing go-encrypt.exe generating the key file.

Decompiling go-encrypt.exe revealed it uses the Cipher Feedback (CFB) mode of the AES encryption algorithm to create the encryption/decryption key in the key file as shown in Figures 10 and 11.

Screenshot of computer code in an assembler-like language, displayed in a text editor with line numbers and hexadecimal values, possibly related to encryption functions.
Figure 10. Decompiled code of go-encrypt.exe showing its AES main encryption routine.
Screenshot of a programming IDE displaying code with variables and functions, mainly written in C++. The code contains several if-else statements, function parameters, and returns, highlighting the logic related to cryptographic operations. Various warnings are commented out within the code indicating potential issues or checks omitted during runtime. A red arrow points to line 59.
Figure 11. Decompiled code of go-encrypt.exe showing CFB mode.

As shown previously for the key generated in Figure 7, the key value is in decimal format. The decimal value of the key from Figure 7 is:

  • 71 76 90 67 120 104 86 98 85 97 88 54 88 50 75 77 71 78 116 89 74 66 51 50 75 103 70 117 56 100 117 88

We can decode these decimal numbers into the 32-byte value of the key through a variety of methods, like the Python script shown in Figure 12. This script will convert the binary values to hexadecimal.

Python code snippet in an IDE showing a function named 'to_hex' that converts a list to hexadecimal format.
Figure 12. Example of a Python script to convert the decimal value of the key to hexadecimal.

The 32-byte value of the key in hexadecimal is:

  • 47 4c 5a 43 78 68 56 62 55 61 58 36 58 32 4b 4d 47 4e 74 59 4a 42 33 32 4b 67 46 75 38 64 75 58

According to Go’s documentation for aes.NewCipher, a byte stream of 32 bytes corresponds to a 256-bit AES encryption in CFBmode. We confirmed the 32-byte hexadecimal value of the key from our example matches the ASCII value in the key file using CyberChef as shown below in Figure 13.

Screenshot of a CyberChef application interface showing various operations and windows. The main focus is on a conversion from Hexadecimal to ASCII, with annotations pointing out the hexadecimal value of the key, its conversion to ASCII, and a comparison with a matching ASCII string in a key file.
Figure 13. Using CyberChef to verify the hex value matches the ASCII value of the key file.

Although we cannot confirm go-encrypt.exe was used for the FrostyGoop attack, two circumstances indicate the attackers might have used it during this activity:

  • First, it is used to encrypt and decrypt JSON files, and encrypted JSON files are an essential element of FrostyGoop functionality.
  • Second, go-encrypt.exe first appeared in the wild around the same time as the FrostyGoop samples and the task_test.json file.

Therefore, attackers could have used this piece of software to conceal target information in JSON files for later use to perpetrate attacks.

Investigation of the Targeted Infrastructure

According to the Dragos report on FrostyGoop, they initially discovered this malware in April 2024. This report notes an example of a FrostyGoop configuration file named task_test.json.

Searching VirusTotal, we found one occurrence of task_test.json on Oct. 10, 2023. Pivoting on that file, we discovered Windows executable files that we subsequently identified as FrostyGoop and go-encrypt.exe.

Figure 14 shows the same first-seen date of Oct. 10, 2023, for task_test.json, go-encrypt.exe and the other Windows executable files.

Screenshot displaying a list of file download links, each with a unique alpha-numeric code, file size, number of downloads, and associated icons for different actions such as Export, Tools and more.
Figure 14. Malware samples and task_test.json detection timestamps in VirusTotal.

The data structure of task_test.json and its key/values are the format we would expect to be used as a configuration file by a FrostyGoop executable file. Our analysis of FrostyGoop samples indicates the malware performs read, write and write-multiple Modbus operations. The content of the task_test.json sample depicted in Figure 15 only shows read operations (Code 3).

Screenshot of JSON code data displaying an array called 'Tasks' with details of various entries that include 'Code', 'Count', and 'Value' fields. Some information is redacted.
Figure 15. The content of task_test.json used by a FrostyGoop malware sample.

The IP address contained in this JSON file corresponds to an ENCO control device located in Romania as noted.

Screenshot displaying network security analytics, highlighting an IP address (redacted) and case location in Craiova, Romania with a focus on Enco Therma Enviro Control 1.0. The image includes graphs showing open ports and service activities over several months.
Figure 16. Xpanse query indicating it is an ENCO device in Romania.

Widening our search for exposed ENCO devices, our telemetry revealed 32 IP addresses, all located in either Romania or Ukraine as noted in Figure 17.

Results of our Xpanse search for exposed ENCO devices revealed 32 IP addresses, a;; on Romania or Ukraine. Screenshot of Cortex XPANSE application interface showing search results for exposed ENCO devices in Romania, revealing 32 IP addresses. Red arrows point to the Ukraine IP address separated from the list of Romanian IP addresses.
Figure 17. Xpanse query of IP addresses with exposed ENCO devices.

The ENCO devices we discovered all have TCP port 23 exposed for Telnet. Telnet provides a communications and management interface that is considered obsolete because it has no built-in encryption.

Simply connecting to an exposed ENCO device over Telnet reveals an ENCO banner with a list of available commands as shown below in Figure 18. This provides a reportedly easy method to probe for and identify ENCO programmable logic controller (PLC) devices on the internet.

A screenshot of Enco Telnet Server v1.00 interface with a dark background and green text displaying various available network commands, among others, in a command-line interface format. Some information is redacted.
Figure 18. Telnet banner from an exposed ENCO device.

Figure 19 shows a portion of our Xpanse report covering details of the network services running on the server listed in task_test.json. This matches the exposed ports among the other ENCO exposed devices we discovered:

  • TCP ports 23 (Telnet)
  • 502 (Modbus)
  • 1024 (Router WebUI)
  • 37777 (ENCO connect port)
Bar chart showing the number of open ports from April to September with key details about specific ports, services, and device fingerprints listed in a table below. Notable ports include 23, 502, 1024, and 37777 with associated services shown.
Figure 19. Xpanse report for open ports on.

We can glean further information on the ENCO device by accessing it using a web browser and recording the traffic. Figure 20 shows a login screen shown when accessing the ENCO device from a web browser. By viewing the web traffic in Wireshark and examining the HTTP response headers, we find the router is being used as a web server and the name of the router is TL-LINK Wireless Lite N Router WR740N.

A series of screenshots. The top shows a web browser during a login attempt on a router's web access interface. This is accessing ENCO device from a web browser. The bottom screenshot shows web traffic viewed in Wireshark. It includes the IP address and TCP port for web access of the ENCO device. A red arrow points to the line that acts as a web server for ENCO device web access. Another arrow points to the name of the router for web access.
Figure 20. Information gleaned from accessing an ENCO device over a web browser.

According to the NIST website, versions 1 and 2 of the WR740N router's firmware are susceptible to a command injection vulnerability. However, there is no hard evidence to indicate that the attackers exploited this vulnerability in the July 2024 FrostyGoop attack.

Network Traffic Analysis

To analyze FrostyGoop traffic, we tested two samples using task_test.json as the configuration file. The two FrostyGoop samples have the following SHA256 hashes:

  • 5d2e4fd08f81e3b2eb2f3eaae16eb32ae02e760afc36fa17f4649322f6da53fb
  • a63ba88ad869085f1625729708ba65e87f5b37d7be9153b3db1a1b0e3fed309c

The task_test.json configuration file only has a function code value of 3, which represents a Modbus command to read the holding registers. Accordingly, the FrostyGoop samples only generated commands to read the holding registers of the targeted device at over TCP port 502.

Figure 21 shows an example of the Modbus traffic generated during our test of the FrostyGoop samples, filtered in Wireshark with a customized column display. It reveals Modbus traffic to over TCP port 502, as well as the four register values specified in the task_test.json configuration file:

  • 53370
  • 53882
  • 53760
  • 54272
Screenshot of a Modbus function code 3 operation in Wireshark software, displaying multiple queries for reading holding registers with detailed timestamps and values.
Figure 21. Example of Modbus traffic from our FrostyGoop sample test filtered in Wireshark.

Figure 22 shows an example of a Modbus function code 3 request to read values from the holding registers of the ENCO device, starting with the register number 53760 for the next 123 registries. The device responded with values from registry 53760-53882. These registry entries hold UINT16 values for unsigned integers that can range from 0-65535.

Two screenshots of Wireshark network analysis tool displaying Modbus protocol information, including data packets and highlighted request details for reading specific register values. On the left an arrow indicates where the Modbus read request of 123 register values starting at register 53760. On the right an arrow indicates the Modbus device responds with the values 123 registers from register 53760 through register 53882.
Figure 22. Modbus interaction with the hardware device.

We reverse engineered the samples to track down their functions. Our analysis revealed that the taskWorker function selects actions performed through the following function parameters:

  • read holding registers (3)
  • write (6)
  • writeMultiple (6)

If the JSON configuration file contains the number 1 as a word count value, only one register is returned. If it does not contain the number 1 as a word count value, more than one register is returned.

Figure 23 shows a code snippet from a FrostyGoop sample with the logic to select Modbus operations depending on the value provided:

  • 3 for read holding registers
  • 6 for write single holding register
  • 6 for write multiple holding registers operation
A screenshot of computer code in an Integrated Development Environment (IDE) with lines of code highlighted in yellow and green, focusing on function definitions and conditional statements.
Figure 23. Code snippet from a FrostyGoop sample showing how it implements Modbus operations.

Conclusion

With cyberattacks against ICS/OT devices and critical infrastructure increasing in recent years, the cybersecurity landscape in these types of environments has become increasingly dangerous. Countries like Ukraine, Romania, Israel, China, Russia and the United States have all been affected by attacks targeting their critical infrastructure. Prior to these incidents, cybersecurity in OT was not considered an essential part of their defensive operations.

The past decade has seen an increase in CS-centric malware, with FrostyGoop being the most recent prominent example. During this time frame, the number of OT and internet of things (IoT) devices exposed to the internet has drastically increased.

An increasing number of OT networks have been connected with IT networks to facilitate facilities management. This has unleashed new ways to perform cyberattacks that can not only damage the cyberspace realm, but also the physical world. Malicious actors can send control commands to field devices easily disguised as regular operations within network traffic, making the activity more difficult to detect and prevent.

For these reasons, we must implement security measures to prevent and mitigate these attacks. Palo Alto Networks customers are better protected from the threats discussed in this blog through the following products:

  • Industrial OT Security is designed to:
    • Use machine learning techniques to detect abnormal network traffic and abnormal behavior in engineering workstations and field devices
    • Raise alerts in the event of a compromised environment, based on anomalous command access
    • Generate alerts based on Modbus operations
    • Implement analytics rules for detection of suspicious traffic including anonymous telnet login, brute-force login attempts, default credentials usage
    • Cover and identify Common Vulnerabilities and Exposures (CVEs) in MikroTik and other common routers
    • Leverage upstream Advanced WildFire and Advanced Threat Prevention detections, along with IoT device detection capabilities, to detect malware command and control communication
    • Detect devices running vulnerable versions of firmware
  • Next-Generation Firewall (NGFW) and Advanced Threat Prevention are designed to:
    • Provide complete visibility and control of the applications in use across all users and devices in all locations all the time
    • Automatically reprogram your firewall with the latest intelligence using inline machine learning as well as the application and threat signatures
    • Implement rules TID 31667 (Modbus read coils) and TID 31668 (Modbus write coils), which allows administrators to identify abnormal devices performing Modbus operations
    • Implement MikroTik CVEs related to prevent remote code execution and command injection vulnerabilities from being exploited within the network
  • Advanced WildFire is designed to:
    • Identify malicious binaries and make verdict determinations when analyzing executing processes
    • Implement detection rules to identify, block and prevent deployment of FrostyGoop/BUSTLEBERM and its variants, as well as other ICS-centric ransomware and malware
  • Cortex Xpanse is designed to:
    • Provide a complete, accurate and continuously updated inventory of all global internet-facing assets, including exposed OT services and devices
    • Enable discovery, evaluation and mitigation of cyberattack surface risks
    • Facilitate evaluation of supplier risk
  • Cortex XDR and XSIAM are designed to:
    • Accurately detect threats with behavioral analytics and reveal the root cause to speed up investigations
    • Better protect against malware discussed in this article through Cortex XDR, including WildFire, Behavioral Threat Protection and the Local Analysis module
  • Unit 42 researchers at Palo Alto Networks are committed to discovering new malware and threats. We share our findings and feed the results back into our products and services, so our customers are better protected.

If you think you may have been compromised or have an urgent matter, get in touch with the Unit 42 Incident Response team or call:

  • North America Toll-Free: 866.486.4842 (866.4.UNIT42)
  • EMEA: +31.20.299.3130
  • APAC: +65.6983.8730
  • Japan: +81.50.1790.0200

Palo Alto Networks has shared these findings with our fellow Cyber Threat Alliance (CTA) members. CTA members use this intelligence to rapidly deploy protections to their customers and to systematically disrupt malicious cyber actors. Learn more about the Cyber Threat Alliance.

Indicators of Compromise

SHA256 hash:

  • 5d2e4fd08f81e3b2eb2f3eaae16eb32ae02e760afc36fa17f4649322f6da53fb
  • File size: 3.7 MB (3,699,200 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • a63ba88ad869085f1625729708ba65e87f5b37d7be9153b3db1a1b0e3fed309c
  • File size: 2.4 MB (2,439,680 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • 2fd9cb69ef30c0d00a61851b2d96350a9be68c7f1f25a31f896082cfbf39559a
  • File size: 3.4 MB (3,359,232 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • c64b67c116044708e282d0d1a8caea2360270a7fc679befa5e28d1ca15f6714c
  • File size: 2.0 MB (1,951,232 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • 91062ed8cc5d92a3235936fb93c1e9181b901ce6fb9d4100cc01167cdc08745f
  • File size: 2.5 MB (2,516,480 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • a25f91b6133cb4eb3ecb3e0598bbab16b80baa40059e623e387a6b1082d6f575
  • File size: 2.5 MB (2,515,968 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for FrostyGoop malware

SHA256 hash:

  • 9cf30d82a86a9485f7bbd0786a5de207cf4902691a3efcfc966248cb1e87d5b7
  • File size: 1.8 MB (1,773,568 bytes)
  • File type: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
  • File description: Windows executable file for go-encrypt.exe, likely used during previous FrostyGoop activity

SHA256 hash:

  • 06919e6651820eb7f783cea8f5bc78184f3d437bc9c6cde9bfbe1e38e5c73160
  • File size: 0.4 KB (379 bytes)
  • File type: JSON text data
  • File description: JSON file named task-test.json likely used to test go-encrypt.exe in July 2024 FrostyGoop attack

Additional Resources

Updated Nov. 19, 2024, at 9:00 a.m. PT to align statements with Dragos report.

Updated Nov. 20, 2024, at 10:00 a.m. PT to correct PANW product names.

Updated Nov. 20, 2024, at 10:54 a.m. PT to correct Modbus code.

Enlarged Image