Vulnerabilidad en la mayoría de los plugins para WordPress

pwnpressHace un par de días, mientras hacia unas pruebas y revisaba unos sistemas descubrí una vulnerabilidad que afectaba a unos cuantos plugins de WordPress instalados.
Continuando mi investigación llegúe a la conclusión de que se trata de una vulnerabilidad Full Path Disclosure (FPD) que afecta a la mayoría de los plugins de WordPress, incluyendo al “Hello Dolly” y Akismet (plugins por defecto). Para explotar esta vulnerabilidad, no es necesario que el plugin esté activo, simplemente que esté instalado. Esta vulnerabilidad es debido a un problema o error a la hora de programar los plugins, al no validar la existencia de funciones antes de ejecutarlas el sistema devuelve un error fatal, mostrandonos la ruta completa de la instalación del CMS. Por ejemplo, en Akismet:

Fatal error: Call to undefined function add_action() in /home/XXYYZZ/public_html/wp-content/plugins/akismet/akismet.php on line 26

Hablando un poco sobre la vulnerabildiad FPD y recordando lo que dije en el post pasado, explotar esta vulnerabilidad no significa que podamos hacer grandes cosas, simplemente nos entregará información que podría ser utilizada para lo que uno estime conveniente.

Analizando más profundamente el código y el error, podemos encontrar (siguiendo con Akismet) las siguientes líneas:

  1. < ?php
  2. function akismet_init() {
  3.         global $wpcom_api_key, $akismet_api_host, $akismet_api_port;
  4.  
  5.         if ( $wpcom_api_key )
  6.                 $akismet_api_host = $wpcom_api_key . ‘.rest.akismet.com’;
  7.         else
  8.                 $akismet_api_host = get_option(‘wordpress_api_key’) . ‘.rest.akismet.com’;
  9.  
  10.         $akismet_api_port = 80;
  11.         add_action(‘admin_menu’, ‘akismet_config_page’);
  12.         add_action(‘admin_menu’, ‘akismet_stats_page’);
  13.         akismet_admin_warnings();
  14. }
  15. add_action(‘init’, ‘akismet_init’);
  16.  
  17. function akismet_admin_init() {
  18.         if ( function_exists( ‘get_plugin_page_hook’ ) )
  19.                 $hook = get_plugin_page_hook( ‘akismet-stats-display’, ‘index.php’ );
  20.         else
  21.                 $hook = ‘dashboard_page_akismet-stats-display’;
  22.         add_action(‘admin_head-‘.$hook, ‘akismet_stats_script’);
  23. }
  24. add_action(‘admin_init’, ‘akismet_admin_init’);
  25. ?>

Sólo en esas líneas se hace unas cuantas veces la llamada a la función “add_action()” que no es validada antes de ser ejecutada, sin embargo, otras funciones si lo están (por ej. mirar línea 18). Lo mismo sucede en hello.php y en muchos otros plugins muy usados.

Para detectar esta vulnerabilidad los plugins que tenemos instalados podemos ejecutar el siguiente comando dentro del directorio wp-content/plugins:

find . -name "*.php" -exec grep -H add_action {} \;

Y obtendremos un resultado como el siguiente:

