HaxRob's Avatar

HaxRob

@haxrob.net.bsky.social

Telco / mobile and IoT security. Surfing the information super highway one keystroke at a time. https://haxrob.net

423 Followers  |  62 Following  |  38 Posts  |  Joined: 12.11.2024  |  2.5844

Latest posts by haxrob.net on Bluesky

Preview
Hiding in plain sight (part 3) - Mount namespaces Introduction The following post explores a relatively unknown technique on Linux offering the ability to conceal artifacts on the filesystem with an exceptional level of stealth. We will explore how ...

Full writeup including mitigations, threat hunting and other detection ideas.👇
(7/7)

haxrob.net/hiding-in-pl...

13.07.2025 07:39 — 👍 1    🔁 0    💬 0    📌 0
Post image

This method can be utilized to perform process masquerading..

Here an implant appears to be running from /usr/sbin/auditd but it's actually 'fileless'.

No '(deleted)', no ':memfd', no '/dev/shm', no ptrace, no LD_PRELOAD. Just stealth.

(6/7)

13.07.2025 07:39 — 👍 0    🔁 0    💬 1    📌 0
Post image

Malware can use the unshare() or clone() syscalls to create the new mount and user namespaces. The uid/grp mapping is done by writing to procfs followed by mount().

If the process enters a spin lock, it can be used to keep a persistent hold of the 'stash space'

(5/7)

13.07.2025 07:39 — 👍 0    🔁 0    💬 1    📌 0
Post image

Create a new mount and user namespace, mapping the unprivileged uid to uid 0.

Here the root user logs in [4] and can't see the file created by the unprivileged user in the /root directory
(4/7)

13.07.2025 07:39 — 👍 0    🔁 0    💬 1    📌 0

As a bonus, commands in this shell will not be written to the history file as we mounted over the user's home directory.

No need to set HISTFILE=/dev/null.
Once the shell exits, artifacts evaporate. Nothing touches the disk.

Now how to do this as an unprivileged user? (3/7)

13.07.2025 07:39 — 👍 0    🔁 0    💬 1    📌 0
Post image

Let's start with the most simple example. Select a mount namespace that is not used by systemd/init.

Migrate the current shell into that process's mount namespace and mount a tmpfs file system.

Anything that writes the mounted path is concealed from users on the host. (2/7)

13.07.2025 07:39 — 👍 0    🔁 0    💬 1    📌 0

A relatively unknown but particularly stealthy technique to hide files on Linux hosts. On unhardened boxes, unprivileged users can conceal files from even the root user. Disk content remains in memory, hindering disk acquisition during forensic investigation. (1/7) 👇

13.07.2025 07:39 — 👍 6    🔁 1    💬 2    📌 0
Preview
BPFDoor: Past and present An exploration the archeological roots of the BPFDoor Linux malware along with it's newest evasive techniques.

Full writeup:
haxrob.net/bpfdoor-past...
(21/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 0    📌 0
Post image

There is a particular byte sequence used here that might have some meaning. The hex encoded bytes can be copied from the blog entry linked below if others would like to have a go at this piece of the puzzle.

(20/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Another interesting feature is the ability to configure the masqueraded process name and implant password. Rather then depend on an external config file, it modifies itself.

(19/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Unlike the familiar BPFDoor, it has a persistence mechanism built in - specify 'x' as an argument and it modifies the system wide bash profile for all users

(18/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

BPFDoor would write a file to /var/run as a mutex lock (to prevent multiple instances. NotBPFDoor uses a semaphore by calling semget. The semaphore key is an epoch timestamp - Friday, June 5, 2015. Interesting

(17/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

It's 'NotBPFDoor' because it does not use BPF filters. When looking for magic packets, the user space process receives all TCP traffic. An early revision of BPFDoor?

(16/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

So what does this really tell us? Perhaps BPFDoor in some form or another has been around for quite some time and may give proximity to a particular intrusion set.

Next we have what I'll call "NotBPF" with the first submitter from HK in 2016. Let's look into it.

(15/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

The sniffdoor notes reveal future ambitions that made it's way into BPFDoor (img from writeup: haxrob.net/bpfdoor-past...)

(14/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image Post image

We also see overlapping code with the WNPS rootkit

(13/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

sniffdoor was advertised in hacking forums in 2007

(12/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

How about the BPF "client / controller"? Also overlapping code / strings with sniffdoor

(11/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Sniffdoor and BPFDoor have quite some overlapping code.

(10/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

The "Just for Fun" ASCII program author also had a blog with the same title. On the archived blog are links to source code to various software they had written. The "adore-ng" rootkit should be familiar to some. But what is "sniffdoor"?

(9/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

... justforfun is the password found in the leaked BPFDoor source code. It's also the password used in samples found in the wild.

"Just For Fun" is the name of a biography by Linux Torvalds. Just a coincidence?

(8/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image Post image

A few weeks after that date, a simple program was published where a tank fires shells across the terminal. A program "Just For Fun". Why does the phrase sound familiar ?

(7/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Since we are taking a closer look at #BPFDoor, let's do a bit of digging. Remember this hard coded epoch timestamp used for tampering it's file modified time- October 30, 2008 ?

(6/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image Post image

So while it looks the process has a socket open for UDP only, the malware can still receive the same TCP, UDP and ICMP magic wakeup packets - making if functionally equivalent to how it behaves when raw sockets was used.

(5/21)

Super tricky!

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

And this explains this change: The first byte is expected to be the first byte of a IP packet. In the leaked BPFDoor source, we see it considers the size of an ethernet header (14 bytes).

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

$ man socket.7 gives some clues. It hints with AF_PACKET, the protocol may have priority over the socket type. So ETH_P_IP overrides SOCK_DGRAM. Also, the layer 2 (ethernet) frame will be removed.

(3/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Perhaps it's only looking for UDP magic packets? Not so fast. Let's look at what changed.

BPF filter is used as before, but the socket is opened with type SOCK_DGRAM, but the protocol is ETH_P_IP.

What's the defined behaviour here?
(2/21)

02.06.2025 14:27 — 👍 0    🔁 0    💬 1    📌 0
Post image

Newer variants of the #BPFDoor has an interesting modification made that avoids detections looking for processes with raw sockets. The kernel reports SOCK_DGRAM rather then rather loud "SOCK_RAW". Here we have a sample found in the recent SK telco breach.

(1/21)

02.06.2025 14:27 — 👍 1    🔁 2    💬 1    📌 0

That was a fun episode 🌶️ 🌶️

27.12.2024 11:01 — 👍 0    🔁 0    💬 0    📌 0

Nice work, very promising project 👍

25.11.2024 00:29 — 👍 0    🔁 0    💬 0    📌 0

@haxrob.net is following 20 prominent accounts