InfraFenceInfraFence

Live Security Operations

Loslegen

So findest und entfernst du einen Krypto-Miner auf deinem Server

Zuletzt aktualisiert:

Ein Krypto-Miner ist das, was man auf einem kompromittierten Linux-Server am häufigsten findet. Er nimmt sich so viel CPU, wie er bekommt, und schürft damit Monero oder eine andere Kryptowährung für jemand anderen. Das erste Anzeichen ist oft eine langsame Website, ein Lüfter auf Volllast, eine Rechnung für CPU-Credits oder eine Abuse-Mail vom Provider.

Der Miner selbst ist der einfache Teil. Entscheidend ist, was ihn hereingelassen hat und was ihn zurückbringt: ein Cronjob, eine systemd-Unit, ein SSH-Schlüssel, eine Bibliothek, die in jeden Prozess vorgeladen wird. Geh in dieser Reihenfolge vor: finden, eindämmen, entfernen, den Einstiegspunkt finden, härten. Die Befehle gelten für Debian und Ubuntu sowie für die RHEL-Familie; PID steht für die Prozess-ID, die du in Schritt 1 findest.

Den Miner erkennen

Fang damit an, was die CPU belastet. Ein Miner belegt meist einen Prozess mit 100 % pro Kern, und das seit Tagen.

Jede Distribution
ps -eo pid,user,%cpu,etime,args --sort=-%cpu | head -n 15
  • Namen: xmrig und seine Varianten, oder Namen, die harmlos wirken sollen: kdevtmpfsi, kinsing, kworkerds, ein von Hand geschriebenes [kthreadd], eine zufällige Zeichenfolge.
  • Ein Kernel-Thread erscheint in eckigen Klammern und hat keine Binärdatei: Ein Name in Klammern, hinter dem ein Pfad steht, ist eine Fälschung.
  • Der Benutzer: Ein Miner, der als www-data, apache, nginx, redis oder postgres läuft, ist über diesen Dienst hereingekommen.

Bei einer verdächtigen PID siehst du dir die Binärdatei an, das Arbeitsverzeichnis, die vollständige Befehlszeile und welche systemd-Unit den Prozess gestartet hat:

Jede Distribution
sudo ls -l /proc/PID/exe /proc/PID/cwd
sudo tr '\0' ' ' < /proc/PID/cmdline; echo
systemctl status PID

Eine Binärdatei mit dem Vermerk (deleted) oder eine, die aus /tmp, /var/tmp oder /dev/shm läuft, ist ein starkes Indiz. Dieser Befehl listet alle solchen Prozesse auf einmal auf:

Jede Distribution
sudo ls -l /proc/[0-9]*/exe 2>/dev/null | grep -E '\(deleted\)|/tmp/|/var/tmp/|/dev/shm/'

Wenn top nichts zeigt: ld.so.preload

Ist die Last hoch, aber kein Prozess erklärt sie, versteckt sich der Miner womöglich hinter einer Bibliothek, die über /etc/ld.so.preload in jedes Programm geladen wird. Diese Datei gibt es normalerweise nicht. Existiert sie und nennt eine Bibliothek, die du nicht kennst, dann lügen dich ps und top an.

Jede Distribution
ls -l /etc/ld.so.preload 2>/dev/null && cat /etc/ld.so.preload
sudo grep -l LD_PRELOAD /proc/[0-9]*/environ 2>/dev/null

Verbindungen zu einem Mining-Pool

Miner sprechen mit ihrem Pool über das Stratum-Protokoll. Ports wie 3333, 4444, 5555, 7777 und 14444 sind typisch, Pools lauschen aber auch auf 443 und 80. Sieh dir deshalb auch die Verbindungen des Prozesses selbst an:

Jede Distribution
sudo ss -tnp state established '( dport = :3333 or dport = :4444 or dport = :5555 or dport = :7777 or dport = :14444 )'
sudo ss -tnp state established | grep PID

Die Konfigurationsdateien von Minern enthalten meist eine Pool-URL. Dieser Befehl sucht an den üblichen Stellen danach:

