Skip to content

Back to the catalog

dfir.chwriteup

bedevil: Dynamic Linker Patching

A deep technical analysis of the bedevil (bdvl) LD_PRELOAD rootkit's "dynamic linker patching" feature, which the threat actor Muddled Libra used against VMware vCenter servers. Instead of writing to /etc/ld.so.preload directly, bedevil binary-patches the system's ld.so dynamic linker files in place to point at a randomly-named preload path, evading common ld.so.preload/LD_PRELOAD detection checks. The post walks through bedevil's setup.py and ldpatch.h/patch.c source, then demonstrates investigation techniques — strace on the linker's initial access() call, rpm -V glibc/debsums integrity checks, and using statically linked find/strings/cp binaries to bypass the rootkit's hooked syscalls — and briefly notes the OrBit rootkit as a similar case.

TL;DR Analysis of the bedevil (bdvl) LD_PRELOAD rootkit's dynamic-linker-patching evasion technique, plus strace/rpm -V/static-binary methods to detect it.
Document

What it is

The bedevil (bdvl) Linux rootkit's _ldpatch/ldpatch functions, which patch the on-disk dynamic linker (e.g. /lib64/ld-linux-x86-64.so.2) instead of relying on /etc/ld.so.preload. Controlled by PATCH_DYNAMIC_LINKER = True in setup.py (the default). Muddled Libra used bedevil against VMware vCenter (per Unit42, 2024).

How it works

_ldpatch(path, oldpreload, newpreload) reads a linker file into memory, scans byte-by-byte for the literal string /etc/ld.so.preload, and overwrites it in place with a replacement path. The replacement is generated per-host by 'PRELOAD_FILE':ut.randpath(18) in setup.py, so the preload path differs on every machine and cannot be threat-hunted as a fixed IOC.

The hard constraint worth remembering: the patch is in-place and must not change file size, so the function returns early if strlen(oldpreload) != strlen(newpreload). Because /etc/ld.so.preload is 18 characters, the randomized replacement is also exactly 18 characters (randpath(18)). The linker then reads that alternate file to load the syscall-hooking shared library.

Which files get patched is defined by the ldhomes array — the rootkit searches these directories for a valid ld.so to modify:

/lib
/lib32
/lib64
/libx32
/lib/x86_64-linux-gnu
/lib/i386-linux-gnu
/lib/arm-linux-gnueabihf

./bdv uninstall reverses the patch, restoring the original /etc/ld.so.preload string.

What to do

Standard LD_PRELOAD checks (inspecting /etc/ld.so.preload contents or the environment variable) will miss this — the reference is baked into the linker binary itself, pointing at a random 18-char path. Investigate the linker binaries in the ldhomes paths directly: a clean linker still contains the literal string /etc/ld.so.preload; a patched one has that 18-byte region replaced with a random path. The post cites Tony Lambert's approach of matching against the expected string ("If you get a match, your linker probably hasn't been tampered with") — the fetched text is truncated here, so treat the exact detection command as unconfirmed and verify against the original post/tweet.

Caveats

The Investigation section is cut off mid-quote in the available text, so the concrete detection command is not fully captured. The 18-byte equality is the reliable anchor: any replacement path is exactly as long as /etc/ld.so.preload, which is what makes an in-place string comparison across the ldhomes linkers a viable check.

Organisations named here

  • bdvl
  • LD_PRELOAD
  • OrBit

Technologies named here

  • VMware vCenter servers
  • strace
  • glibc
  • RPM-based Linux distributions
  • xxd
  • cat
  • Debian-based systems
  • find
  • ld-linux-x86-64.so.2 / ld-2.17.so / ld-lsb-x86-64.so.3
  • strings
  • cp
  • ldd
  • grep
  • file
  • rpm -V glibc
  • debsums
  • Linux

Techniques named here

  • Dynamic Linker Hijacking / Patching
  • Random path generation for evasion
  • Syscall hooking to conceal files
  • Detection via strace on process execution
  • Detection via static binary usage
  • Detection via package integrity verification
  • Detection via grep/strings on dynamic loader binaries

Threat actors named here

  • Muddled Libra
  • bedevil
  • OrBit