← All posts

How to Detect a Cryptominer on a Linux Server

Aswad Gul · 2026-08-12 · 8 min read

Most compromised Linux servers do not get used for anything dramatic. They get used to mine cryptocurrency, because it converts stolen compute directly into money with no further effort from the attacker. If you are wondering what happens to a server after a webshell or a weak SSH password gets exploited, this is usually it.

The naive detection is "look for high CPU," and it catches the careless miners. The competent ones throttle specifically to defeat that check.

Key Takeaways

  • Cryptojacking is the default monetisation of a compromised server, which makes it the most likely thing you will actually find.
  • CPU usage is a useful first signal and a poor sole signal, because throttled miners stay under any threshold you set.
  • Outbound network behaviour is harder to hide than CPU, because a miner must reach a pool to be paid.
  • Miners persist aggressively, cron, systemd units, and library preloading are all common, so killing the process is not remediation.
  • A miner is a symptom. The entry point is the actual problem, and it is still open until you find it.

Table of Contents

Why cryptojacking and not something worse

From an attacker's perspective a small business Linux server is not interesting for its data. It is interesting for its CPU, its bandwidth, and the fact that nobody is watching it closely. Mining requires no target research, no negotiation, and no buyer. It starts paying immediately and continues until someone notices.

This has a practical consequence for detection priorities. Exotic threats get the attention in security writing; mining is what you will actually encounter. It is worth having a specific check for it rather than hoping general monitoring covers it.

The obvious check, and its limits

Start here, because it is free and it does catch the lazy ones:

ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -15

Signals worth reading closely in that output:

  • A process consuming most of a core with a name you do not recognise
  • A long etime on something you never started
  • A binary running from /tmp, /dev/shm, /var/tmp, or a user's home directory
  • A process name designed to look plausible, kworkerd, systemd-network, [kswapd0] with brackets faked to imitate a kernel thread

Check where a suspicious process actually runs from, since the name in ps is attacker-controlled:

ls -l /proc/<PID>/exe
cat /proc/<PID>/cmdline | tr '\0' ' '; echo

If exe points at a deleted file, that is significant on its own, the binary was unlinked after execution specifically to complicate exactly this investigation.

Now the limitation. Mining pools support throttling, and attackers who want to persist use it. A miner configured to take 30% of one core on an eight-core box adds a few percent to total utilisation, which looks like normal variance on any dashboard and trips no threshold you would be willing to set. Some go further and pause when they detect an interactive login, so the server looks clean precisely when you are looking at it.

CPU is worth checking. It is not sufficient.

Network signals are harder to hide

A miner has one requirement it cannot throttle away: it must talk to a mining pool, continuously, or the attacker earns nothing. That makes outbound network behaviour the more reliable signal.

See what is actually connected and which process owns each connection:

ss -tupn state established

What to look for:

  • Connections to ports commonly used by pools, 3333, 4444, 5555, 7777, 14444, though these are configurable and not definitive
  • A long-lived connection to an IP with no business relationship to your application
  • Any outbound connection owned by a process that has no reason to make one
  • Steady traffic to a single destination that never varies

Cross-reference against what should be listening and connecting:

ss -tulpn
lsof -i -n -P 2>/dev/null | grep -v ESTABLISHED

This is where per-server baselining earns its place, and why it beats any fixed rule. There is no universal list of acceptable outbound destinations, a mail server, a CI runner, and a static site have completely different legitimate profiles. What is detectable is deviation from a given server's own established pattern. A machine that has connected to the same six destinations for three months and now maintains a persistent connection to a seventh has told you something, without anyone having to write a rule about port numbers.

DNS is another angle, since many miners resolve pool hostnames rather than hardcoding IPs. Unexpected lookups for pool domains, or a sudden switch to an external resolver, are both worth flagging.

Finding persistence

Assume the miner is designed to survive both a reboot and your first attempt at removing it. Check the common mechanisms:

# scheduled tasks, all users
crontab -l 2>/dev/null
for u in $(cut -f1 -d: /etc/passwd); do crontab -l -u "$u" 2>/dev/null | sed "s/^/[$u] /"; done
ls -la /etc/cron.d/ /etc/cron.*/ 2>/dev/null