Jede Distribution
sudo grep -rIl -E 'stratum\+(tcp|ssl)://|"pools"|donate-level' /tmp /var/tmp /dev/shm /root /home /var/www /etc 2>/dev/null

Was ihn zurückbringt

Such nach Persistenz, bevor du irgendetwas beendest, damit du weißt, was du entfernen musst. Zuerst Cron: Zeilen, die mit curl oder wget herunterladen, base64 dekodieren oder aus /tmp starten.

Jede Distribution
sudo cat /etc/crontab
sudo ls -la /etc/cron.d /etc/cron.hourly /etc/cron.daily /var/spool/cron 2>/dev/null
for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"; done
sudo grep -rE 'curl|wget|base64|/tmp/|/dev/shm' /etc/crontab /etc/cron.* /var/spool/cron 2>/dev/null

Dann die systemd-Timer und die Unit-Dateien, die in den letzten 30 Tagen geändert wurden:

Jede Distribution
systemctl list-timers --all
sudo sh -c "find /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /root/.config/systemd /home/*/.config/systemd \
  -type f \( -name '*.service' -o -name '*.timer' \) -mtime -30 2>/dev/null"

Dann SSH-Schlüssel, die du nicht hinzugefügt hast, rc.local, Shell-Startdateien und Konten, die du nicht angelegt hast:

Jede Distribution
sudo sh -c 'cat /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/null'
ls -l /etc/rc.local 2>/dev/null
sudo sh -c "grep -lE 'curl|wget|/tmp/|/dev/shm' /etc/profile.d/* /etc/bash.bashrc /etc/bashrc /root/.bashrc /root/.profile /home/*/.bashrc 2>/dev/null"
awk -F: '$3 == 0 || $3 >= 1000 {print $1, $3, $7}' /etc/passwd

Prüfe zum Schluss, ob die Binärdateien des Systems selbst ersetzt wurden. Die Ausgabe listet Dateien aus Paketen, deren Inhalt sich geändert hat; Konfigurationsdateien sind ausgenommen.

Debian / Ubuntu
sudo dpkg --verify | grep -v ' c /'
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo rpm -Va 2>/dev/null | grep -E '^..5' | grep -v ' c /'

Den Miner eindämmen

Wenn dein Provider einen Snapshot der Festplatte anlegen kann, mach das jetzt: Er sichert die Beweise und einen Weg zurück. Dann schneidest du den Miner von seinem Pool ab. Ersetze 198.51.100.23 durch die Pool-Adresse aus Schritt 1. Diese nftables-Tabelle funktioniert unter Debian, Ubuntu und der RHEL-Familie neben ufw oder firewalld und ist nach einem Neustart wieder weg.

Jede Distribution mit nftables
sudo nft add table inet quarantine
sudo nft 'add chain inet quarantine out { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet quarantine out ip daddr 198.51.100.23 drop

Sichere eine Kopie der Binärdatei und ihrer Befehlszeile, bevor sie gelöscht wird. /proc/PID/exe funktioniert auch dann noch, wenn die Datei auf der Festplatte schon entfernt wurde. Den SHA-256 kannst du in öffentlichen Malware-Datenbanken nachschlagen.

Jede Distribution
sudo mkdir -p /root/evidence
sudo cp /proc/PID/exe /root/evidence/miner.bin
sudo tr '\0' ' ' < /proc/PID/cmdline | sudo tee /root/evidence/cmdline.txt
sudo sha256sum /root/evidence/miner.bin

Friere den Prozess zuerst ein, damit ein Watchdog nicht bemerkt, dass er stirbt, und ihn sofort neu startet. Sieh dir seinen Elternprozess an und beende ihn dann. Ist der Elternprozess ein Skript oder ein zweiter Miner-Prozess, kümmere dich auch um diesen.

Jede Distribution
sudo kill -STOP PID
ps -o pid,ppid,user,args -p PID
sudo kill -9 PID

Achtung: Geh davon aus, dass jedes Geheimnis auf dem Server bekannt ist: SSH-Schlüssel, Passwörter, die Datenbankpasswörter und API-Schlüssel in .env und in Konfigurationsdateien. Ändere sie von einem sauberen Rechner aus, beginnend mit den Konten, die Zugriff auf andere Server haben.

