During the last few days there have been many articles describing BPFDoor, a UNIX backdoor allegedly used by Chinese threat actors. BPFDoor is a smart backdoor that does not need to open additional ports when the attacker wants to connect to the compromised host. It is able to hijack current open ports, sniff the traffic, and then bind a shell or open a reverse shell so that the attacker can execute remote commands.

There is a very good description in the ‘CyberThreats 2021: A Year in Retrospect’ report by PwC, that states:

“Throughout 2021 we tracked and responded to multiple intrusions attributed to a China-based threat actor that we have named Red Menshen.128 This threat actor has been observed targeting telecommunications providers across the Middle East and Asia, as well as entities in the government, education, and logistics sectors using a custom backdoor we refer to as BPFDoor. This backdoor supports multiple protocols for communicating with a C2 including TCP, UDP,and ICMP allowing the threat actor a variety of mechanisms to interact with the implant.“

PwC’s Global Threat Intelligence team will present their findings at the awesome WeAreTroopers conference in Heidelberg, Germany, at the end of June.

In this post, we will show how our team detected a BPFDoor using deception techniques. BPFDoor uses a variety of techniques, including particularly clever ones that allow it to enable backdoors without opening ports. This makes detecting it uniquely challenging .It seems that this particular backdoor has been in use for more than five years (affecting Linux and Solaris hosts), affecting principally Asian organizations and telco providers.

BPFDoor

One of the most interesting features of BPFDoor is that it is able to backdoor a host for remote code execution, without needing to open a listening port. Basically, what it is doing is listening to all the incoming traffic (after applying a BPF packet filter), and depending on the packets received, it will open a remote shell in a high TCP port or start a reverse shell.

At first, it sounds similar to a technique called port knocking, but the difference is that port knocking is usually used for opening a port after receiving a specific set of packets. In this case, the port is already opened by another service, and BPFDoor is able to capture the incoming traffic and open the remote shell after receiving a specific set of packets (a magic packet and a password).

Depending on the received magic packet, the backdoor will do different things. That magic packet consists of:

  •  A flag (unused)
  •  An IP address
  •  A port
  •  A password (max 14 characters)

This method has lots of advantages compared to the normal use of a malicious process that is listening to the network:

  •  It is difficult to detect as there is not any listening port
  •  It can reuse existing open ports
  •  It is only activated when the attacker connects to it

But of course it has some other disadvantages:

  •  You need to be root in order to listen to the network traffic, or at least you need to get the cap_net_raw and cap_net_admin capabilities.
  •  You still need to have a running process that is analyzing the traffic matched by the BPF packet filter.

BPFDoor source code was published in PasteBin on May 8th, so we can analyze all its features (there are also some good analysis from Sandfly Security and Exatrack about its capabilities):

  • 1. It installs a BPF packet filter that filters the following traffic:
    • a. The incoming packet is IPv4
    • b. If the incoming packet is UDP, check that 0x7255 is in its payload
    • c. If the incoming packet is ICMP, check that is an ICMP Echo Request and that 0x7255 is in its payload
    • d. If the incoming packet is TCP, check that 0x5293 is in its payload
  • 2. If the incoming packet matches the above conditions, then the code will check that it includes the correct password; there are two different passwords – the source code calls them ‘pass’ and ‘pass2’ – (both encrypted with RC4)
  • 3. If the provided password does not match any of the two passwords, then it sends back an UDP packet with the payload ‘1’ to the port included in the incoming packet. This is a strange behaviour because it can be used for remotely scanning compromised hosts (as for example, this bpfdoor-scanner is doing), but we guess it is also a method for remotely detecting that the backdoor is still active.
  • 4. If one of the passwords is correct, then:
    • a. If the password is the same one initialized in ‘pass’ – in the leaked source code it is ‘justforfun’– it will open a remote shell in a high TCP port.
    • b. If the password is the same one initialized in ‘pass2’ – in the leaked source code it is ‘socket’ – it will start a reverse shell to the remote IP address and the remote port that was included in the incoming packet.

Step-by-step compromise

Let’s see what happens after BPFDoor is executed in a compromised host:

T1059.004: Command and Scripting Interpreter: Unix Shell
T1070.004: Indicator Removal on Host: File Deletion
T1036/004: Masquerading: Masquerade Task or Service
T1070/006: Indicator Removal on Host: Timestomp

The process deletes previous instances of the backdoor and copies itself as the ‘/dev/shm/kdmtmpflush’ binary. In our installation, as it was a non-infected host, the file deletion failed. Then it changes its permissions so that it is now executable for everybody, executes this new binary with the flag ‘–init’, changes the process name and deletes itself.