./wp-gravatar/gravatars.php:add_action(‘admin_menu’, ‘gravatar_admin_menu’);
./wp-gravatar/gravatars.php:add_action(‘plugins_loaded’, ‘widget_authdescription_init’);
./wp-gravatar/gravatars.php:add_action(‘plugins_loaded’, ‘widget_recent_comments_gravatars_register’, 1);
./smart-youtube/smartyoutube.php:add_action(‘admin_menu’, ‘yte_add_pages’);
./smart-youtube/smartyoutube.php:add_action( ‘plugins_loaded’, ‘yte_install’ );
./smart-youtube/smartyoutube.php:add_action( ‘after_plugin_row’, ‘yte_check_plugin_version’ );
./chili-code-highlighter/chili-code-highlighter.php:add_action( ‘plugins_loaded’, create_function( ”, ‘global $ChiliCodeHighlighter; $ChiliCodeHighlighter = new ChiliCodeHighlighter();’ ) );
./wp-db-backup/wp-db-backup.php:add_action(‘plugins_loaded’, ‘wpdbBackup_init’);
./subscribe2/counterwidget.php:add_action(‘plugins_loaded’, ‘widget_s2counter_init’);
./add-to-any/add-to-any.php:add_action(‘init’, ‘A2A_SHARE_SAVE_textdomain’);
./add-to-any/add-to-any.php:add_action(‘the_content’, ‘A2A_SHARE_SAVE_to_bottom_of_content’, 98);
./add-to-any/add-to-any.php:add_action(‘wp_head’, ‘A2A_SHARE_SAVE_button_css’);
./add-to-any/add-to-any.php:add_action(‘admin_head’, ‘A2A_SHARE_SAVE_admin_head’);
./add-to-any/add-to-any.php:add_action(‘admin_menu’, ‘A2A_SHARE_SAVE_add_menu_link’);
./creative-commons-license-widget/ccLicense.php:add_action(‘widgets_init’, ‘widget_ccLicense_init’);
./wordpress-23-related-posts-plugin/wp_related_posts.php:add_action(‘init’, ‘init_textdomain’);
./wordpress-23-related-posts-plugin/wp_related_posts.php:add_action(‘admin_menu’, ‘wp_add_related_posts_options_page’);
./twitter-updater-using-tinyurl/twitter_updater.php:add_action ( ‘save_post’, ‘vc_twit’);
./twitter-updater-using-tinyurl/twitter_updater.php:add_action(‘admin_menu’, ‘vc_addTwitterAdminPages’);
./simplepie-core/simplepie_core.php:add_action(‘admin_menu’, ‘simplepie_core_options’);
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘edit_post’, array($aiosp, ‘post_meta_tags’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘publish_post’, array($aiosp, ‘post_meta_tags’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘save_post’, array($aiosp, ‘post_meta_tags’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘edit_page_form’, array($aiosp, ‘post_meta_tags’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘init’, array($aiosp, ‘init’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘wp_head’, array($aiosp, ‘wp_head’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘template_redirect’, array($aiosp, ‘template_redirect’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘admin_menu’, array($aiosp, ‘admin_menu’));
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action(‘admin_menu’, ‘aiosp_meta_box_add’);
./all-in-one-seo-pack/all_in_one_seo_pack.php:add_action( ‘admin_notices’, ‘aioseop_activation_notice’);
./google-analyticator/google-analyticator.php:add_action(‘admin_init’, ‘ga_admin_init’);
./google-analyticator/google-analyticator.php:add_action(‘admin_menu’, ‘add_ga_option_page’);
./google-analyticator/google-analyticator.php:add_action(‘init’, ‘ga_outgoing_links’);
./google-analyticator/google-analyticator.php:add_action(‘plugin_action_links_’ . plugin_basename(__FILE__), ‘ga_filter_plugin_actions’);
./google-analyticator/google-analyticator.php:add_action(‘wp_ajax_ga_ajax_accounts’, ‘ga_ajax_accounts’);
./google-analyticator/google-analytics-stats-widget.php:add_action(‘widgets_init’, ‘GoogleStatsWidget_init’);
./akismet/akismet.php:add_action(‘init’, ‘akismet_init’);
./akismet/akismet.php:add_action(‘admin_init’, ‘akismet_admin_init’);
./akismet/akismet.php:add_action(‘wp_set_comment_status’, ‘akismet_submit_spam_comment’);
./akismet/akismet.php:add_action(‘edit_comment’, ‘akismet_submit_spam_comment’);
./akismet/akismet.php:add_action(‘preprocess_comment’, ‘akismet_auto_check_comment’, 1);
./akismet/akismet.php:add_action(‘admin_menu’, ‘akismet_manage_page’);
./akismet/akismet.php:add_action(‘activity_box_end’, ‘akismet_stats’);
./akismet/akismet.php:add_action(‘rightnow_end’, ‘akismet_rightnow’);
./akismet/akismet.php:add_action(‘manage_comments_nav’, ‘akismet_check_for_spam_button’);
./akismet/akismet.php:add_action(‘admin_action_akismet_recheck_queue’, ‘akismet_recheck_queue’);
./akismet/akismet.php:add_action(‘init’, ‘widget_akismet_register’);
./source-code-syntax-highlighting-plugin-for-wordpress/deans_code_highlighter.php:add_action(‘admin_menu’, ‘dl_reg_admin’);
./flickr-widget/flickr_widget.php:add_action( “init”, “flickr_widgets_init” );

La lista de plugins afectados es muy grande, sólo en este caso (mi wordpress) tenemos 15:

wp-gravatar
smart-youtube
chili-code-highlighter
wp-db-backup
subscribe2
add-to-any
creative-commons-license-widget
wordpress-23-related-posts-plugin
twitter-updater-using-tinyurl
simplepie-core
all-in-one-seo-pack
google-analyticator
akismet
source-code-syntax-highlighting-plugin-for-wordpress
flickr-widget

Para corregirlo simplemente debemos agregar, a cada llamada de la función, la siguiente validación:

  1. if(function_exists(‘add_action’)) {
  2. []
  3. }

Quizás a mucha gente no le interese este tema y piense que este tipo de vulnerabilidad no sirve y no les importa que sepan en que directorio está instalado el wordpress, aún así, pienso que es necesario que esto se corrija. No va a depender de los usuarios solucionar esto, sino de los desarrolladores.
Esta vulnerabilidad puede ser aprovechada no sólo para entrar a un sistema wordpress, puede ser combinada con otras vulnerabildiades como LFI o Directory Transversal y comprometer a las otras cuentas que estan en el servidor. Con esta información podemos obtener típicamente el nombre de usuario de la cuenta (luego ingresar por la IP agregando colita de chancho [~] y luego el username) y el directorio de ese usuario, que luego pueden ser usados para distintos fines.
Las personas que alguna véz hayan explotado este tipo de vulnerabilidad sabrán lo útil que puede llegar a ser al momento de querer penetrar un sistema.

Si lo miramos desde otro punto de vista, podríamos llegar a escalar el problema y decir que gran parte de la responsabilidad la tiene WordPress, todos los plugins deberían pasar por un test de calidad donde se verifiquen este tipo de cosas. La forma de operar que tienen los plugins de WordPress deberían ser, al menos, en un entorno WP. ¿Me explico? Debería existir una forma de determar que el fichero php se está ejecutando bajo el entorno wordpress y no por si solo (por ejemplo al llamar a hello.php), ya sea con un método, constante, variable, etc, algo tan simple como un if:

  1. if(WORDPRESS_ENVIRONMENT == 1)

Otra forma de solucionarlo, sería deshabilitando los mensajes de advertencia y errores por lado del servidor, pero insisto, creo que la solución no es por parte de los usuarios, sino de los desarrolladores.

4 comentarios

  1. El mismo WP trae varios fpd, no hace falta buscar en los plugins http://blog.xd-blog.com.ar/obteniendo-informacion-de-un-wordpress/

    editar todos los plugins a mano me parece una pérdida de tiempo, encima hay que hacerlo en cada catualización. Mejor configurá php para que no muestre los errores

  2. @seth: Claro, es una perdida de tiempo modificar todos los plugins a mano, por eso no lo recomiendo ni por si las moscas. Ahora, deshabilitar el php para que no muestre los errores seria una solucion bien practica, pero no deja de tener un error el codigo del plugin. Yo preferiria que los desarrolladores de cada plugin se dedicaran a validar bien las llamadas a las funciones, ya que es un error por lado de la programacion y no por la configuracion del servidor. obviamente, todo esto que digo es en cierta forma muy utopico por lo que la gente que quiera “solucionar” (o parchear) este problema simplemente desactive la opcion “display_errors” del php.ini

    saludos

  3. Lo peor como ya le he comentado a Zerial en un correo es que no solo se encuentran los fallos en los plugins, sino que hay un montón de sitios en WP donde tambien existen estos fallos.
    Más info -> http://rollanwar.net/?p=12

  4. como explotas esta vulnerabilidad de akismet si no valida el add_action
    por ejemplo http://victima.com/wp-content/plugins/akismet/akismet.php?algun_parametro_que_injecta

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Esto sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.