Detecting and removing WhisperGate malware

| by | Wazuh 4.3
Post icon

WhisperGate is a destructive file-wiper malware that is being used in a campaign targeting Ukrainian organizations. The malware targets Windows devices, corrupts the Master Boot Record (MBR), and the hard disk of the victim endpoint. It is designed to look like ransomware but doesn’t present a ransom recovery mechanism, which renders the device inoperable.

In this blog post, we explore the detection and removal of WhisperGate using several Wazuh features.

WhisperGate malware behavior

When WhisperGate malware infects an endpoint, its activities can be divided into 3 stages:

Stage 1: Overwrite Master Boot Record (MBR)

In stage 1, the primary objective of the malware is to overwrite the MBR with a malicious one. This malicious MBR takes effect once the endpoint is rebooted. The malware is often named stage1.exe and is commonly found in directories such as C:\PerfLogs, C:\ProgramData, C:\, and C:\temp. When the endpoint is restarted, a ransomware note will be displayed to the user. 

Stage 2: Download a file corrupter malware

In stage 2, the file corrupter malware file is downloaded from the C2 server. It is usually named stage2.exe and it retrieves the third stage malware from a Discord attachment.

Stage 3: Execute file corrupter 

In stage 3, the file corrupter downloaded by stage2.exe  is executed. After execution, it excludes the Windows C drive from being scanned by Microsoft Defender and stops the Microsoft Defender service. Finally, it locates and corrupts any file that matches a list of 191 file extensions in certain directories on the endpoint.

Requirements

  1. An installed Wazuh server.
  2. An installed and enrolled Wazuh agent on the Windows endpoint to be monitored. Python 3.10 and pip should also be installed here, with python added as an environment variable.

Detection with Wazuh 

We detect WhisperGate using the following techniques:

  • Detecting WhisperGate files using the File Integrity Monitoring (FIM) module.
  • Scanning malicious files using the Wazuh VirusTotal integration.

Detecting WhisperGate files using the File Integrity Monitoring (FIM) module

Using the FIM module, we configure Wazuh to monitor changes to files or folders on an endpoint. The module looks for modifications by comparing the added files’ checksums to the old ones. This will allow us to create a rule when the checksum of the files matches any of the malware files of WhisperGate. 

To simulate the malware behavior, we monitor one of the folders where the malware resides, by adding the following configuration to the “C:\Program Files (x86)\ossec-agent\ossec.conf” file on the Windows endpoint.

<syscheck>
  <directories check_all="yes" realtime="yes">c:\perfLogs</directories>
</syscheck>

To apply the changes, restart the agent by running the following PowerShell command as an administrator:

Restart-Service -Name wazuh

On the Wazuh manager, we add the following rules to the /var/ossec/etc/rules/local_rules.xml file. This will generate an alert when WhisperGate malware files are found in the monitored folder.

<group name="syscheck,malware,">

  <rule id="110001" level="10">
    <if_group>syscheck</if_group>
    <field name="sha256">a196c6b8ffcb97ffb276d04f354696e2391311db3841ae16c8c9f56f36a38e92</field>
    <description>Malware Hash Match: WhisperGate Stage 1 IOC Detected</description>
    <mitre>
      <id>T1204.002</id>
    </mitre>
  </rule>

  <rule id="110002" level="10">
    <if_group>syscheck</if_group>
    <field name="sha256">dcbbae5a1c61dbbbb7dcd6dc5dd1eb1169f5329958d38b58c3fd9384081c9b78</field>
    <description>Malware Hash Match: WhisperGate Stage 2 IOC Detected</description>
    <mitre>
      <id>T1204.002</id>
    </mitre>
  </rule>

  <rule id="110003" level="10">
    <if_group>syscheck</if_group>
    <field name="sha256" type="pcre2">9ef7dbd3da51332a78eff19146d21c82957821e464e8133e9594a07d716d892d|923eb77b3c9e11d6c56052318c119c1a22d11ab71675e6b95d05eeb73d1accd6</field>
    <description>Malware Hash Match: WhisperGate Stage 3 IOC Detected</description>
    <mitre>
      <id>T1204.002</id>
    </mitre>
  </rule>
  
</group>

We restart the wazuh manager service after adding the rules. This is done with the command below:

systemctl restart wazuh-manager

To simulate the malware behavior, we download the malware files to the monitored folder. It gets detected and we can see the alert on the Wazuh dashboard.