# systemd units, including user-level
systemctl list-units --type=service --all --no-pager | grep -iv "loaded active\|not-found"
systemctl list-timers --all --no-pager
ls -la /etc/systemd/system/ /usr/lib/systemd/system/ ~/.config/systemd/user/ 2>/dev/null

# library preloading, a common and easily missed technique
cat /etc/ld.so.preload 2>/dev/null
ls -la /etc/ld.so.conf.d/

# shell profile persistence
grep -rn "curl\|wget\|base64\|/tmp/" /etc/profile /etc/profile.d/ ~/.bashrc ~/.bash_profile 2>/dev/null

/etc/ld.so.preload deserves particular attention. A library preloaded there is injected into every dynamically linked process on the system, which is how some miners hide themselves from ps and ls entirely. If that file exists and you did not create it, treat the machine as fully compromised, the tools you are using to investigate are no longer trustworthy.

This is exactly the class of change that file integrity monitoring is for: cron directories, systemd unit paths, and /etc/ld.so.preload are static on a normal server, so any write to them is worth an alert. Which paths to watch and how to keep the output readable is covered in what file integrity monitoring actually catches on Linux.

What to do after you find one

Killing the process is the least important step, and doing it first destroys evidence you will want.

Collect before you clean. Record the process tree, the binary path and hash, open connections, and the contents of any cron or unit files involved. If this turns out to touch client data you may have a disclosure obligation, and reconstructing the timeline later from memory is not adequate.

Find the entry point. This is the part people skip, and it is the only part that prevents recurrence. A miner did not appear on its own. The realistic candidates: a web application vulnerability that dropped a shell, SSH credentials that were guessed or reused, or an exposed service, Redis, Docker's API, a database, reachable from the internet without authentication. Start with how to detect a webshell on a Linux server, then check what your SSH logs show, then enumerate what is actually listening publicly.

Check for escalation and lateral movement. Attackers who get a foothold frequently add a user, plant an SSH key, or grant sudo rights as a fallback. Working through detecting privilege escalation on a Linux server matters here, as does the broader sweep in how to tell if your Linux server has been compromised.

Rebuild if you can. Once something has run as root, proving the machine is clean is harder than reprovisioning it. If you have infrastructure as code and current backups, rebuild from a known-good image and restore data selectively. Cleaning in place is a reasonable choice when rebuilding is genuinely impossible, but be clear that it is the weaker option.

Rotate everything the server held. SSH keys, API tokens, database credentials, anything in environment files. Assume all of it was read.

SecAI watches for this pattern directly rather than relying on a CPU threshold: process and listener monitoring flags new executables and unexpected outbound behaviour, per-server baselining catches deviation from each machine's own normal connection profile, and file integrity monitoring covers the persistence paths above including /etc/ld.so.preload and the cron and systemd directories. Findings arrive as ordered remediation steps rather than raw alerts, alongside the rest of the detection stack.

For how this detection sits alongside everything else worth running, see the Linux server security software guide.

Frequently Asked Questions

Can a cryptominer run without root? Yes. Mining needs CPU, not privileges. A miner running as www-data from a webshell works fine, which is why "no root compromise" is not reassurance.

How much does cryptojacking actually cost me? Directly: degraded application performance, higher bills on metered compute, and possible provider action if outbound abuse is detected. Indirectly, and more importantly: an attacker has code execution on your server and chose mining. Next time they may choose something else.

Will antivirus software catch a Linux miner? Sometimes, for known binaries. Miners are trivially recompiled and repacked, so signature detection alone is unreliable. Behavioural signals, unexpected process, unexpected outbound connection, unexpected persistence entry, hold up better.

My CPU is normal. Am I clear? Not necessarily. Throttled miners deliberately stay under CPU thresholds. Check established outbound connections and the persistence locations above before concluding anything.

How do I stop this happening again? Reduce what is reachable and detect changes fast. A practical Linux server hardening checklist for small teams covers the reduction side; continuous process, network and file integrity monitoring covers the detection side.

Process and resource anomalies like these are one of the things automated Linux server monitoring is watching for continuously.

SecAI monitors Linux servers for exactly these threats automatically.