📑 Daftar Isi
- Step 0 — Know Your Baseline
- Step 1 — Grab the Big Picture With top
- Step 2 — Get the Full List With ps
- Step 3 — Check What's Talking to the Outside World
- Step 4 — Hunt Deleted Files Still in Use
- Step 5 — Comb Through Cron Jobs
- Step 6 — Go Forensic Inside /proc
- Step 7 — Verify, Then Kill, Then Clean the Root
- Quick Reference: Suspicious Process Patterns
- FAQ
- Q: How do I tell a normal process from a suspicious one?
- Q: Is the server safe once I kill the process?
- Q: Are top and ps enough to detect intrusions?
- Q: Are there automated tools that help?
- Wrapping Up
Skip the small talk. You’re staring at a Linux box that’s acting up — CPU pinned at 100%, outbound traffic you don’t recognize, or a ticket from a client saying their site feels slow. You need to find the culprit now, not in an hour. Good news: every command in this guide is built into Linux, so you can start immediately without installing a single package. Bad news: if you’ve never thought about what’s “normal” on this server, you’re flying blind. Let’s fix that first.
One ground rule before we touch anything: detect first, verify second, kill third. Jumping straight to kill -9 is how you lose forensic evidence, take down a production service by accident, and leave the attacker’s persistence intact. If you only kill the process, the cron job or backdoor will just bring it right back. So do the steps in order. It’s actually faster than cleaning up after a panic kill.
Step 0 — Know Your Baseline
Here’s the thing about detecting something suspicious: you can’t spot an intruder if you don’t know who’s supposed to be home. Before an incident, write down what normal looks like on that box. Which processes run at boot, which user owns your web app, which outbound connections happen on a quiet Tuesday. It doesn’t have to be fancy — a note in a ticket or a README is fine. I’ve seen too many incidents where the “weird process” turned out to be a legitimate agent a colleague installed last week. A five-minute baseline check saves you from those false alarms.
If you haven’t done that yet, do it now for your critical servers. It’s the single cheapest security investment you’ll make all year. And while you’re at it, make sure SSH auth is key-only, because most compromises I’ve handled started with a weak password being brute-forced. See our SSH key hardening guide if that’s not the case yet.
Step 1 — Grab the Big Picture With top
Open your terminal and take a wide snapshot first. Don’t jump straight into deep dives — you need context before detail.
top -c -o %CPU -n 1
The -c flag shows the full command path, which is the first thing I check. Process names are easy to fake; the path is harder. A process named kworker0 that resolves to /var/tmp/.x/kworker0 is not the kernel’s kworker — the real one doesn’t have a path at all. Also note the user column. A process running as root that you never scheduled is worth a second look immediately. Note the PID of anything suspicious and move on; top is a map, not a verdict.