Den Miner entfernen und alles, was ihn zurückbringt

Entferne jedes Stück Persistenz, das du in Schritt 1 gefunden hast, und danach die Binärdateien. Für eine systemd-Unit (ersetze NAME):

Jede Distribution
sudo systemctl disable --now NAME.service
sudo rm /etc/systemd/system/NAME.service
sudo systemctl daemon-reload
  • Cron: Lösche die Zeilen mit sudo crontab -e -u USER und die Dateien in /etc/cron.d, die du nicht angelegt hast.
  • SSH: Lösche die Schlüssel, die du nicht kennst, aus jeder authorized_keys.
  • Konten: Sperre oder lösche Benutzer, die du nicht angelegt hast (sudo usermod -L NAME), und prüfe /etc/sudoers und /etc/sudoers.d/.
  • Binär- und Konfigurationsdateien des Miners, wo auch immer Schritt 1 sie gefunden hat.

Miner machen ihre Dateien oft unveränderlich, sodass rm selbst als root mit Operation not permitted scheitert. Prüfe die Attribute zuerst und entferne sie:

Jede Distribution
sudo lsattr /path/to/file
sudo chattr -i -a /path/to/file
sudo rm /path/to/file

Nennt /etc/ld.so.preload eine Bibliothek, die du nicht kennst, verschiebe die Datei (legitime Software nutzt sie nur selten) und lösche die Bibliothek, die darin stand:

Jede Distribution
sudo mv /etc/ld.so.preload /root/evidence/ld.so.preload
sudo ldconfig

Starte neu und prüfe die CPU nach einer Stunde erneut, und noch einmal am nächsten Tag: Kommt der Miner zurück, ist noch ein Stück Persistenz oder der Einstiegspunkt vorhanden.

Achtung: Lief der Miner als root, wurden System-Binärdateien geändert oder wurde ld.so.preload verwendet, kannst du nicht sicher sein, dass der Server sauber ist. Setz ihn aus einem frischen Image neu auf und spiel die Daten aus einem Backup von vor der Infektion zurück, nachdem du es geprüft hast. Eine Bereinigung im laufenden System ist nur vertretbar, wenn der Miner als unprivilegierter Benutzer lief und sich außerhalb der Dateien dieses Benutzers nichts geändert hat.

Herausfinden, wie er hereingekommen ist

Wenn du den Weg hinein nicht schließt, ist der Miner in wenigen Tagen wieder da. Der Benutzer, als der der Miner lief, und der Zeitpunkt, zu dem seine Dateien angelegt wurden, weisen darauf hin:

Jede Distribution
ps -o user,pid,lstart,args -p PID
sudo stat /path/to/miner
  • Läuft als Benutzer des Webservers: ein verwundbares Plugin, Theme oder eine verwundbare Anwendung, oder ein Upload-Formular. Sieh dir die Web-Logs rund um den Zeitpunkt an, zu dem die Datei aufgetaucht ist.
  • Läuft als redis, oder die Dateien wurden von diesem Benutzer angelegt: Redis ohne Passwort aus dem Internet erreichbar.
  • Von einem Container oder von dockerd gestartet: die Docker-API offen auf 2375 oder 2376.
  • Läuft als root oder als normaler Benutzer mit einer Anmeldung kurz davor: ein schwaches Passwort oder ein gestohlener SSH-Schlüssel.
SSH-Anmeldungen
last -i -n 50
sudo journalctl --since "14 days ago" | grep -E "Accepted (password|publickey)"
Webserver-Logs
sudo grep -hE 'wget|curl|base64|%2Fbin%2Fsh|/bin/sh' \
  /var/log/nginx/access.log* /var/log/apache2/access.log* /var/log/httpd/access_log* 2>/dev/null | tail -n 50

Und die Dienste, die häufig als Einstieg dienen, wenn sie auf allen Schnittstellen lauschen: die Docker-API, Redis, Webkonsolen auf 8080, Elasticsearch, MongoDB, Memcached.

