What is BPFdoor?

BPFdoor is a Linux-specific, low-profile, passive backdoor intended to maintain a persistent, long-term foothold in already-breached networks and environments and functions primarily to ensure an attacker can re-enter an infected system over an extended period of time, post-compromise.

The malware gets its name from its usage of a Berkley Packet Filter – a fairly unique way of receiving its instructions and evading detection, which bypasses firewall restrictions on incoming traffic.

The malware is associated with a Chinese threat actor, Red Menshen (AKA Red Dev 18), which has been observed targeting telecommunications providers across the Middle East and Asia, as well as entities in the government, education, and logistics sectors since 2021.

When it was first discovered, approximately one year ago, BPFdoor was noted for its effective and elegant design and its high emphasis on stealth – an essential element in maintaining undetected long-term persistence.

Recently, Deep Instinct’s threat lab observed and analyzed a previously undocumented and fully undetected new variant of BPFdoor.

New, Stealthier Variant

Several key differences that make this new variant even stealthier compared to the previous version include the following:

 “New stealthy” 2023 variant“Old” 2022 variant

Encryption

Static library encryption

RC4 Encryption

Communication

Reverse-Shell

Bind shell and iptables

Commands

No hardcoded commands – all commands are sent through the reverse-shell

Hardcoded commands

Filenames

Not hardcoded

Hardcoded

One of the most significant differences compared to the previous variant lies in the removal of many of its hardcoded indicators, making the newer version more difficult to detect. Since first seen on VirusTotal in February 2023, the new variant remained undetected and is still undetected as of this writing.

BPFdoor Technical Analysis

When executed, the BPFdoor sample will attempt to create and get a lock on a runtime file at “/var/run/initd.lock” and will exit if it fails using that file as a makeshift mutex.

Figure 1 - BPFdoor
Figure 1 - BPFdoor "mutex" check

If successful, BPFdoor will fork itself and continue to run as a child process and in this context will close its stdin, stdout, and stderr streams, and set itself to ignore the following operating system signals:

Signal NumberSignal NameSignal Description

1

SIGHUP

SIGHUP ("signal hang-up") is a signal sent to a process when its controlling terminal session is closed.

2

SIGINT

SIGINT (“signal interrupt”) is a signal sent when a user interrupts a program (Ctrl + C)

3

SIGQUIT

SIGQUIT is a signal sent to terminate a process.

13

SIGPIPE

SIGPIPE is a signal sent when a pipe breaks.

17

SIGCHLD

SIGCHLD is a signal sent when a child process exits.

21

SIGTTIN

SIGTTIN is a signal sent to a process attempting to read from the same terminal session and is blocked.

23

SIGTTOU

SIGTTOU is a signal sent to a process attempting to write to the same terminal session and is blocked.

Ignoring these signals hardens BPFdoor against tampering with its processes.

Having set up the above, BPFdoor then allocates a memory buffer and creates a socket as follows:

Figure 2 - Socket arguments
Figure 2 - Socket arguments

Figure 3 - Socket creation
Figure 3 - Socket creation

It will proceed to specify the following socket options using setsockopt:

Figure 4 - Setsockopt options
Figure 4 - Setsockopt options

Figure 5 - Call to setsockopt
Figure 5 - Call to setsockopt

And will read from it in a loop (further described below) using recvfrom:

Figure 6 - Recvfrom arguments
Figure 6 - Recvfrom arguments

Figure 7 - Recvfrom call
Figure 7 - Recvfrom call

An interesting point in the above-described flow is that the “addr” parameter is zeroed out in the call to recvfrom; it should point to a specific address from which to read data. The socket is not connected and no bind or listen calls have been made. So, what exactly is going on here?

Interpreting the exact arguments that are used to create the socket reveals that the call is structured as follows:

Figure 8 - Socket call
Figure 8 - Socket call

This creates the socket as a special packet sniffing socket which is able to read every packet that is sent to the machine from the ethernet layer and above without being bound to any specific protocol.

BPFdoor employs this type of packet sniffing socket to read data with recvfrom, even without an “addr” parameter, by using the loop below to search for a specific “magic” byte sequence:

Figure 9 - Looped search for
Figure 9 - Looped search for "magic" byte sequence (highlighted)

“Magic” byte sequence: \x44\x30\xCD\x9F\x5E\x14\x27\x66

Once found, the loop will break and BPFdoor will continue to Its next phase of operation.