Scanning malicious files using the Wazuh VirusTotal integration

Using the VirusTotal integration, Wazuh automatically sends a request to the VirusTotal API with the hashes of files that are created or modified in the monitored folders. This is carried out using the following steps:

  • File monitoring: The FIM module detects file modification, deletion or addition, and triggers an alert.
  • VirusTotal API request: After FIM triggers an alert, the Wazuh manager queries the VirusTotal API with the hash of the file.
  • Alerting: If there is a match from VirusTotal, the Wazuh manager generates an alert.

To scan these files with VirusTotal, we add the block below to the Wazuh manager /var/ossec/etc/ossec.conf configuration file.

<ossec_config>
  <integration>
    <name>virustotal</name>
    <api_key>API_KEY</api_key> <!-- Replace with your VirusTotal API key -->
    <group>syscheck</group>
    <alert_format>json</alert_format>
  </integration>
</ossec_config>

We restart the Wazuh manager service after adding the VirusTotal configuration. This is done with the command below:

systemctl restart wazuh-manager

After enabling the integration, we get alerts whenever samples of WhisperGate malware are added to our monitored folder.

Note

The VirusTotal Public API is limited to 500 requests per day at a rate of 4 requests per minute.

Removing malicious files with active response

We need to modify the configuration of the Windows endpoint and the Wazuh manager to make use of our active response script. Once VirusTotal identifies a file as a threat, we can configure Wazuh to trigger an active response to remove the file from the endpoint. 

The os.remove() function in the active response script handles the removal of the malicious file.

os.remove(msg.alert["parameters"]["alert"]["data"]["virustotal"]["source"]["file"])

We make use of the active response script remove-threat.py with the following content:

#!/usr/bin/python3
# Copyright (C) 2015-2022, Wazuh Inc.
# All rights reserved.
 
import os
import sys
import json
import datetime
 
if os.name == 'nt':
    LOG_FILE = "C:\\Program Files (x86)\\ossec-agent\\active-response\\active-responses.log"
else:
    LOG_FILE = "/var/ossec/logs/active-responses.log"
 
ADD_COMMAND = 0
DELETE_COMMAND = 1
CONTINUE_COMMAND = 2
ABORT_COMMAND = 3
 
OS_SUCCESS = 0
OS_INVALID = -1
 
class message:
    def __init__(self):
        self.alert = ""
        self.command = 0
 
