
Reproduziert nicht authentifizierten ZendTo-ClamAV-RCE und Root-Rechteausweitung in einer autorisierten Laborumgebung, mit festgepinntem Docker-Ziel, Fail-Closed-Verifizierung, Nonce-gebundener Ausgabe und Bereinigung.
Dieses Verzeichnis ist ein eigenständiges Reproduktionsbündel für autorisierte Labore der kontolosen ZendTo-zu-ClamAV-Code-Ausführungskette sowie ihrer separaten Smarty-/Root-Cron-Fortführung mit Standardprofil. Es enthält:
Der initiale PoC führt einen vom Aufrufer gewählten Befehl als das Standard-Dienstkonto clamav aus. Die optionale Variante erweitert diesen kontolosen Einstiegspunkt zu einem vom Aufrufer gewählten Befehl als root. Beide verwenden standardmäßig id, lehnen den wörtlichen Pfad /root/flag ab und liefern nonce-gebundene Ausgaben über HTTPS.
Die verwundbaren Gruppen-, Verzeichnis-, Smarty- und Root-Cron-Beziehungen entsprechen den Debian-Paket-/Installationsstandardwerten von ZendTo. Die Erreichbarkeit von root ist dennoch umgebungsabhängig: Diese exakte positive Testumgebung verwendet ein ext4-gestütztes /var/zendto-Volume, funktionierendes PHP-CLI-FFI/POSIX/exec und einen uneingeschränkten clamd-Prozess. Das Erzwingen von AppArmor/SELinux oder inkompatible Dateisystem-Semantik kann die Fortführung auf einer ansonsten unveränderten Installation blockieren.
Verwenden Sie dies nur auf der enthaltenen Wegwerf-Testumgebung oder einem anderen System, das Sie ausdrücklich testen dürfen.
Das maßgebliche exakte Ziel ist ein lokales, absichtlich nicht versioniertes Artefakt unter:
image/zendto-installer-systemd-debian12.tar.zst
Git ignoriert Docker-Image-Archive. Legen Sie vor der exakten Regression eine autorisierte lokale Kopie an diesem Pfad ab; scripts/setup.sh erwartet die aufgezeichnete SHA-256-Prüfsumme und Image-ID. source-recipe/README.md dokumentiert, wie das aus dem Installer abgeleitete Image erstellt und erfasst wurde. Ein neuer Build aus Live-Paketquellen ist für Topologietests nützlich, wird aber nicht als byte-identisch mit dem gepinnten Ziel angenommen.
Das Setup und der Container-Entrypoint lehnen jede Abweichung vom folgenden Profil ab:
Die vollständigen Werte stehen in PROFILE.json.
Das ist stärker als nur die ClamAV-Paketversion zu pinnen. Die Allokator-Konstruktion hängt ebenfalls von glibc, dem CVD-gesteuerten Parser-Verkehr, den Worker-Einstellungen und der exakten Ziellibrary ab. FreshClam ist im erfassten Image deaktiviert, und der Start schlägt fehl, wenn daily.cvd abgewichen ist oder eine daily.cld aufgetaucht ist.
Der derzeit langlaufende Forschungscontainer im übergeordneten Workspace ist nicht die saubere Testumgebung: Spätere Tests haben dessen Formular für externe Absender deaktiviert und seine daily-Datenbank aktualisiert. Diese Änderungen sind hier bewusst ausgeschlossen. Dieses Bündel verwendet die saubere Baseline, gegen die die native Ausführung demonstriert wurde.
/sys/fs/cgroupzstd, Python 3 mit venv, ein C-Compiler, file und GNU readelfDas Ziel teilt sich den Host-Kernel und die ASLR-Implementierung. Kernabhängiges Mapping-Verhalten bleibt daher eine Portabilitätsvariable.
Es sollte jeweils nur eine systemd-Testumgebung den Host-cgroup-Namespace teilen. Stoppen Sie auf dem ursprünglichen Forschungsrechner die ältere Testumgebung, ohne sie zu löschen:
docker stop zendto-installer-systemd-native
Sie kann später mit docker start zendto-installer-systemd-native wiederhergestellt werden.
Aus diesem Verzeichnis:
./scripts/verify-bundle.sh
./scripts/setup.sh
Das Setup-Skript:
.venv mit den gepinnten Python-Abhängigkeiten des PoC;/var/zendto-Volume und startet systemd; undrenameat2(RENAME_EXCHANGE), die als clamav ausgeführt wird.Die Standard-Endpunkte sind nur auf Loopback erreichbar:
http://127.0.0.1:18084/
https://127.0.0.1:18447/
Das Zertifikat ist selbstsigniert. Der PoC verwendet für jede HTTP-Anfrage bewusst verify=False. Vor dem Setup können andere Loopback-Ports gewählt werden:
export ZENDTO_HTTP_PORT=19084
export ZENDTO_HTTPS_PORT=19447
./scripts/setup.sh
Verwenden Sie für spätere Compose-/Helfer-Befehle dieselben Umgebungsvariablen.
Überprüfen Sie das Ziel jederzeit:
./scripts/verify-target.sh
docker compose ps
Die saubere Installer-Baseline enthält:
allowExternalUploads = TRUE
confirmExternalEmails = TRUE
captcha = google
Seine CAPTCHA- und Mail-Werte sind Installer-Platzhalter, sodass das unveränderte Archiv die öffentliche Verifikations-E-Mail nicht tatsächlich zustellen kann. Das native Regressionstesten hat nur diesen abgeschlossenen Anwendungsschritt durch eine äquivalente AuthData-Zeile für externe Absender repräsentiert. Der Zielcode, die Pakete, der Scanner, die Berechtigungen und der Exploit-Pfad wurden nicht gepatcht.
Erstellen Sie diese eine Labor-Zeile und eine Token-Datei mit Modus 0600 mit:
./scripts/mint-lab-auth.py [email protected]
Der Token-Wert wird nicht ausgegeben und unter folgendem Pfad gespeichert:
.lab/upload-auth-token.txt
Dieser lokale Helfer ist keine Behauptung, dass eine Bereitstellung mit deaktiviertem externen Upload aus der Ferne ausgenutzt werden kann. Wenn das öffentliche Formular für externe Absender deaktiviert ist, stoppt der PoC korrekt vor ClamAV, selbst wenn eine Token-Datei bereitgestellt wird.
Bei einer normal konfigurierten autorisierten Bereitstellung lassen Sie --external-auth-token-file weg: Öffnen Sie die Verifikationsseite manuell, lösen Sie das CAPTCHA, empfangen Sie die vom Ziel erzeugte Nachricht in einem angreiferkontrollierten Postfach und fügen Sie deren URL/Token an der verborgenen Eingabeaufforderung ein.
Dieser Modus sendet kein CAPTCHA, keine E-Mail, keine Capability, keinen Upload, kein Login-POST und keine Scanner-Inhalte. --skip-clamd-tcp-probe unterdrückt zusätzlich die optionale schreibgeschützte native TCP/3310-Prüfung:
mkdir -p -m 700 work
.venv/bin/python poc/zendto_6_15_8_unauth_clamav_rce.py \
https://127.0.0.1:18447 \
--enumerate-only \
--skip-clamd-tcp-probe \
--fingerprint-json work/fingerprint.json
Die Enumeration erzeugt weiterhin gewöhnliche Web-Zugriffsprotokolle und kann normale Anwendungs-Caches initialisieren. Ihr Ergebnis im Debian-/Ubuntu-Apache-Layout belegt nicht das native Paket, die Build-ID, die libc, die CVDs, die Socket-Richtlinie oder den MAC-Zustand. Das lokale Docker-Verifikationsskript liefert diese Belege für diese Testumgebung.
Dies validiert den Labor-Bearer und die Empfängerrichtlinie, übermittelt aber keine Datei- oder Scanner-Inhalte:
.venv/bin/python poc/zendto_6_15_8_unauth_clamav_rce.py \
https://127.0.0.1:18447 \
--sender-email [email protected] \
--recipient [email protected]. \
--external-auth-token-file .lab/upload-auth-token.txt \
--probe-only \
--no-open-browser
[email protected]. entspricht dem bewusst ungewöhnlichen internen Domänenwert test., der beim Erstellen dieser Installer-Testumgebung eingegeben wurde. Eine individuell angepasste echte Bereitstellung kann einen tatsächlich autorisierten Empfänger erfordern.
Warnung: Dies ist keine harmlose Scanner-Prüfung. Vor dem ersten Versuch sendet der Fernmodus EICAR, stürzt clamd mit dem PESpin-Diskriminator absichtlich ab, weist die socket-ausgelöste Wiederherstellung nach und führt zwei Terminal-Codepage-Sonden mit zusätzlichen Absturz-/Wiederherstellungszyklen aus. Abgelehnte Mappings töten clamd absichtlich.
Verwenden Sie ein frisches Arbeitsverzeichnis und einen harmlosen Befehl:
run_dir="work/run-$(date +%Y%m%d-%H%M%S)"
mkdir -m 700 "$run_dir"
.venv/bin/python poc/zendto_6_15_8_unauth_clamav_rce.py \
https://127.0.0.1:18447 \
--sender-email [email protected] \
--recipient [email protected]. \
--external-auth-token-file .lab/upload-auth-token.txt \
--oracle-conditioned-attempts 72 \
--command 'id; uname -a' \
--workdir "$run_dir" \
--keep-workdir
Der bevorzugte konditionierte Weg testet auf das nützliche Nibble-8-Mapping, bevor ein Korruptions-Träger übermittelt wird. Das aktuelle Drei-Layout-Aggregat ist eine spätere Lebenszyklus-Korrektur; seine historischen Ein-Layout-Orakel- und Same-Process-RCE-Phasen sind separat in docs/ dokumentiert.
Der blinde Fixed-Nibble-6-Fallback ist explizit verfügbar:
.venv/bin/python poc/zendto_6_15_8_unauth_clamav_rce.py \
https://127.0.0.1:18447 \
--sender-email [email protected] \
--recipient [email protected]. \
--external-auth-token-file .lab/upload-auth-token.txt \
--restart-resample-attempts 72 \
--command 'id; uname -a' \
--workdir work/blind-run \
--keep-workdir
Unter einem unabhängigen gleichverteilten Nibble-Modell entsprechen 47 frische Mappings etwa 95 % und 72 etwa 99 %. Das sind geometrische Mapping-Wahrscheinlichkeiten, keine End-to-End-Zuverlässigkeitsgarantien. Jedes abgelehnte Mapping dauert mindestens die 12-sekündige Wiederherstellungsverzögerung plus die erzwungene 40-sekündige Worker-Auslaufphase, ohne Scan-Zeit. Ein Lauf mit 72 Versuchen kann über eine Stunde dauern.
Das Ergebnis wird nicht aus einem Callback oder einer Webshell gelesen. Das DSO erstellt einen separaten, nur-Ausgabe-AuthData-Bearer mit 30 Minuten Gültigkeit, führt /bin/sh -c als clamav aus und liefert begrenzte stdout/stderr-Ausgaben über eine anonyme ZendTo-Seite zurück. Für einen Erfolg ist ein gerahmtes Ergebnis erforderlich, in dem alle folgenden Punkte konsistent sind:
zendto_unauth_clamav_rce_result=1Fehlende, doppelte, abgeschnittene oder nicht übereinstimmende Belege bedeuten einen fehlgeschlagenen Lauf.
Führen Sie dies erst aus, nachdem ./scripts/verify-target.sh sowohl für [target] als auch für [privesc-target] Erfolg meldet. Der Wrapper führt zunächst dieselbe kontolose ClamAV-Phase aus, verlangt deren exakten begrenzten Scharfschaltungs-Beleg und wartet dann auf den unveränderten Standard-Root-Cron-Konsumenten:
.venv/bin/python poc/zendto_clamav_to_root_smarty_privesc.py chain-unauth \
https://127.0.0.1:18447 \
--sender-email [email protected] \
--recipient [email protected]. \
--external-auth-token-file .lab/upload-auth-token.txt \
--oracle-conditioned-attempts 72 \
--root-command 'id; uname -a' \
--keep-workdir
Die Token-Datei-Option ist in der Testumgebung lediglich der Ersatz für die abgeschlossene E-Mail. Lassen Sie sie bei einem autorisierten öffentlichen Workflow weg und schließen Sie die CAPTCHA-/E-Mail-Aufforderung manuell ab. Von chain-unauth werden kein ZendTo-Benutzername und kein Passwort verwendet.
Die Root-Phase ist bewusst getrennt, auch wenn der Wrapper ihre Übergabe automatisiert. Sie:
savechunk.php hoch;clamav atomar ein geklontes Smarty-Kompilierverzeichnis aus;/zendto-root-result-<nonce>.json mit verify=False herunter und verlangt euid=0, den exakten Befehls-Hash, den Wiederherstellungsmarker und die Abschluss-Nonce.Cron kann den letzten Poll fast eine Stunde warten lassen; das Standard-Timeout beträgt 3900 Sekunden. Der Root-Befehl ist auf 1024 Bytes und 30 Sekunden begrenzt, mit höchstens je 1 MiB für stdout und stderr. Sein nonce-adressiertes JSON ist in diesem Wegwerf-Labor absichtlich im Web lesbar; verwenden Sie daher nur harmlose Testausgaben.
Für die manuelle Orchestrierung gibt emit den exakten Befehl aus, der an --command des kontolosen PoC zu übergeben ist; verwenden Sie nach dem Scharfschaltungs-Beleg poll mit der ausgegebenen Lauf-ID und der SHA-256-Prüfsumme des exakten Root-Befehls. Siehe docs/SMARTY_ROOT_BRIDGE.md für das Konstruktions- und Audit-Protokoll.
Es wird erwartet, dass diese Variante sicher stoppt, wenn eine Voraussetzung fehlt. Überlappen Sie keine Arme und wiederholen Sie keinen mehrdeutigen Lauf: Fehlgeschlagene Phasen können eine eingehende PHP-Datei, einen versteckten Klon, eine Sperre oder einen vertauschten Cache hinterlassen. Verwenden Sie für jeden Root-Test eine frische Testumgebung:
./scripts/reset-lab.sh --yes-delete-lab-volume
./scripts/mint-lab-auth.py [email protected]
Pro clamd-Prozess wird eine erfolgreiche Korruption unterstützt. Ein zweiter Aufruf ist nur vertretbar, nachdem die destruktive Recycle-Sonde eines frischen Laufs die erwartete Scanner-Fehlerantwort geliefert hat und EICAR die Wiederherstellung über den aktiven Socket belegt. Verwenden Sie keine Lauf-ID, keinen gestuften Chunk-Namen, keinen Ergebnis-Bearer und kein Client-Arbeitsverzeichnis erneut.
Stoppen Sie sofort bei jeder Weiterleitung, jedem Netzwerk-Timeout, jedem mehrdeutigen Body/Status, jeder unerwarteten sauberen Antwort oder jeder fehlgeschlagenen EICAR-Wiederherstellung. Übermitteln Sie die vorherige Korruptionsanfrage niemals manuell erneut an einen unsicheren Daemon.
Der gepackte Dienst hat Restart=no. Die Wiederholbarkeit ergibt sich aus dem weiterhin aktiven clamav-daemon.socket, nicht aus einer automatischen Dienst-Neustartrichtlinie. Wenn der Socket deaktiviert oder startbegrenzt ist, können absichtliche Abstürze den Scanner unverfügbar machen.
Zu den erwarteten Rückständen des Ziels gehören Zugriffs-/Fehlerprotokolle, clamd-Absturzaufzeichnungen oder -Cores, begrenzte Waisen-Claim-Dateien von sauberen Orakel-Wachen, ein append-only-DSO /var/zendto/incoming/Bridge<nonce>.1 und kurzlebige AuthData-Zeilen. Die Standardbereinigung entfernt gewöhnliche Waisen-Claims erst nach mehr als einem Tag.
Die Root-Variante hinterlässt zusätzlich einen Nonce-PHP-Armer, einen versteckten Klon und eine Sperre, das root-gehörige öffentliche JSON-Ergebnis sowie private stdout/stderr-Ausgaben unter /run. Ein erfolgreicher Wrapper stellt vor der Ausführung des Root-Befehls das echte templates_c wieder her, aber diese Beweisdaten bleiben erhalten, bis Container und Volume zurückgesetzt werden.
Widerrufen Sie den Labor-Upload-Bearer nach dem Test:
./scripts/revoke-lab-auth.py
Stoppen Sie das Ziel, während Sie das Beweis-Volume erhalten:
docker compose down
Löschen Sie für eine saubere frische Testumgebung ausdrücklich nur das benannte Volume dieses Projekts und starten Sie es aus dem gepinnten Image neu:
./scripts/reset-lab.sh --yes-delete-lab-volume
Archivieren Sie das Arbeitsverzeichnis und das Fingerprint-JSON vor dem Zurücksetzen, falls sie als Beweis benötigt werden.
docker-compose.yml exact systemd/socket target topology
PROFILE.json exact package/hash/CVD profile
image/*.tar.zst local ignored target artifact
poc/ no-account driver and support modules
third_party/ minimized builder/source/binary closure
scripts/setup.sh image/client/Compose setup
scripts/verify-bundle.sh delivery-manifest verification
scripts/verify-target.sh fail-closed target verification
scripts/verify-privesc-target.sh root-variant semantic preflight
scripts/mint-lab-auth.py local completed-email substitute
scripts/revoke-lab-auth.py remove that lab bearer
scripts/reset-lab.sh explicit clean-volume reset
source-recipe/ installer provenance, not exact rebuild
docs/ technical regression/audit notes
source-recipe/install.ZendTo.tgz und sein Runbook sind für den Herkunftsnachweis und die Quellkonstruktion enthalten. Behandeln Sie einen neuen Live-Repository-Build nicht als exakt: Der Installer pinnt nicht alle Pakete oder ClamAV-Datenbanken. Für eine exakte Regression muss das ignorierte lokale Image-Archiv mit PROFILE.json übereinstimmen.
MANIFEST.sha256 umfasst jede gelieferte Datei außer sich selbst. Docker-Image-Archive, der host-kompilierte Helfer third_party/installer-runtime/clamav-pespin/pespin_summit sowie die erzeugten Verzeichnisbäume .venv, .lab, work und __pycache__ werden ignoriert. Das Setup baut den Helfer aus seiner manifestierten C-Quelle neu und prüft das lokale Image separat.
Die statischen Prüfungen zur Paketierungszeit, der Remote-Preflight, das probabilistische Resampling und die instrumentierten End-to-End-Prüfungen sind in docs/BUNDLE_VALIDATION.md festgehalten. Der Bericht unterscheidet Remote-Beobachtungen von dem einen Validierungslauf, dem explizit eine lokal beobachtete Modulbasis bereitgestellt wurde.
| Komponente | Exakt getesteter Wert |
|---|
| Docker-Image-ID | sha256:de6d2f06ca04943362a9bdec5026e808448953728f31bd926343a4ed2ca2ef7c |
| ZendTo | 6.15-8 |
| ClamAV/libclamav-Paket | 1.4.3+dfsg-1~deb12u2 |
| libclamav | libclamav.so.12.0.3, SHA-256 55e3cd94…027c |
| libclamav-Build-ID | e6427ab62146ee3001fe463d12e797e9d25bf81a |
| glibc | 2.36-9+deb12u14, SHA-256 6b4a4535…421 |
| main-Datenbank | v63, SHA-256 0b2182d2…365 |
| daily-Datenbank | v28082, SHA-256 cddbcccf…906 |
| bytecode-Datenbank | v339, SHA-256 6d4aa01f…ffb |
| clamd | MaxThreads 12, IdleTimeout 30, Restart=no |
| Lebenszyklus | aktivierter clamav-daemon.socket, systemd-PID 1 |
| Web-Laufzeit | Apache 2.4.68, PHP 8.2.32 |
| MAC-Haltung | uneingeschränkte privilegierte Docker-Testumgebung |
| Root-Brücke | Standard-clamav in www-data; /var/zendto root:www-data 0775 |
| Root-Konsument | Standard-Root-Cleanup-Cron, stündlich zur Minute 25 |
| Smarty-Cache | deterministisch kompiliertes Smarty 4.5.4 zendto.conf |
| Austausch-Dateisystem | ext4-gestütztes benanntes /var/zendto-Volume |