But, that creates quite a lot of traffic that BPFdoor will need to go through.

Let’s examine the usage of setsockopt a bit further. When parsing its arguments, we arrive at the following code:

Figure 10 - Setsockopt attaches BPF
Figure 10 - Setsockopt attaches BPF

This is where BPFdoor gets its name from. The above code that attaches a Berkley Packet Filter to the socket; this is the very same mechanism that underpins infosec staples such as libpcap and allows BPFdoor to filter out “uninteresting” types of data coming through its socket.

A Berkley Packet Filter can be defined as in the example below, which allows TCP over IPv4:

Figure 11 - BPF example
Figure 11 - BPF example

By setting the socket option SO_ATTACH_FILTER and pointing filter to the following sock_filter_code:

Figure 12 - BPF sock_filter_code
Figure 12 - BPF sock_filter_code

BPFdoor guides the kernel to set up its socket to only read UDP, TCP, and SCTP traffic coming through ports 22 (ssh), 80 (http), and 443 (https).

Because of its positioning at such a low level, BPFdoor does not abide by any firewall rules, and can bypass any firewall restrictions on incoming traffic and listen for packets that otherwise wouldn't have surfaced to the machine's user mode.

When BPFdoor finds a packet containing its “magic” bytes in the filtered traffic it will treat it as a message from its operator and will parse out two fields and will again fork itself.

The parent process will continue and monitor the filtered traffic coming through the socket while the child will treat the previously parsed fields as a Command & Control IP-Port combination and will attempt to contact it.

Figure 13 - Connect to Command & Control
Figure 13 - Connect to Command & Control

An interesting point to note, this variant of BPFdoor contains a pre-compiled version of libtomcrypt, an open-source encryption library, as can be seen in the sample’s contained strings, which also offer a few additional insights:

Figure 14 - Contained strings
Figure 14 - Contained strings

We can see that the library was compiled at the beginning of October 2022 using GCC on a system running Red Hat Linux. This may suggest that this variant has been operational significantly earlier than its first appearance on VirusTotal.

By compiling our own version of the library in similar fashion and using bindiff to compare against BPFdoor we can see its statically linked exports:

Figure 15 - Libtomcrypt bindiff snippet
Figure 15 - Libtomcrypt bindiff snippet

Having made the comparison, we determined that BPFdoor is using libtomcrypt functionality to set up a secure and encrypted “reverse-shell” session with its Command & Control. This replaced its previous mechanism.

After this session is established, BPFdoor will begin a loop that can be described by the following:

Conclusion

BPFdoor retains its reputation as an extremely stealthy and difficult-to-detect malware with this latest iteration.

Regardless of whether one considers the encryption library compilation time (October 2022) or its initial submission to VirusTotal (February 2023) as indicative of when this sample was first put into use, it is truly amazing how long it has remained fully undetected.

Figure 16 & 17 - 0 VirusTotal detections, 7 different scans.
Figure 16 & 17 - 0 VirusTotal detections, 7 different scans.

IOCs

afa8a32ec29a31f152ba20a30eb483520fe50f2dce6c9aa9135d88f7c9c511d7 – BPFDoor ELF SHA256
/var/run/initd.lock – BPFDoor "mutex”

MITRE ATT&CK:

TacticTechniqueDescriptionObservable

Command and Control
Defense Evasion
Persistence

T1205 - Traffic Signaling

Attacker employs “magic” values to trigger response.

“Magic” byte sequence

Command and Control
Defense Evasion
Persistence

T1205.002 - Traffic Signaling: Socket Filters

Attacker attaches filter to a network socket.

Usage of Berkley Packet Filter

Command and Control

T1573 - Encrypted Channel

Attacker employs encrypted Command & Control communication.

Usage of libtomcrypt

Execution

T1106 – Native API

Attacker calls upon native OS APIs in order to execute behaviors.

Usage of popen

Earlier variant analysis:
https://www.elastic.co/security-labs/a-peek-behind-the-bpfdoor

Deep Instinct takes a prevention-first approach to stopping ransomware and other malware using the world’s first and only purpose-built, deep learning cybersecurity framework. We prevent ransomware, zero-day threats, and previously unknown malware in <20 milliseconds, 750x faster than the fastest ransomware can encrypt. Deep Instinct has >99% zero-day accuracy and promises a <0.1% false positive rate. The Deep Instinct Prevention Platform is an essential addition to every security stack – providing complete, multi-layered protection against threats across hybrid environments.