It also uses a specific file as we can see in Image 6 (/var/run/haldrund.pid) in order to check if the backdoor is already running. If the process finds that file, then it exits without doing anything else.

It changes the timestamp of the new file to a specific date before deleting it: 1225394236 seconds in epoch format, which translates to Thursday, 30 October 2008 19:17:16 GMT. In theory, this technique is used to try to hide the real timestamp of the file or to modify the timestamp in order to mimic the files in the current folder. But in this case, there is another file (the PID file) that keeps the timestamp when it was created.

Image 1: Initial execution

Image 2: Delete previous installations (failure)

Image 3: Copy executable file

Image 4: Set file permissions

Image 5: Execution with the -init flag

Image 6: Creation of PID file

Image 7: Self-delete

T1205: Traffic Signaling

T1059.004: Command and Scripting Interpreter: Unix Shell

T1036/004: Masquerading: Masquerade Task or Service

The process opens a raw socket with the AF_PACKET address family so that it can listen to the network traffic, and applies the BPF packet filter so the process will only get the packets with a valid magic number.

Image 8: Create capture socket

As we described before there are three main modes of operation: open a shell in a high port, open a reverse shell, or just send an UDP packet with ‘1’ in the payload if the password does not match with any of the two predefined passwords.

In the first case, if we send the correct password, the process will fork itself and start listening to a high port (between 42391 and 43391, the process will listen to those ports in sequential order, depending on the number of clients), and we will see a number of iptables command executions so that when the remote IP address connects to the host its traffic to the existing port will be redirected to the high port with the shell.

The iptables commands will be the following:

  •  /sbin/iptables -I INPUT -p tcp -s ATTACKER_IP -j ACCEPT
  •  /sbin/iptables -t nat -A PREROUTING -p tcp -s ATTACKER_IP –dport 22 -j REDIRECT –to-ports 42391

And then the process will delete the created iptables rules:

  •  /sbin/iptables -t nat -D PREROUTING -p tcp -s ATTACKER_IP –dport 22 -j REDIRECT –to-ports 42391
  •  /sbin/iptables -D INPUT -p tcp -s ATTACKER_IP -j ACCEPT

Image 9: Iptable rule

In the second case, if we send the correct password, it will establish a reverse shell against the remote IP address and remote port that was specified in the magic packet, so there is no need to add any iptables rules.

In both cases, the shell that will be spawned will have some specific properties:

  •  The new process name (a fork) will be changed to ‘/usr/libexec/postfix/master’
  •  The shell will be another forked process with the process name changed to ‘qmgr -l -t fifo -u’
  •  The shell will be ‘/bin/sh’
  •  The environment variables will be the following:
    • – HOME=/tmp
    • – PS1=[\u@\h \W]\$
    • – HISTFILE=/dev/null
    • – MYSQL_HISTFILE=/dev/null
    • – PATH=/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/ bin:/usr/local/sbin:/usr/X11R6/bin:./bin

Image 10: Listen to a high port

Image 11: Process fork

Image 12: Iptables command

Image 13: Iptables command

Image 14: Iptables command

Image 15: Iptables command

Detection opportunities

