
Un fuzzer de plugins de WordPress de prueba de concepto
Un fuzzer de plugins de WordPress como prueba de concepto que llevó al descubrimiento de más de 300 vulnerabilidades en plugins de WordPress instalados en casi 30 millones de sitios.
La técnica utilizada se describe en https://kazet.cc/2022/02/03/fuzzing-wordpress-plugins.html
Si deseas continuar la investigación, comienza con plugins menos populares: si un plugin alcanzó al menos 10 000 instalaciones activas entre octubre de 2021 y enero de 2024, lo más probable es que ya haya revisado los informes del fuzzer (y me centré especialmente en plugins con al menos 20 000 instalaciones activas). Debido a la gran aleatoriedad en el funcionamiento del fuzzer, algunas vulnerabilidades en estos plugins pueden permanecer sin descubrir, aunque son menos.
Los informes del fuzzer contienen muchos falsos positivos: la mayoría no indican una vulnerabilidad. Después de ver un informe, primero analiza si el comportamiento que observas es realmente una vulnerabilidad o un falso positivo. No envíes informes crudos del fuzzer a WPScan o a los proveedores; en su lugar, proporciona un exploit PoC.
Por razones obvias, los ejemplos contendrán solo vulnerabilidades que ya han sido corregidas.
Supongamos que estás fuzzeando responsive-vector-maps en la versión 6.4.0:
./bin/fuzz_object plugin responsive-vector-maps --version 6.4.0
(para fuzzear la última versión, simplemente omite --version).
Una vez que el fuzzing finalice (lo que tomaría entre 10 y 30 minutos para este plugin), puedes ejecutar:
./bin/print_findings data/object_fuzz_results/
Verás, entre otros:
.
Eso significa que el fuzzer detectó la ejecución de fopen() sobre un payload conocido.
La mayoría de los payloads contienen la palabra GARLIC para facilitar la detección automática
en la salida. Puedes verlos o configurarlos en docker_image/magic_payloads.php.
Luego, puedes examinar el código fuente y notar que el endpoint wp_ajax_rvm_import_markers
usa el contenido del archivo para generar la salida, lo que permite leer archivos arbitrarios
en el servidor: CVE-2021-24947.
Lo que ves en blanco es un crash considerado interesante (puedes modificarlos o agregar nuevos
en crash_detectors.py). El verde es el contexto. En azul ves el nombre del archivo del informe
(con el nombre del plugin), la popularidad del plugin y el nombre del endpoint (aquí: el nombre de la acción ajax).
Los datos en amarillo son los payloads que se inyectaron en qué variables.
Supongamos que estás fuzzeando page-builder-add en la versión 1.4.9.4:
./bin/fuzz_object plugin page-builder-add --version 1.4.9.4
Después de imprimir los resultados, verás que un payload conocido se ha reflejado en la salida:
.
Luego puedes probar manualmente si realmente este lugar (recuerda: en azul tienes el nombre del endpoint, aquí: el nombre de la página del menú) es vulnerable a XSS. En este caso, lo es: CVE-2021-25067.
./bin/fuzz_object plugin duplicate-page-or-post --version 1.4.6
Después de imprimir los resultados, verás que se llama a update_option:
.
El análisis del código del endpoint te indicará que esto efectivamente lleva a una vulnerabilidad de XSS almacenado: CVE-2021-25075.
Desafortunadamente, para la mayoría de los plugins el fuzzer no encuentra ningún crash interesante, y para el resto, la mayoría de los informes son falsos positivos. Por ejemplo, si ves:
Call: wp_mail arguments={'to': '[email protected]', 'subject': '[Plugin contact] - http://GARLICGARLICGARLIC.example.com'}
Esto puede significar que wp_mail sí se llama, pero no controlas el destinatario
ni la mayor parte del asunto. Si quieres estar seguro, revisa el código fuente del plugin.
__GARLIC_ACCESSED__ _FILES[files] __ENDGARLIC__ — eso indica que se detectó el acceso
a un archivo subido. No se realizan más comprobaciones por ahora; para verificar si esto es una
vulnerabilidad, examina el código.$_GET['page'] si deseas que se muestre una página de menú específica.La primera ejecución del fuzzing o de las pruebas puede tomar alrededor de una hora, porque necesitamos construir la imagen Docker con PHP y WordPress instrumentados.
./bin/fuzz_object plugin PLUGIN_SLUG
./bin/fuzz_object theme THEME_SLUG
También puedes instalar un plugin desde un archivo zip local:
./bin/fuzz_object plugin PLUGIN_FILE_NAME.zip
Para imprimir lo que encontró el fuzzer, usa:
./bin/print_findings data/object_fuzz_results/
Para ejecutar las pruebas, usa:
./bin/test
Advertencia: las pruebas toman mucho tiempo (más de una hora) y, como verifican si el fuzzer encontraría vulnerabilidades, fallan con cierta probabilidad.
wpgarlic usa pre-commit para ejecutar linters y formatear el código.
pre-commit se ejecuta en CI para verificar que el código esté formateado correctamente.
Para ejecutarlo localmente, usa:
pre-commit run --all-files
Para configurar pre-commit para que se ejecute antes de cada commit, usa:
pre-commit install
Puedes iniciar un entorno de prueba con solo un plugin instalado usando:
./bin/manual_testing PLUGIN_SLUG|PLUGIN_PATH.zip [version]
Puedes instalar un plugin usando su slug o desde un archivo zip local.
Escuchará en http://127.0.0.1:8001/
Habrá dos usuarios de prueba en la base de datos:
Esta herramienta es una prueba de concepto — esta sección contiene lugares donde se puede mejorar para encontrar más vulnerabilidades.
Puedes editar filtering.py — contiene las reglas que determinan si un crash particular se considera
importante o no. Si las cambias, puedes tener más falsos positivos, pero también encontrar más vulnerabilidades.
Por ejemplo, el único encabezado que considero interesante cuando se emite es el encabezado Location,
para detectar vulnerabilidades de Open Redirect. Esa es solo una idea y puedes tener otras.
Otro archivo que vale la pena extender es docker_image/patch_wordpress.sh. Describe
las llamadas a qué funciones se registrarán como interesantes.
Si deseas inyectar otros payloads (o cambiar las probabilidades con las que se inyectan),
edita docker_image/magic_payloads.php y docker_image/fuzz/config.py.
crash_detector.py contiene expresiones regulares que encuentran crashes interesantes o información
interesante (por ejemplo, correos electrónicos) que se expone.
Se ha deshabilitado el fuzzing de rutas REST como administrador con sesión iniciada porque generaba falsos
positivos. Descomenta rest_routes_admin en config.DEFAULT_ENABLED_FEATURES para cambiarlo.
Algunos plugins necesitan otros (por ejemplo, woocommerce) como dependencia. Al fuzzear un plugin que tiene una dependencia, queremos fuzzear solo el plugin elegido y omitir las acciones AJAX, rutas REST y páginas de menú de la dependencia. Queremos fuzzear las acciones/rutas/páginas de woocommerce solo cuando hemos seleccionado woocommerce para fuzzear.
La lista de acciones/rutas/páginas de dependencias se llaman listas negras y se enumeran en docker_image/blocklists/.
Los archivos denominados common contienen las acciones/rutas/páginas del núcleo de WordPress; tampoco
queremos fuzzearlas.
Para actualizar estas listas negras, usa ./bin/update_blocklists.
Quizás. Instala el plugin en un entorno de prueba local (por ejemplo, puedes usar el descrito en la sección Entorno de pruebas manuales) y analiza el error.
No des por sentado eso. El fuzzer encuentra algunas clases de vulnerabilidades, pero tiene sus limitaciones.
El fuzzer no encuentra nada para la mayoría de los plugins; el propósito de la herramienta es más bien escanear masivamente una gran cantidad de plugins de WordPress, no realizar pruebas exhaustivas de un solo plugin.
Es posible. El fuzzer elige payloads aleatoriamente e introduce aleatoriedad en otros lugares (por ejemplo,
cómo debe comportarse el operador == en los casos descritos en
https://kazet.cc/2022/02/03/fuzzing-wordpress-plugins.html#patched-equality).
Abre un ticket en Github o envíame un correo electrónico: [email protected].