def write_debug_file(ar_name, msg):
    with open(LOG_FILE, mode="a") as log_file:
        log_file.write(str(datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')) + " " + ar_name + ": " + msg +"\n")
 
def setup_and_check_message(argv):
 
    # get alert from stdin
    input_str = ""
    for line in sys.stdin:
        input_str = line
        break
 
 
    try:
        data = json.loads(input_str)
    except ValueError:
        write_debug_file(argv[0], 'Decoding JSON has failed, invalid input format')
        message.command = OS_INVALID
        return message
 
    message.alert = data
 
    command = data.get("command")
 
    if command == "add":
        message.command = ADD_COMMAND
    elif command == "delete":
        message.command = DELETE_COMMAND
    else:
        message.command = OS_INVALID
        write_debug_file(argv[0], 'Not valid command: ' + command)
 
    return message
 
 
def send_keys_and_check_message(argv, keys):
 
    # build and send message with keys
    keys_msg = json.dumps({"version": 1,"origin":{"name": argv[0],"module":"active-response"},"command":"check_keys","parameters":{"keys":keys}})
 
    write_debug_file(argv[0], keys_msg)
 
    print(keys_msg)
    sys.stdout.flush()
 
    # read the response of previous message
    input_str = ""
    while True:
        line = sys.stdin.readline()
        if line:
            input_str = line
            break
 
    # write_debug_file(argv[0], input_str)
 
    try:
        data = json.loads(input_str)
    except ValueError:
        write_debug_file(argv[0], 'Decoding JSON has failed, invalid input format')
        return message
 
    action = data.get("command")
 
    if "continue" == action:
        ret = CONTINUE_COMMAND
    elif "abort" == action:
        ret = ABORT_COMMAND
    else:
        ret = OS_INVALID
        write_debug_file(argv[0], "Invalid value of 'command'")
 
    return ret
 
def main(argv):
 
    write_debug_file(argv[0], "Started")
 
    # validate json and get command
    msg = setup_and_check_message(argv)
 
    if msg.command < 0:
        sys.exit(OS_INVALID)
 
    if msg.command == ADD_COMMAND:
        alert = msg.alert["parameters"]["alert"]
        keys = [alert["rule"]["id"]]
        action = send_keys_and_check_message(argv, keys)
 
        # if necessary, abort execution
        if action != CONTINUE_COMMAND:
 
            if action == ABORT_COMMAND:
                write_debug_file(argv[0], "Aborted")
                sys.exit(OS_SUCCESS)
            else:
                write_debug_file(argv[0], "Invalid command")
                sys.exit(OS_INVALID)
 
        try:
            os.remove(msg.alert["parameters"]["alert"]["data"]["virustotal"]["source"]["file"])
            write_debug_file(argv[0], json.dumps(msg.alert) + " Successfully removed threat")
        except OSError as error:
            write_debug_file(argv[0], json.dumps(msg.alert) + "Error removing threat")
           
       
    else:
        write_debug_file(argv[0], "Invalid command")
 
    write_debug_file(argv[0], "Ended")
 
    sys.exit(OS_SUCCESS)
 
if __name__ == "__main__":
    main(sys.argv)

Configuration on Windows endpoint

We proceed to convert the active response python script remove-threat.py to an executable application, by using the following steps:

  • Download and extract the latest PyInstaller source code from here
  • From the PyInstaller folder, run the following command with PowerShell (Administrator)
pip install wheel
python setup.py install
  • Copy the remove-threat.py file to the PyInstaller folder
  • Run the following command to create the executable
pyinstaller -F remove-threat.py
  • Move the executable file remove-threat.exe from pyinstaller-5.2\dist folder to C:\Program Files (x86)\ossec-agent\active-response\bin

To apply the changes, restart the agent by running the following PowerShell command as an administrator:

Restart-Service -Name wazuh

Configuration on the Wazuh manager

We proceed to configure active response on the Wazuh manager, this is triggered when malicious files are identified by VirusTotal. We append the following blocks to the Wazuh manager /var/ossec/etc/ossec.conf file.

<ossec_config>

    <command>
        <name>remove-threat</name>
        <executable>remove-threat.exe</executable>
        <timeout_allowed>no</timeout_allowed>
    </command>

    <active-response>
        <disabled>no</disabled>
        <command>remove-threat</command>
        <location>local</location>
        <rules_id>87105</rules_id>
    </active-response>

</ossec_config>

After the active response configuration is completed, we create rules that alerts us if the active response is successful or not. We achieve this by adding the following to our /var/ossec/etc/rules/local_rules.xml file on the Wazuh manager.

<group name="virustotal,">
  <rule id="110006" level="12">
    <if_sid>657</if_sid>
    <match>Successfully removed threat</match>
    <description>$(parameters.program) removed threat located at $(parameters.alert.data.virustotal.source.file)</description>
  </rule>

  <rule id="110007" level="12">
    <if_sid>657</if_sid>
    <match>Error removing threat</match>
    <description>Error removing threat located at $(parameters.alert.data.virustotal.source.file)</description>
  </rule>
</group>

Finally, restart the Wazuh manager to apply configuration changes.

systemctl restart wazuh-manager

Active response

To simulate the malware behavior, we download the malware files to the folder monitored by the FIM module. The malicious files were removed by the active response module, and an alert was created upon successful deletion.

Conclusion

In this blog post, we use various components of Wazuh such as FIM, VirusTotal integration, and active response capability to detect and remove WhisperGate malware.

Reference

Destructive malware targeting Ukrainian organizations – Microsoft Security Blog

Appendix

Indicators of compromise:

https://bazaar[.]abuse[.]ch/sample/a196c6b8ffcb97ffb276d04f354696e2391311db3841ae16c8c9f56f36a38e92
https://bazaar[.]abuse[.]ch/sample/dcbbae5a1c61dbbbb7dcd6dc5dd1eb1169f5329958d38b58c3fd9384081c9b78
https://bazaar[.]abuse[.]ch/sample/9ef7dbd3da51332a78eff19146d21c82957821e464e8133e9594a07d716d892d
https://bazaar[.]abuse[.]ch/sample/923eb77b3c9e11d6c56052318c119c1a22d11ab71675e6b95d05eeb73d1accd6