Detection can be accomplished by looking for the two specific filenames (‘/dev/shm/kdmtmpflush’ and ‘(/var/run/haldrund.pid’), but you can also scan your network infrastructure using Python scripts like the bpfdoor-scanner. This will find compromised hosts due to the third mode of operation where sending a bad password will receive an UDP packet with ‘1’ in its payload.

You can also try to detect it by reviewing the process names, and seeing if any of them are in the process list.

Additionally, if you are using an EDR in your UNIX hosts and see a process opening a raw socket with AF_PACKET address family, you should definitely look closer, since it usually means that process is sniffing the network traffic, which is highly suspicious.

Finally, here are some YARA rules that can help locating the BPFdoor binaries in your hosts:

Summary

As we have seen during our analysis, BPFDoor is a smart backdoor that does not need to open additional ports when the attacker wants to connect to the compromised host. It is able to hijack current open ports, sniff the traffic, and then bind a shell or open a reverse shell so that the attacker can execute remote commands.

BPFDoor uses a variety of techniques but the most interesting one is T1205: Traffic Signaling, as it is a clever method for enabling a network backdoor without opening a port.

ATT&CK techniques:

T1059.004: Command and Scripting Interpreter: Unix Shell
T1070.004: Indicator Removal on Host: File Deletion
T1036/004: Masquerading: Masquerade Task or Service
T1070/006: Indicator Removal on Host: Timestomp
T1205: Traffic Signaling

If you want to get any BPFDoor binaries, Kevin Beaumont maintains a good collection of BPFDoor hashes in VirusTotal and you can also find some hashes in the previous YARA rules.

CounterCraft runs a series of internet-based deception farms to collect relevant and timely threat intel for the cybersecurity community. This post is the result of our threat intel team’s findings and research on BPFDoor threat.

Further reading

If you want to know more about BPFDoor, we recommend the following resources:

IOCs

Hashes

07ecb1f2d9ffbd20a46cd36cd06b022db3cc8e45b1ecab62cd11f9ca7a26ab6d 1925e3cd8a1b0bba0d297830636cdb9ebf002698c8fa71e0063581204f4e8345 4c5cf8f977fc7c368a8e095700a44be36c8332462c0b1e41bff03238b2bf2a2d 591198c234416c6ccbcea6967963ca2ca0f17050be7eed1602198308d9127c78 599ae527f10ddb4625687748b7d3734ee51673b664f2e5d0346e64f85e185683 5b2a079690efb5f4e0944353dd883303ffd6bab4aad1f0c88b49a76ddcb28ee9 5faab159397964e630c4156f8852bcc6ee46df1cdd8be2a8d3f3d8e5980f3bb3 76bf736b25d5c9aaf6a84edd4e615796fffc338a893b49c120c0b4941ce37925 93f4262fce8c6b4f8e239c35a0679fbbbb722141b95a5f2af53a2bcafe4edd1c 96e906128095dead57fdc9ce8688bb889166b67c9a1b8fdb93d7cff7f3836bb9 97a546c7d08ad34dfab74c9c8a96986c54768c592a8dae521ddcf612a84fb8cc c796fc66b655f6107eacbe78a37f0e8a2926f01fecebd9e68a66f0e261f91276 c80bd1c4a796b4d3944a097e96f384c85687daeedcdcf05cc885c8c9b279b09c f47de978da1dbfc5e0f195745e3368d3ceef034e964817c66ba01396a1953d72 f8a5e735d6e79eb587954a371515a82a15883cf2eda9d7ddb8938b86e714ea27 fa0defdabd9fd43fe2ef1ec33574ea1af1290bd3d763fdb2bed443f2bd996d73 fd1b20ee5bd429046d3c04e9c675c41e9095bea70e0329bd32d7edd17ebaf68a 144526d30ae747982079d5d340d1ff116a7963aba2e3ed589e7ebc297ba0c1b3 fa0defdabd9fd43fe2ef1ec33574ea1af1290bd3d763fdb2bed443f2bd996d73 76bf736b25d5c9aaf6a84edd4e615796fffc338a893b49c120c0b4941ce37925 96e906128095dead57fdc9ce8688bb889166b67c9a1b8fdb93d7cff7f3836bb9 c80bd1c4a796b4d3944a097e96f384c85687daeedcdcf05cc885c8c9b279b09c f47de978da1dbfc5e0f195745e3368d3ceef034e964817c66ba01396a1953d72 07ecb1f2d9ffbd20a46cd36cd06b022db3cc8e45b1ecab62cd11f9ca7a26ab6d 4c5cf8f977fc7c368a8e095700a44be36c8332462c0b1e41bff03238b2bf2a2d 599ae527f10ddb4625687748b7d3734ee51673b664f2e5d0346e64f85e185683 5b2a079690efb5f4e0944353dd883303ffd6bab4aad1f0c88b49a76ddcb28ee9 5faab159397964e630c4156f8852bcc6ee46df1cdd8be2a8d3f3d8e5980f3bb3 93f4262fce8c6b4f8e239c35a0679fbbbb722141b95a5f2af53a2bcafe4edd1c 97a546c7d08ad34dfab74c9c8a96986c54768c592a8dae521ddcf612a84fb8cc c796fc66b655f6107eacbe78a37f0e8a2926f01fecebd9e68a66f0e261f91276 f8a5e735d6e79eb587954a371515a82a15883cf2eda9d7ddb8938b86e714ea27 fd1b20ee5bd429046d3c04e9c675c41e9095bea70e0329bd32d7edd17ebaf68a

Filenames

/dev/shm/kdmtmpflush
/dev/shm/kdumpflush
/dev/shm/kdumpdb

/var/run/xinetd.lock
/var/run/kdevrund.pid
/var/run/haldrund.pid
/var/run/syslogd.reboot

Process names

“/sbin/udevd -d”,
“/sbin/mingetty /dev/tty7”,
“/usr/sbin/console-kit-daemon –no-daemon”,
“hald-addon-acpi: listening on acpi kernel interface /proc/acpi/event”,
“dbus-daemon –system”,
“hald-runner”,
“pickup -l -t fifo -u”,
“avahi-daemon: chroot helper”,
“/sbin/auditd -n”,
“/usr/lib/systemd/systemd-journald”
“‘/usr/libexec/postfix/master”
“qmgr -l -t fifo -u”