{
	"id": "b4209654-7388-4c39-8337-6458f12bd181",
	"created_at": "2026-04-06T00:18:16.373636Z",
	"updated_at": "2026-04-10T03:33:12.079834Z",
	"deleted_at": null,
	"sha1_hash": "03024125af7f94341afef701b3299542f647b96a",
	"title": "BPFDoor - An Evasive Linux Backdoor Technical Analysis",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 100932,
	"plain_text": "BPFDoor - An Evasive Linux Backdoor Technical Analysis\r\nArchived: 2026-04-05 22:39:19 UTC\r\nSandfly Blog\r\n11 May 2022\r\nMalware\r\nRecently Kevin Beaumont revealed a new evasive backdoor targeting Linux associated with the Chinese Red Menshen\r\nthreat actors. In his article he reveals that this backdoor has been operating globally for many years with potentially\r\nthousands of instances already deployed. The backdoor has also been noted by investigators at PricewaterhouseCoopers in\r\ntheir latest Cyber Threat Intelligence Retrospect Report (pg. 36).\r\nThe source for this backdoor was posted by anonymously and Sandfly researchers are able to provide the following in-depth\r\ntechnical analysis. At a high level, it does the following:\r\nGoes memory resident and deploys anti-forensics and evasion to hide.\r\nLoads a Berkeley Packet Filter (BPF) sniffer allowing it to efficiently watch traffic and work in front of any locally\r\nrunning firewalls to see packets (hence BPFDoor).\r\nUpon receiving a special packet, it will modify the local firewall to allow the attacker IP address to access resources\r\nsuch as a spawned shell or connect back bindshell.\r\nOperations are hidden with process masquerading to avoid detection.\r\nWhile the malware takes steps to evade casual observation, it is easily seen if you know where and how to look. We'll\r\nreview the above and provide detection tips.\r\nSource Build Size and Compatibility\r\nThe BPFDoor source is small, focused and well written. While the sample we reviewed was Linux specific, with some small\r\nchanges it could easily be ported to other platforms (a Solaris binary reportedly exists). BPF is widely available across\r\noperating systems and the core shell functions would likely work across platforms with little modification.\r\nThe dynamically linked binary is small at about 35K on Ubuntu:\r\n-rwxr-xr-x 1 root root 34952 May 11 00:03 bpfdoor\r\nStatically linked it would grow to about 1MB, but the dynamically linked version would likely work on most modern Linux\r\ndistributions. Cross compiling for various CPUs is also possible so this implant would likely work on embedded Linux\r\ndevices as well.\r\nImplant Operation Steps\r\nThe binary itself just needs to be downloaded onto the victim and run. It doesn't matter how or where it gets to the host as it\r\ntakes care of moving itself to a suitable area once run to remain resident. However, the binary does need root permissions to\r\nrun.\r\nWhen run, the binary has an initialization sequence as follows:\r\n1) Copy binary to the /dev/shm directory (Linux ramdisk).\r\n2) Rename and run itself as /dev/shm/kdmtmpflush.\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 1 of 9\n\n3) Fork itself and run fork with \"--init\" flag which tells itself to execute secondary clean-up operations and go resident.\r\n4) The forked version timestomps the binary file /dev/shm/kdmtmpflush and initiates packet capture loop.\r\n5) The forked version creates a dropper at /var/run/haldrund.pid to mark it is resident and prevent multiple starts.\r\n6) The original execution process deletes the timestomped /dev/shm/kdmtmpflush and exits.\r\n7) The forked version remains resident and monitors traffic for magic packet to initiate attacker operations such as a\r\nbindshell.\r\nPersistence\r\nThe implant itself has no persistence mechanisms as it is highly focused on a single task. Persistence would need to be\r\ninitiated by the attacker in some other way such as rc or init scripts or scheduled tasks such as with crontab. The initial\r\nreport referenced above indicates that persistence scripts have been found.\r\nThe implant uses /dev/shm on Linux. This is a ramdisk and is cleared out on every reboot. For persistence reasons, the\r\nimplant will need to be somewhere else on the host to survive reboots or be inserted again remotely.\r\nIncident response teams that find this implant operating should assume the real binary is somewhere else on the file\r\nsystem. Check all system boot scripts for unusual references to binaries or paths.\r\nTimestomping\r\nThe binary copies itself to /dev/shm/kdmtmpflush which is only in RAM and clears out every reboot. The interesting part of\r\nthe implant is that it sets a bogus time to timestomp the binary before deletion. The relevant code is below:\r\ntv[0].tv_sec = 1225394236; tv[0].tv_usec = 0; tv[1].tv_sec = 1225394236; tv[1].tv_usec = 0; utimes(file, tv);\r\nThe date is set to 1225394236 seconds from epoch which translates to: Thursday, October 30, 2008 7:17:16 PM (GMT)\r\nWe did some searches to see if this date has any significance but didn't see anything obvious. It could have some\r\nsignificance to the author or could be random.\r\nThe interesting part about this is the timestomp happens by the forked process before the main process tries to delete the\r\nbinary. We assume this is a failsafe mechanism. If the implant should fail to load and not delete itself from\r\n/dev/shm/kdmtmpflush then the file left behind will have an innocuous looking time on it that masks when it was created. It\r\nwould also make incident response harder if you are looking for recently created files (this one looks like it was created 14\r\nyears ago).\r\nPID Dropper\r\nThe implant creates a zero byte PID file at /var/run/haldrund.pid. This file is deleted if the implant terminates normally, but\r\nif there is a problem such as a hard shutdown or crash, the file may be left behind. The implant will not start if this file is\r\npresent as it is used to mark that it may already be running.\r\nBinary Deletion\r\nAfter the binary starts, it deletes itself making recovery harder. However, recovering a deleted process binary on Linux is\r\ntrivial once it is running (see our article on how to do it). But the main thing deletion does is allow the binary to avoid\r\ndetection by malware scanners that rely on file scanning. The binary is simply not on the disk to be scanned and if the main\r\nbinary is hidden/encrypted on the device for persistence it would be very hard to find.\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 2 of 9\n\nHowever on Linux a deleted process binary is extremely suspicious. If you search for any kind of process with a deleted\r\nbinary then it stands out:\r\nls -alR /proc/*/exe 2\u003e /dev/null | grep deleted\r\nIf you are using Sandfly to protect your Linux systems you will have received multiple automated alerts about a suspicious\r\nbinary running. The red arrow shows that the process is masquerading as something else. We'll talk about that in a bit.\r\nIn general, any process deleting its binary after running is going to be malicious.\r\nMasquerading\r\nThe binary masquerades its name by selecting from one of 10 names randomly:\r\n/sbin/udevd -d /sbin/mingetty /dev/tty7 /usr/sbin/console-kit-daemon --no-daemon hald-addon-acpi: listening on\r\nacpi kernel interface /proc/acpi/event dbus-daemon --system hald-runner pickup -l -t fifo -u avahi-daemon:\r\nchroot helper /sbin/auditd -n /usr/lib/systemd/systemd-journald\r\nThe names are made to look like common Linux system daemons. The implant overwrites the argv[0] value which is used\r\nby the Linux /proc filesystem to determine the command line and command name to show for each process. By doing this,\r\nwhen you run commands like ps you will see the bogus name. Below you can see the process running under the masquerade\r\nname dbus-daemon --system.\r\nThis masquerading tactic has been around for a while. While it works, the real process name is still visible inside Sandfly\r\nwith the masqueraded versions also showing. This kind of difference in real process name vs. the command line values\r\nindicates also there is a problem.\r\nIf you find a suspicious process ID (PID), you can quickly investigate what the real name may be by going to /proc/\u003cPID\u003e\r\nand doing a simple ls command:\r\ncd /proc/\u003cPID\u003e ls -al\r\nYou will see the exe link which will be pointing to the real binary location which can confirm at least what the binary was\r\ncalled when started. Also you'll see the timestamp on the file is when the binary was started which can help bracket the time\r\nof intrusion. Linux also helpfully labels the binary as \"(deleted)\".\r\nEnvironment Wipe\r\nThe last thing the implant does before going fully resident is wipe out the process environment. When you start a process on\r\nLinux it stores a lot of useful forensic information in /proc/\u003cPID\u003e/environ. This area can often reveal useful information\r\nsuch as SSH connections that started the process, usernames, etc.\r\nThe environment wipe the implant uses is interesting because it wipes out envp[] (third argument to main() which is where\r\nenvironment variables are passed in as array in Linux). See below for explanation of how to use argv iteration to get\r\nenvironment variables:\r\nargv prints out environment variables\r\nThis is a pretty good mechanism and ensures there are no environment variables left on the running process. Although it\r\nwon't work in this case, we have an article on how to do live process environment forensics here:\r\nUsing Linux Process Environment Variables for Live Forensics\r\nThe end result is that the implant leaves the environment completely blank which can happen under some normal\r\ncircumstances, but usually not. Below we see the fake dbus implant and the real dbus on the same box. The real dbus\r\nenvironment has some data with it. A completely empty environment is unusual for normal processes.\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 3 of 9\n\nBPF Filter Activation and Analysis\r\nOnce the implant has done its anti-forensics and evasion housekeeping, it goes into the packet capture loop. The packet\r\ncapture function loads a BPF filter (hence the name). BPF is a highly efficient way to filter packets coming into a system\r\nwhich massively reduces CPU load by preventing all packets from needing to be analyzed by the receiver. It effectively\r\noperates as a very efficient pre-filter and only passes likely valid packets for review to the implant.\r\nWith BPFDoor they have taken a BPF filter and converted it to BPF bytecode. This keeps the implant small and less reliant\r\non system libraries that may need to parse a human readable BPF filter, and allows for filters that the normal expression\r\nsyntax cannot represent.\r\nWe have reverse engineered the bytecode below to show you what it is doing. It does basically two things:\r\nGrabs either an ICMP (ping), UDP or TCP packet.\r\nSees if it has magic data value. If not then reject.\r\nThe commented assembly and pseudocode is here:\r\nl0: ldh [12] // A = halfword from offset 12 [Ethernet: EtherType] l1: jeq #0x800, l2, l29 // if\r\nEtherType==IPv4 goto l2; else goto l29 l2: ldb [23] // A = byte from packet offset 23 [IPv4: Protocol] (data\r\nbegins at offset 14 of ethernet packet; so this is offset 9 in the IPv4 packet) l3: jeq #0x11, l4, l9 // if\r\nProtocol==UDP goto l4, else goto l9 l4: ldh [20] // A = IPv4 flags+fragment offset l5: jset #0x1fff, l29, l6 //\r\n...if fragmentation offset != 0, goto l29 l6: ldxb 4*([14]\u00260xf) // X = IPv4 Header Length l7: ldh [x+22] // A =\r\nhalfword from offset X+22... first halfword of UDP datagram data l8: jeq #0x7255, l28, l29 // if A==0x7255 goto\r\nl28, else goto l29 l9: jeq #0x1, l10, l17 // if Protocol==ICMP goto l10, else goto l17 (jumped to from l3;\r\nregister contains IP protocol) l10: ldh [20] // A = IPv4 flags+fragment offset l11: jset #0x1fff, l29, l12 //\r\n...if fragmentation offset != 0, goto l29 l12: ldxb 4*([14]\u00260xf) // X = IPv4 Header Length l13: ldh [x+22] // A\r\n= halfword from offset X+22... first halfword of ICMP data l14: jeq #0x7255, l15, l29 // if A==0x7255 goto l15,\r\nelse goto l29 l15: ldb [x+14] // A = byte from offset X+14... ICMP Type l16: jeq #0x8, l28, l29 // if ICMP Type\r\n== Echo Request (ping) goto l28, else goto l29 l17: jeq #0x6, l18, l29 // if Protocol==TCP goto l18, else goto\r\nl29 (jumped to from l3; register contains IP protocol) l18: ldh [20] // A = IPv4 flags+fragment offset l19:\r\njset #0x1fff, l29, l20 // ...if fragmentation offset != 0, goto l29 l20: ldxb 4*([14]\u00260xf) // X = IPv4 Header\r\nLength l21: ldb [x+26] // A = byte from offset X+26... Assume no IPv4 options so X=20; packet offset 46 = TCP\r\nsegment offset 12 l22: and #0xf0 // A = A \u0026 0xF0 (high nibble of TCP offset 12 = Data offset = TCP header size\r\nin 32-bit words) l23: rsh #2 // A = A \u003e\u003e 2 (this has the effect of multiplying the high nibble by four, e.g\r\nA\u003e\u003e4 then A\u003c\u003c2). A now contains number of bytes in the TCP header l24: add x // A = A + X. Adding IPv4 header\r\nlength + TCP header length. l25: tax // X = A l26: ldh [x+14] // A = halfword from packet offset X+14 (14 is\r\nethernet header, x is IPv4+TCP header, so this offset is first TCP payload byte) l27: jeq #0x5293, l28, l29 //\r\nif A==0x5293 goto l28, else goto l29 l28: ret #0xffff // return match l29: ret #0 // return doesn't-match\r\nPseudocode. \"return false\" means packet doesn't match; \"return true\" means packet matches. if (EtherType ==\r\nIPv4) { if (Packet is an additional piece of a fragmented packet) { return false; } else { if (Protocol == UDP\r\n\u0026\u0026 data[0:2] == 0x7255) { return true; } else if (Protocol == ICMP \u0026\u0026 data[0:2] == 0x7255 \u0026\u0026 ICMP Type == Echo\r\nRequest) { return true; } else if (Protocol == TCP \u0026\u0026 data[0:2] == 0x5293) { return true; } else { return\r\nfalse; } } } else { return false; }\r\nTo get past the filter you will need to send the right data in the packet as shown above.\r\nThe filter rejects most traffic from entering the main packet decoding loop so the implant will run with very little CPU\r\nsignature. Packets that make it through the BPF check are quickly checked for a valid password before any further\r\noperations take place.\r\nPacket Capture and Firewall Bypass\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 4 of 9\n\nThe relevance of the BPF filter and packet capture is that it is sniffing traffic at a lower level than the local firewall. This\r\nmeans that even if you run a firewall the implant will see, and act upon, any magic packet sent to the system. The\r\nfirewall running on the local host will not block the implant from having this visibility. This is an important point to\r\nunderstand.\r\nFurther, if you have a network perimeter firewall, but it allows traffic to a host on ICMP, UDP or TCP to any port, then the\r\nimplant can see it. Any inbound traffic to the sever can activate the magic packet check and initiate a backdoor.\r\nFor instance, if you run a webserver and lock it down so only port TCP 443 can be accessed, the attacker can send a magic\r\npacket to TCP port 443 and activate a backdoor. Same for any UDP packet or even a simple ICMP ping. We'll talk about\r\nhow it does this below.\r\nLocating Packet Sniffing Processes\r\nFinding a process sniffing packets on Linux by hand is not always obvious. It's just not normal for most people to check for\r\nsuch things and as a result something like BPFDoor can remain around for a long time unnoticed.\r\nHowever, with this malware in a wait state loop searching for packets you can look for traces left under the process stack by\r\nviewing /proc/\u003cPID\u003e/stack. With BPFDoor we can see references to function calls in the Linux kernel that indicate the\r\nprocess is likely grabbing packets.\r\nYou can search the entire /proc/*/stack area for any process that is showing packet capture functions like the above:\r\ngrep packet_recvmsg /proc/*/stack grep wait_for_more_packets /proc/*/stack\r\nFalse alarms with this search are possible, but you can narrow down possible candidates like below. The red arrow is the\r\nPID in question running BPFDoor.\r\nThe above is time consuming though and not practical in many cases. Instead, we recommend an automated sweep from\r\nSandfly to quickly identify all processes with packet sockets in operation. With this, BPFDoor is immediately found. The\r\npacket capture socket in operation shows up easily and there is no mistaking that this process is reading network traffic.\r\nRC4 Encryption and Passwords\r\nTo access the implant you need not just a magic packet, but also the correct password. The leaked source has some\r\npasswords set, but there is no reason to believe these are used in actual deployment.\r\nThe implant uses RC4 as the encryption layer. RC4 is a very robust cipher for this application and is the only truly secure\r\ncipher you can write on a napkin. It's a great choice for small implant code like this.\r\nIn the case of the implant we will deduct a few points because they did not throw out the first few kilobytes from the cipher\r\nstream which can weaken it, but overall this cipher is a good choice to keep things small and fast.\r\nThe implant can take an optional password. The password is compared against two internal values. If it matches one value it\r\nwill setup a local bindshell backdoor. If it matches another it will do a reverse bindshell connect-back to the specified host\r\nand port.\r\nThere is a third option though and that is if no password is specified, then a function is called that sends a single UDP packet\r\nwith the value \"1\". This might be some kind of operation check status to show the implant is still running. Relevant code\r\nbelow:\r\nif ((s_len = sendto(sock, \"1\", 1, 0, (struct sockaddr *)\u0026remote, sizeof(struct sockaddr))) \u003c 0) { close(sock);\r\nreturn -1; }\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 5 of 9\n\nNote the above is not passed through the RC4 encryption. If you are investigating this on your network, it may be\r\nworthwhile looking for single UDP packets with just the data \"1\" in them and nothing else from many hosts over time to a\r\nsingle host IP (controller).\r\nFirewall Bypass for Bindshell Backdoor\r\nThe implant has a unique feature to bypass the host firewall and make the traffic look legitimate. When the magic packet is\r\nreceived by the host, the implant will spawn a new instance and change the local iptables rules to do a redirect from the\r\nrequesting host to the shell port.\r\nFor instance, the implant can redirect all traffic from the attacker using TCP port 443 (encrypted web) to the shell.\r\nExternally, the traffic will look like TLS/SSL traffic but in fact the attacker is interacting with a remote root shell on the\r\nsystem.\r\nLet's review what this means with a diagram:\r\nThe steps are as follows if the actor requests the system open a local shell:\r\n1) Implant is listening to all traffic coming to the host regardless of firewall.\r\n2) Implant sees magic packet.\r\n3) Magic packet can contain IP address, port and password for attacker. Otherwise it uses the origin IP address.\r\n4) Depending on password, implant will open local or connect-back backdoor.\r\n5) Implant selects a TCP port sequentially starting at 42391 up to 43391.\r\n6) Implant binds to first unused port in this range.\r\n7) For local shell, iptables is called to redirect all traffic from attacker host IP from the requested port to the bound port\r\nrange from the above steps.\r\n8) Attacker connects with TCP to the defined port they requested (e.g. TCP port 443).\r\n9) Traffic from that host is redirected from the port to the shell routing behind the firewall.\r\n10) Observed traffic still appears to be going to host on a legitimate port, but in fact is being routed to the shell on the host.\r\nIf this is confusing, then let's look at the shell in action using SSH as our target port.\r\nNOTE: We disabled the RC4 encryption in the implant for example purposes to use netcat. The real implant would\r\nrequire the correct password and RC4 encryption layer to see these results.\r\nBelow we connect to a host on SSH port 22. We get back a normal OpenSSH banner. Then on another window we send the\r\nmagic packet on UDP to the host (or TCP or ICMP). The implant sees this packet and that we want to use TCP port 22 as\r\nour shell access port. The implant starts a shell on a high TCP port and then redirects the traffic. When we connect again to\r\nport 22, instead of SSH we now get a shell with root access.\r\nHere again is the important point: All other users still get SSH. Only the attacker's traffic is redirected to the shell even\r\nthough it goes to the same SSH port!\r\nYou'll see also when you connect the value \"3458\" is sent above. This may be a version identifier for the implant operator.\r\nThe redirect rules for the shell access are seen below. Here you see that the TCP port 42392 was found available and the\r\nshell bound to it. All TCP port 22 traffic from our attacker host (192.168.1.1) is now routed to this shell on this port. The\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 6 of 9\n\ntraffic looks like encrypted SSH communications going to TCP port 22, but in reality is being directed to the shell port once\r\nit hits the iptables rule for the attacker host only.\r\n/sbin/iptables -t nat -D PREROUTING -p tcp -s 192.168.1.1 --dport 22 -j REDIRECT --to-ports 42392\r\n/sbin/iptables -D INPUT -p tcp -s 192.168.1.1 -j ACCEPT\r\nConnect-Back Bindshell\r\nThe implant also has the ability to connect back to a host as defined in the magic packet. Operation here is largely the same,\r\nbut this may not be as stealthy having a system connect outbound (and many orgs may block servers talking outbound). The\r\nfirst method of packet redirect is far more dangerous and harder to find as it will look like legitimate traffic going to the\r\nserver and not originating outbound.\r\nStatus Check\r\nAs discussed above, if you do not supply any password or an incorrect password in a magic packet the implant will simply\r\nsend out \"1\" on UDP. We believe this is some kind of status check to allow keeping tabs on many systems.\r\nOrganizations may want to consider running a network scan against their hosts sending a magic packet on ICMP,\r\nUDP or TCP with a known UDP port you monitor to see if any systems respond. Any host responding has an active\r\nimplant.\r\nShell Anti-Forensics and Evasion\r\nThe shell is spawned by forking a controller and finally the shell itself. The controlling PID will be masquerading running\r\nunder the name:\r\n/usr/libexec/postfix/master\r\nThe shell itself will be running under the name:\r\nqmgr -l -t fifo -u\r\nIn the ps listing you'll see the following. Here the implant is restarted under a new bogus name. Then you see the two\r\nprocesses masking the shell operation when it is operating.\r\nAgain if you go under /proc/\u003cPID\u003e and do a listing you will see the reference to the real names.\r\nSandfly hunter view shows the mismatch between the shell and the masquerading names it is using. Here the masquerading\r\nname clearly does not match the shell path and actual process name we saw.\r\nThe shell also sets up some anti-forensics for good measure. The environment is carefully selected to only have the\r\nfollowing. We'll use strings /proc/\u003cPID\u003e/environ to look at what it is doing below:\r\nroot@bpfdoor:/# strings /proc/2500/environ HOME=/tmp PS1=[\\u@\\h \\W]\\\\$ HISTFILE=/dev/null\r\nMYSQL_HISTFILE=/dev/null\r\nPATH=/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:.\r\nvt100\r\nThe implant is telling the shell to not log shell history and also does the same for MySQL. This means that the operators\r\nlikely are doing a lot of work with MySQL to call this out specifically. The listing of kerberos in the path also means that\r\nkerberos authentication systems may be a frequent target.\r\nSandfly finds this shell in numerous ways, but the anti-forensics is a dead giveaway it's up to no good.\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 7 of 9\n\nImplant Termination\r\nThe implant has mechanisms to terminate itself if there is an error or for other reasons. It will clean up its dropper file and\r\nexit cleanly. There are no destructive commands built into the implant, but obviously a root shell is all you need.\r\nSandfly Detection\r\nAlthough the implant takes many measures to hide, it is easily found if you know where and how to look. Sandfly finds it\r\neasily and would have been able to for quite a while now.\r\nA host running this backdoor will have many distinct and very severe Sandfly alerts that something is wrong. Although the\r\ntechniques here will help incident responders investigate their hosts by hand, we offer a free 500 host license for Sandfly\r\nthat will do it much faster and more completely.\r\nConclusions\r\nThis implant is well executed and layers known-tactics such as environment anti-forensics, timestomping, and process\r\nmasquerading effectively. The use of BPF and packet capture provides a way to bypass local firewalls to allow remote\r\nattackers to control the implant. Finally, the redirect feature is unique and very dangerous as it can make malicious traffic\r\nblend in seamlessly with legitimate traffic on an infected host with exposed ports to the internet.\r\nThe code does not reveal much about the authors, but it clearly was done by someone that knows what they are doing with\r\nan intent to remain undetected.\r\nIndicators of Compromise\r\nUse these to help manually search for BPFDoor. Please see our Linux compromise cheat sheet for commands to help you\r\nwith these checks.\r\nDo not use hashes to find this malware. Hashes work very poorly on Linux to find malware as the binaries are easily re-compiled and changed. This kind of malware needs tactics hunting to find it consistently.\r\nHunting Tactics\r\nPossible binary left behind if implant fails to load:\r\n/dev/shm/kdmtmpflush\r\nDropper if implant active or did not clean up:\r\n/var/run/haldrund.pid\r\nDeleted process called kdmtmpflush or similar.\r\nProcesses missing environment variables.\r\nAny process running from /dev/shm\r\nAny process operating with a packet socket open that you don't recognize as needing that kind of access.\r\nProcess stack trace showing kernel function calls involved with packet capture:\r\ngrep packet_recvmsg /proc/*/stack grep wait_for_more_packets /proc/*/stack\r\nUnusual redirect rules in iptables.\r\nAny process bound to TCP port 42391-43391 as a listening service.\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 8 of 9\n\nSystem boot scripts referencing unusual binaries or strange path locations.\r\nUDP outbound traffic containing only the data \"1\" perhaps from many hosts back to a single IP for status checks.\r\nLow bandwidth intermittent data streams to ports where you'd expect high traffic. For instance someone using an interactive\r\nshell sending manual commands with long latency between packets (e.g. using a bindshell backdoor) would be an unusual\r\npattern on a webserver pushing big data over TCP port 443 to web browsers.\r\nPost Tags:\r\nShare this post:\r\nSource: https://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nhttps://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://sandflysecurity.com/blog/bpfdoor-an-evasive-linux-backdoor-technical-analysis/"
	],
	"report_names": [
		"bpfdoor-an-evasive-linux-backdoor-technical-analysis"
	],
	"threat_actors": [
		{
			"id": "9c8a7541-1ce3-450a-9e41-494bc7af11a4",
			"created_at": "2023-01-06T13:46:39.358343Z",
			"updated_at": "2026-04-10T02:00:03.300601Z",
			"deleted_at": null,
			"main_name": "Red Menshen",
			"aliases": [
				"Earth Bluecrow",
				"Red Dev 18"
			],
			"source_name": "MISPGALAXY:Red Menshen",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434696,
	"ts_updated_at": 1775791992,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/03024125af7f94341afef701b3299542f647b96a.pdf",
		"text": "https://archive.orkl.eu/03024125af7f94341afef701b3299542f647b96a.txt",
		"img": "https://archive.orkl.eu/03024125af7f94341afef701b3299542f647b96a.jpg"
	}
}