Jede Distribution
sudo ss -tlnp | grep -E ':(2375|2376|6379|8080|9200|27017|11211)\b'

Den Server danach härten

  • Schließ den Einstiegspunkt, den du gefunden hast: Aktualisiere oder entferne die Anwendung, binde Redis und die Datenbanken mit Passwort an localhost, stell die Docker-API nie offen ins Netz.
  • SSH nur mit Schlüsseln und ohne root-Login: siehe So stoppst du SSH-Brute-Force-Angriffe.
  • Installiere Updates, schalte automatische Sicherheitsupdates und die Firewall ein: siehe Einen neuen VPS absichern: die Checkliste.
  • Begrenze ausgehenden Verkehr, wo es geht: Ein Webserver muss nur selten Verbindungen zu beliebigen Ports aufbauen.
  • Überwache ab jetzt CPU-Last, ausgehende Verbindungen und Änderungen an Cron, systemd und SSH-Schlüsseln, damit der nächste Miner in Minuten auffällt und nicht erst nach Wochen.

Wie InfraFence einen Krypto-Miner erkennt

Mehrere Detektoren von InfraFence decken die Schritte oben ab, jeder von einer anderen Seite:

  • Prozesserkennung: Ein laufender Prozess, dessen Name oder Befehlszeile zu einem bekannten Miner (xmrig, minerd, cpuminer und andere), einer Stratum-URL oder einem bekannten Pool passt, wird als kritisch gemeldet, mit PID und Befehlszeile. Auch Reverse Shells und Skripte, die aus /tmp laufen, werden gemeldet.
  • Malware-Scan: Signaturen für Krypto-Miner, Web-Shells und Backdoors in deinen Websites, täglich aktualisierte YARA-Regeln und ein Abgleich der System-Binärdateien mit der Paketdatenbank (dpkg -V / rpm -Va).
  • Ausgehender Verkehr und DNS: Verbindungen zu Adressen auf öffentlichen Bedrohungslisten und jede DNS-Anfrage, dem Programm zugeordnet, das sie gestellt hat.
  • Dateiintegrität: Von /etc/ld.so.preload, den Crontabs, den systemd-Units und jeder authorized_keys werden Hashes gebildet und überwacht, und jede Änderung löst sofort einen Alarm aus.
  • Härtungsprüfungen, die die üblichen Einfallstore melden: aus dem Internet erreichbare Datenbanken, veraltete Software, SSH mit Passwörtern.

Die Prozessprüfung vergleicht Namen und Befehlszeilen: Ein umbenannter Miner, der seinen Pool aus einer Konfigurationsdatei liest, fällt dabei nicht auf und bleibt den anderen Detektoren überlassen. Die Bereinigung aus dieser Anleitung musst du weiterhin selbst erledigen.

Fragen

Kann ich den Prozess nicht einfach beenden?
Er kommt wieder. Miner richten einen Cronjob, eine systemd-Unit oder einen SSH-Schlüssel ein, um neu zu starten, und die Lücke, durch die sie hereingekommen sind, ist weiterhin offen. Entferne die Persistenz und schließ den Einstiegspunkt.
Muss ich den Server neu installieren?
Wenn der Miner als root lief, System-Binärdateien geändert wurden oder /etc/ld.so.preload verwendet wurde: ja, denn du kannst nicht nachweisen, dass der Server sauber ist. Lief er als unprivilegierter Benutzer und hat sich sonst nichts geändert, kann eine sorgfältige Bereinigung genügen.
Mein Provider sagt, der Server schürft Kryptowährung, aber ich sehe nichts. Warum?
Der Miner kann über /etc/ld.so.preload versteckt sein, in einem Container laufen oder per Cron nur zu bestimmten Uhrzeiten starten. Prüfe die Preload-Datei, docker ps und die Verbindungen, die der Server über die Zeit aufbaut.

Kostenlos auf 1 Server testen

Starter ist für einen Server kostenlos, mit vollem Schutz und automatischen Sperren. Ohne Kreditkarte.

Installiere den Agenten als root, mit deinem Token anstelle von <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

Das Token erstellst du im Dashboard unter Server › Server hinzufügen.