Step 2 — Get the Full List With ps
Now list processes sorted by resource usage so the heavy hitters float to the top:
ps aux --sort=-%cpu | head -20
ps aux --sort=-%mem | head -20
Read the COMMAND column carefully. You’re looking for patterns that don’t belong: curl | sh pipelines, base64 -d, references to /tmp or /dev/shm, or command lines pointing at mining pools. A classic example looks like this:
www-data 24680 2.0 1.2 481224 9088 ? S 00:12 0:03 ./xkcd -a -o stratum+tcp://xmr.pool:443 -u wallet_address -p x
That’s an XMRig coin miner running as the web server user. It got in through an unpatched web app, and nobody noticed because it’s only using 2% CPU. Note the PID, then check what it’s talking to.
Step 3 — Check What’s Talking to the Outside World
Malware has to phone home eventually. Checking outbound connections catches more intruders than any other single step, and it’s criminally underused. See every established TCP connection with its owning process:
ss -tunap | grep ESTAB
Scan the peer addresses. Unknown IPs, weird ports like 4444, 6666, 3333, or anything going to a datacenter that has nothing to do with your business — flag them. If your box only serves web traffic on 80/443, there’s no legitimate reason for a 4 a.m. outbound connection to an overseas IP. If you already have a PID from an earlier step, map it directly:
lsof -p PID -i
I once chased a process that was barely using any CPU — it would never have shown up in top. But its socket to a mining pool reconnected every five minutes like clockwork, and ss caught it in one shot. Never skip this step.
Step 4 — Hunt Deleted Files Still in Use
This is the trick that separates juniors from seniors. Good malware runs from /tmp, then deletes its own file to hide the evidence. The process keeps running happily, but its binary is gone. Linux lets you see exactly that:
lsof +L1 | grep -i deleted
Any process holding a deleted file deserves a close look. Then confirm where its real binary lives:
ls -la /proc/PID/exe
The exe symlink can’t be faked as easily as a process name. If it points to /tmp/… (deleted) or /dev/shm, you’ve found your malware — it’s deliberately hiding itself.
Step 5 — Comb Through Cron Jobs
Attackers don’t want their malware to die on reboot, so they set up persistence. Cron is still the favorite spot. Check everything:
for user in $(cut -f1 -d: /etc/passwd); do echo "== $user =="; crontab -u $user -l 2>/dev/null; done
cat /etc/crontab
ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/
You’re looking for cron entries that fetch or run something: wget, curl, base64, or scripts living in /tmp. A normal cron entry is short and obvious — “backup database at 2 a.m.” A suspicious one is long, obfuscated, and downloads from a URL you’ve never seen. Also check systemd timers and rc.local, since smarter malware has moved on from cron:
systemctl list-unit-files --state=enabled | grep -E "tmp|shm|update|hidden"
Step 6 — Go Forensic Inside /proc
Still suspicious? Time to look under the hood. Each running process has a virtual directory under /proc that reveals everything about it:
cat /proc/PID/cmdline | tr ' ' ' '
cat /proc/PID/environ | tr ' ' 'n' | head -30
ls -la /proc/PID/fd | head -30
cat /proc/PID/status | grep -E "Name|State|PPid"
cmdline shows the real arguments, environ shows environment variables (I’ve found wallet addresses and C2 configs here), fd lists every open file descriptor, and status gives you the parent PID — which is useful for tracing back how the process was spawned. A pile of deleted files in /dev/shm or /tmp is the usual pattern here.
Step 7 — Verify, Then Kill, Then Clean the Root
Okay, you have a strong suspect. Resist the urge to nuke it. Verify first:
grep -i "PID" /var/log/syslog /var/log/auth.log 2>/dev/null
strings /proc/PID/exe | grep -iE "miner|stratum|pool|tcp://" | head -20
If the binary contains mining pool strings, case closed. Then kill:
kill -9 PID
killall -9 process_name
Now the part most people skip: find and close the entry point. Delete the malicious cron entry, remove the dropped file, check authorized_keys for unknown SSH keys, inspect /etc/ld.so.preload for library hijacking, and rotate every credential that might have been exposed. If you don’t do this, the same attacker re-enters through the same hole tonight. Close unused ports, slap fail2ban on SSH, and lock down access.
Warning: Never kill a suspicious process before documenting it. Record the PID, full command line, binary path, outbound IPs, and timestamps. If this becomes a real incident, that evidence is priceless — and it disappears the second you hit kill.
Quick Reference: Suspicious Process Patterns
| Signal | Command | Meaning | Action |
|---|---|---|---|
| Single process pinned at 90%+ CPU | top -c -o %CPU | Likely miner or runaway job | Record PID, inspect cmdline |
| Name mimics a system process (systmed, kdevtmpfs) | ls -la /proc/PID/exe | Spoofed name | Verify binary path |
| Outbound connection to unknown IP | ss -tunap | grep ESTAB | C2 or mining pool | Block IP, trace PID |
| Process running a deleted file | lsof +L1 | grep deleted | Self-hiding malware | Inspect /proc/PID/environ |
| Cron entry with wget/curl/base64 | crontab -l; ls /etc/cron.d/ | Persistence payload | Remove entry, find source |
| New user or fresh logins | last; cat /etc/passwd | Backdoor account | Disable user, reset passwords |
| Binary dropped in /tmp and running | ps aux –sort=-%cpu | Download-and-exec attack | Kill, delete, patch the hole |
FAQ
Q: How do I tell a normal process from a suspicious one?
The rule is simple: if you can’t explain what it does, treat it as suspicious. Build a baseline of what normally runs on the box — which users, which commands, which connections. Then compare. Real kernel threads like kworker appear without a user and without a path; malicious processes almost always have a path, usually in /tmp, /dev/shm, or /var/tmp, and run as a specific user.
Q: Is the server safe once I kill the process?
Not yet. Killing is symptom removal. You have to close the root cause — the way the attacker got in — or they’ll be back within hours, through a cron job, a web shell, or an SSH backdoor you haven’t found. Always follow up: check cron, authorized_keys, /tmp and /dev/shm, update software, and rotate credentials.
Q: Are top and ps enough to detect intrusions?
They’re a good starting point but not enough on their own. Decent malware throttles its CPU, mimics system names, and persists via cron or systemd. That’s why the full flow matters: top, ps, ss, lsof, crontab, and /proc. Cross-checking several sources is what makes you confident before you act.
Q: Are there automated tools that help?
Yes. chkrootkit and rkhunter catch classic rootkits, Lynis runs a hardening audit, and ClamAV scans files for known malware. For real-time visibility, Netdata can alert you when a new process appears or CPU spikes — check our Netdata monitoring guide. Just remember: tools filter, humans decide.
Wrapping Up
Detection isn’t a mystery once you have a method. Work the steps in order: baseline, top, ps, sockets, deleted files, cron, then /proc. Nine times out of ten the culprit shows up in the first two. When it doesn’t, the deeper checks are exactly where it’s hiding.
Bookmark this page for your next on-call shift and run the commands on a test box until they’re muscle memory. If you want to go further, our Linux hardening best practices and high-load troubleshooting guide are the natural next reads. That’s it — three commands in, you’re already ahead of most people. Done.