Detecting and responding to InvisibleFerret with Wazuh

InvisibleFerret is a Python-based backdoor malware that affects both Windows and Linux endpoints. It is used in targeted campaigns by North Korean threat actors, particularly the notorious Lazarus Group. This malware is deployed through advanced social engineering tactics, often disguised as part of legitimate job recruitment processes. Threat actors impersonate recruiters, luring victims, primarily professionals in the technology, financial, and cryptocurrency sectors, into downloading malicious files. These files are cleverly masked as coding challenges, video conferencing software, or dependency packages, making them appear harmless and credible.
InvisibleFerret is delivered as a second-stage payload by BeaverTail, a JavaScript-based loader and stealer. Once installed, it exhibits a wide range of malicious capabilities, including geolocation tracking, file exfiltration via FTP and Telegram Bots, keylogging, and clipboard monitoring.
In this blog post, we demonstrate how Wazuh can be configured to detect and mitigate the threat posed by InvisibleFerret on Linux endpoints.
Below are some of the behaviors observed when the InvisibleFerret malware is successfully executed on a Linux endpoint:
/tmp/
, then removes them after execution to cover its tracks.Hash type | Value |
MD5 | 30ee0cc21753e27dd45a7cedc1271cda |
SHA1 | 989252de0be3253c5cfd4b68bc84aae0a6fd6c9c |
SHA256 | 2012f6f7d8add86ebbc6629815832554fca37cc3e1edab68a51f57e345365f85 |
We use the following infrastructure to demonstrate the detection of InvisibleFerret with Wazuh:
In this blog post, we demonstrate how to use custom Wazuh detection rules to identify InvisibleFerret malware activity. We also use the CDB lists and Active Response capabilities to detect and automatically remove the InvisibleFerret malware files.
We install SysmonForLinux to enrich the event logs generated on the Linux endpoints. This approach provides detailed information about events such as process creations, network connections, and changes to the file system. Then we create custom rules on the Wazuh server to detect the malicious behavior of the InvisibleFerret malware.
Note
Execute all the commands below as root. If you are using a non-root (normal) user, prepend sudo
to each command.
# wget https://wazuh.com/resources/blog/detecting-sysjoker-backdoor-malware-with-wazuh/sysmonforlinux-config.xml
# sysmon -accepteula -i# sysmon -i sysmonforlinux-config.xml
# systemctl enable sysmon# systemctl start sysmon
<ossec_config>
block of the /var/ossec/etc/ossec.conf
file to forward Sysmon events to the Wazuh server for analysis:<localfile> <log_format>syslog</log_format> <location>/var/log/syslog</location> </localfile>
# systemctl restart wazuh-agent
Wazuh utilizes decoders to extract information from received log messages. Follow these steps to download the decoders that can extract information from SysmonforLinux logs.
# wget https://wazuh.com/resources/blog/detecting-sysjoker-backdoor-malware-with-wazuh/sysmonforlinux-decoders.xml.txt
/var/ossec/etc/decoders/local_decoder.xml
file:# cat sysmonforlinux-decoders.xml.txt >> /var/ossec/etc/decoders/local_decoder.xml
Wazuh uses rules to analyze decoded log data and trigger alerts. Follow these steps to download the rules that can trigger alerts from the SysmonforLinux log.
# wget https://wazuh.com/resources/blog/detecting-sysjoker-backdoor-malware-with-wazuh/sysmonforlinux-base-rules.xml
/var/ossec/etc/rules/local_rules.xml
file. Since these are base rules, the rule levels are set to 1 to generate alerts that will not be shown on the dashboard.# cat sysmonforlinux-base-rules.xml >> /var/ossec/etc/rules/local_rules.xml
/var/ossec/etc/rules/local_rules.xml
file to detect InvisibleFerret behavior:<group name="invisibleferret,"> <rule id="100501" level="7"> <if_sid>200155</if_sid> <field name="eventdata.image" type="pcre2">\/usr\/bin\/python(\d+\.\d+).*?</field> <field name="eventdata.targetFilename" type="pcre2">\/tmp\/([a-zA-Z0-9]{8}).*?</field> <description>Suspicious file created: "$(eventdata.targetFilename)"- Possible InvisibleFerret malware activity detected.</description> <mitre> <id>T1044</id> </mitre> </rule> <rule id="100502" level="7"> <if_sid>200157</if_sid> <field name="eventdata.image" type="pcre2">\/usr\/bin\/python(\d+\.\d+).*?</field> <field name="eventdata.targetFilename" type="pcre2">\/tmp\/([a-zA-Z0-9]{8}).*?</field> <description>Suspicious file deleted: "$(eventdata.targetFilename)" - Possible InvisibleFerret malware activity detected.</description> <mitre> <id>T1107</id> <id>T1485</id> </mitre> </rule> <rule id="100503" level="7"> <if_sid>200152</if_sid> <field name="eventdata.image" type="pcre2">\/usr\/bin\/python(\d+\.\d+).*?</field> <field name="eventdata.destinationIp" type="pcre2">(127\.0\.0\.1)</field> <field name="eventdata.sourceIp" type="pcre2">(127\.0\.0\.53)</field> <field name="eventdata.sourcePort" type="pcre2">(53)</field> <description>Suspicious query of DNS - Possible InvisibleFerret malware activity detected.</description> <mitre> <id>T1043</id> </mitre> </rule> <rule id="100504" level="12"> <if_sid>200152</if_sid> <field name="eventdata.image" type="pcre2">\/usr\/bin\/python(\d+\.\d+).*?</field> <field name="eventdata.sourceIp" type="pcre2">(\d+\.\d+\.\d+\.\d+)</field> <field name="eventdata.destinationIp" type="pcre2">(151\.101\.\d+\.\d+)</field> <field name="eventdata.destinationPort" type="pcre2">443</field> <description>Suspicious download request to "$(eventdata.destinationIp)" for remote access - InvisibleFerret malware activity detected.</description> <mitre> <id>T1043</id> </mitre> </rule> <rule id="100505" level="12"> <if_sid>200152</if_sid> <field name="eventdata.image" type="pcre2">\/usr\/bin\/python(\d+\.\d+).*?</field> <field name="eventdata.sourceIp" type="pcre2">(\d+\.\d+\.\d+\.\d+)</field> <field name="eventdata.destinationIp" type="pcre2">(208\.95\.\d+\.\d+)</field> <field name="eventdata.destinationPort" type="pcre2">80</field> <description>Suspicious download request to "$(eventdata.destinationIp)" for data exfiltration - InvisibleFerret malware activity detected.</description> <mitre> <id>T1043</id> </mitre> </rule> </group>
Where:
100501
is triggered when the malware creates suspicious files in the /tmp
directory.100502
is triggered when the malware immediately deletes suspicious files in the /tmp
directory to maintain its legitimacy.100503
is triggered when the malware queries the DNS to map the network and detect the virtualized environment.100504
is triggered when the InvisibleFerret malware makes a request to download AnyDesk and connect to the C2 server for remote access.100505
is triggered when InvisibleFerret makes a second request for data exfiltration.# systemctl restart wazuh-manager
Follow the steps below to view the alerts generated on the Wazuh dashboard when the InvisibleFerret malware is executed on the Linux endpoint.
rule.id
.is one of
.100501
, 100502
, 100503
, 100504
, and 100505
in the Values field.We configure Wazuh to detect malicious files by comparing their signatures against a CDB list of known malware signatures. A CDB list is a text file that stores key:value
pairs, allowing you to track users, file hashes, IP addresses, or domain names, or other relevant data. The Active Response module triggers automated countermeasures such as file deletion, process termination, to contain the threat immediately after detection.
To detect the InvisibleFerret malware, you must add its known hashes to a CDB list. The Wazuh File Integrity Monitoring (FIM) module tracks file changes within monitored directories, generating alerts when files are created, modified, or deleted. These alerts include the MD5, SHA1, and SHA256 checksums of the file. By comparing the SHA256 checksums from the FIM module against the entries in the CDB list, Wazuh identifies the presence of the malware.
Follow the steps below to set up FIM, create a CDB list and set up the detection mechanism.
<syscheck>
block of the /var/ossec/etc/ossec.conf
file to monitor the Downloads
directory of all regular users in real-time.<directories check_all="yes" report_changes="yes" realtime="yes">/home/*/Downloads</directories>
Note
In this blog post, we monitored only the Downloads
directory of all regular users. However, you can configure Wazuh to monitor any directory of your choice.
# systemctl restart wazuh-agent
malware-hashes
in the /var/ossec/etc/lists
directory. This is the CDB list that will contain the known file hashes associated with the InvisibleFerret malware. # touch /var/ossec/etc/lists/malware-hashes
/var/ossec/etc/lists/malware-hashes
file as key:value
pairs: 2012f6f7d8add86ebbc6629815832554fca37cc3e1edab68a51f57e345365f85:invisbleferret a2de54fbfbca6e1715b2621ab382e9c1c645fdb0723a410e8775d2ac026897c8:invisbleferret 11dde438e1a636073e79c81d4c2543708cc0a2922e7c42c38b1b588e17545f96:invisbleferret
/var/ossec/etc/ossec.conf
file and include the /etc/lists/malware-hashes
list within the <ruleset>
configuration block:<list>etc/lists/malware-hashes</list>
/var/ossec/etc/rules/local_rules.xml
file to trigger alerts on the Wazuh dashboard whenever a SHA256 hash from the CDB list is detected: <group name="invisbleferret,"> <rule id="100510" level="13"> <if_sid>554</if_sid> <list field="sha256" lookup="match_key">etc/lists/malware-hashes</list> <description>A known InvisibleFerret malware hash detected: $(file)</description> <mitre> <id>T1204.002</id> </mitre> </rule> </group>
# systemctl restart wazuh-manager
Perform the following on the Wazuh dashboard to view the alerts generated when the InvisibleFerret malware files are added to the Downloads
directory.
rule.id
.is
.100510
in the Values field.The Wazuh Active Response module helps mitigate threats by executing scripts on monitored endpoints when specific triggers occur.
In this guide, we demonstrate how to set up a Python script on a Linux endpoint to automatically delete InvisibleFerret malware files upon detection by Wazuh.
Follow the steps below to configure the active response script to remove InvisibleFerret malware files as soon as they are detected.
remove-threat.py
script file in the /var/ossec/active-response/bin
using the command below:touch /var/ossec/active-response/bin/remove-threat.py
/var/ossec/active-response/bin/remove-threat.py
file:#!/usr/bin/python3 # Copyright (C) 2015-2022, Wazuh Inc. # All rights reserved. # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General Public # License (version 2) as published by the FSF - Free Software # Foundation. import os import sys import json import datetime from pathlib import PureWindowsPath, PurePosixPath 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: ar_name_posix = str(PurePosixPath(PureWindowsPath(ar_name[ar_name.find("active-response"):]))) log_file.write(str(datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')) + " " + ar_name_posix + ": " + msg +"\n") def setup_and_check_message(argv): # get alert from stdin input_str = "" for line in sys.stdin: 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') 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: """ Start Custom Key At this point, it is necessary to select the keys from the alert and add them into the keys array. """ alert = msg.alert["parameters"]["alert"] keys = [alert["rule"]["id"]] """ End Custom Key """ 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"]["syscheck"]["path"]) 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)
# chmod 750 /var/ossec/active-response/bin/remove-threat.py # chown root:wazuh /var/ossec/active-response/bin/remove-threat.py
# systemctl restart wazuh-agent
<ossec_config>
block of the /var/ossec/etc/ossec.conf
file to trigger an Active Response to rule ID 100510
:<command> <name>remove-threat</name> <executable>remove-threat.py</executable> <timeout_allowed>yes</timeout_allowed> </command> <active-response> <disabled>no</disabled> <command>remove-threat</command> <location>local</location> <rules_id>100510</rules_id> </active-response>
Where:
<name>
specifies that remove-threat
is the name of the command being called in the active response section.<executable>
specifies that remove-threat.py
is the executable file to run.<command>
specifies the command that the active response will use.<active response>
block calls the <command>
block when the rule ID 100510
is triggered.<location>
specifies where the active response script is executed./var/ossec/etc/rules/local_rules.xml
to generate alerts when response actions are taken:<group name="invisbleferret,"> <rule id="100511" level="12"> <if_sid>657</if_sid> <match>Successfully removed threat</match> <description>$(parameters.program): Successfully removed threat $(parameters.alert.syscheck.path) whose hash appears in a malware blacklist.</description> </rule> <rule id="100512" level="12"> <if_sid>657</if_sid> <match>Error removing threat</match> <description>$(parameters.program): Error removing threat $(parameters.alert.syscheck.path) whose hash appears in a malware blacklist.</description> </rule> </group>
Where:
100511
is triggered when the threat is successfully removed by the Wazuh Active Response module.100512
is triggered when the threat is not successfully removed by the Wazuh active response module.# systemctl restart wazuh-manager
Perform the following steps on the Wazuh dashboard to view the alerts of the removal of the malicious file by the Wazuh Active Response module:
rule.id
.is one of
.100511
and 100512
in the Values field.In this blog post, we demonstrated how to detect InvisibleFerret malware activities on monitored Linux endpoints. We enriched logs from the victim endpoint by integrating Sysmon and creating Wazuh detection rules to trigger alerts once they are associated with InvisibleFerret malware. We also illustrated how to remove the known malicious files using the Wazuh CDB lists and Active Response module.
Wazuh is a free, open source security platform providing a wide range of capabilities to monitor and safeguard your infrastructure against malicious activities. If you have any questions about this blog post or Wazuh, we invite you to join our community, where our team is available to assist you.