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 Lviv in April 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:
- Zero Trust OT Security
- Palo Alto Networks Next-Generation Firewall with Advanced Threat Prevention
- Advanced WildFire
- Cortex Xpanse
- Cortex XDR and Cortex XSIAM
- Prisma Cloud
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 in January 2024. This incident caused a two-day heating system outage affecting over 600 apartment buildings in Lviv, Ukraine, during sub-zero temperatures.
According to an open-source report [PDF], 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.
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.
Figure 3 shows the timing configuration for main.Cycle.getCycleConfig.
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.
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.
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.
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.
Figure 8 shows the content of an encrypted JSON file generated by go-encrypt.exe.
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.
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.
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.
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.
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 [PDF], 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.
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).
The IP address contained in this JSON file corresponds to an ENCO control device located in Romania as noted.
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.
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.
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)
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.
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
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.
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 (16)
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
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:
- Zero Trust 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
- Impact of FrostyGoop ICS Malware on Connected OT Systems [PDF] – Dragos Intelligence Brief
- Simple ‘FrostyGoop’ malware responsible for turning off Ukrainians’ heat in January attack – SANS Blog
- go-json: Fast JSON encoder/decoder compatible with encoding/json for Go – goccy (Masaaki Goshima) on GitHub
- Queues: A simple sync.WaitGroup like queue and goroutine execution controller – hsblhsn (Hasibul Hasan) on GitHub
- How to Find and Probe ENCO PLCs on the Internet Just Like FrostyGoop malware – ZeroNtek
- CVE-2023-33538 Detail – NIST NVD