ldpreload Malware Overview
POC Malware LD_PRELOAD – Project Overview
Disclaimer: This project was built purely for educational purposes as part of a school assignment. It was also my very first real project written in C. Everything described here was tested in an isolated, controlled environment (Docker containers). Do not use any of this outside of a lab setup.
What is this project?
This is a proof of concept (POC) malware written in C that abuses the Linux LD_PRELOAD mechanism to intercept SSH credentials on a compromised machine and exfiltrate them to a remote Command & Control (C2) server over SSL.
The project is split into four main components:
- The malware (
malware.so) – a shared library injected viaLD_PRELOAD - The loader – a fake “V-Bucks generator” used to deploy the malware
- The C2 server – receives stolen credentials over an encrypted SSL connection
- The database – stores the exfiltrated data locally on the C2 server (more on this below)
The LD_PRELOAD Technique
LD_PRELOAD is a Linux environment variable that tells the dynamic linker to load a specific shared library before all others when a program starts. This means any function defined in that library will take precedence over the real one from libc or any other system library.
This is a well-known technique used legitimately for things like debugging or mocking. Here, it’s used offensively to hook system calls at the userland level — no kernel exploit required.
The malware hooks several key libc functions:
| Hooked Function | Purpose |
|---|---|
read | Intercepts data being read from file descriptors (captures SSH password input) |
write | Monitors outgoing data |
open | Intercepts file open calls |
readdir | Hides the malware’s presence from directory listings |
The most impactful hook is on read: when an SSH client reads the password typed by the user, the hook captures it before it’s processed, giving us plaintext credentials.
Hiding itself
A notable stealth trick: the malware hooks readdir and open to hide the /etc/ld.so.preload file from standard tools like ls or cat. This makes it significantly harder for a user to notice the infection just by browsing the filesystem.
The Loader – A Fake V-Bucks Generator
The initial infection vector is a binary disguised as a Fortnite V-Bucks generator. When executed (typically tricked into running with sudo), it silently:
- Connects to the C2 server and downloads
malware.so - Writes the path to
malware.sointo/etc/ld.so.preload
/etc/ld.so.preload is a system-wide file that lists shared libraries to preload for every process on the system. Writing to it requires root — hence why social engineering the victim into running the loader with sudo is part of the attack chain.
Once this file is written, every new process spawned on the system will load malware.so automatically. Persistence is achieved.
The C2 Server
The C2 server is written in C and uses OpenSSL to secure communications. It listens for incoming connections from infected machines and receives stolen credentials.
Key characteristics:
- SSL/TLS encrypted channel – credentials are not sent in plaintext over the network
- Uses POSIX threads (
pthread) to handle multiple clients concurrently - On reception of credentials, forwards them to the local database process via a socket
The server runs on port 6000 and acts as the backbone of the whole operation.
The Database – B-Tree in C
The database component was a school exercise in data structures. It implements a B-Tree from scratch in C to store and query the received credentials.
It communicates with the C2 server locally via a socket on port 7777. In practice, its role is straightforward: persist the stolen data so it can be retrieved and queried later.
Architecture Overview
+------------------+ +---------------------+ +-------------------+
| | | | | |
| sshvictims | <──── | victimsdebian | ────> | serverc2 |
| (SSH Server) | | (Malware active) | | (SSL + DB + .so) |
| | | | | |
+------------------+ +---------------------+ +-------------------+The full demo environment is dockerized with three containers on a private subnet (172.21.0.0/16):
| Container | IP | Role |
|---|---|---|
victimedebian | 172.21.0.10 | Infected victim machine |
victimessh | 172.21.0.11 | SSH server the victim connects to |
serverc2 | 172.21.0.12 | C2 server + database + malware binary |
Attack Flow – Step by Step
1. Infection
The victim runs the loader (sudo ./loader). It downloads malware.so from the C2 server and writes its path into /etc/ld.so.preload. From this point, every process on the machine will load the malicious library.
2. Credential Capture
The victim connects via SSH to sshvictims:
When they type their password, the hooked read() function captures it in memory.
3. Exfiltration Trigger
The credentials are buffered and sent to the C2 server. In the demo, a curl request acts as the trigger that flushes the buffer and initiates the send:
curl https://example.com/This technique avoids suspiciously timed outbound connections right after an SSH session.
4. Storage
The C2 server receives the credentials over SSL and forwards them to the B-Tree database. The stolen data is now persisted and queryable.
Building the Project
The project compiles cleanly with a single make at the root:
makeThis produces:
server/server– the C2 server binaryserver/malware.so– the LD_PRELOAD shared libraryldpreload_malware/loader/loader– the fake V-Bucks loaderdb/projectdb– the B-Tree database binary
Dependencies: gcc, make, libssl-dev, Linux.
To spin up the full demo environment:
docker compose up --build -dWhat I Learned
This was my first serious C project, and it covered a lot of ground:
- Low-level shared library mechanics and the ELF dynamic linker
- Function interposition with
LD_PRELOADanddlsym(RTLD_NEXT, ...) - Network programming in C (BSD sockets, SSL with OpenSSL)
- Multi-threaded servers with
pthreads - Implementing a B-Tree data structure from scratch
- Docker networking and multi-container setups
The project is far from production-grade code and has plenty of rough edges — but as a learning exercise in systems programming and offensive security fundamentals, it covered more ground than any textbook exercise could.