Categories
Seguridad Web WordPress XSS

Nueva vulnerabilidad de WordPress

Héctor comentaba sobre la liberación de una nueva versión de wordpress que corregía un bug presente en las ramas 2.0 y 2.1 de este CMS.

Este error se presenta en la función wp_nonce_ays (archivo wp-includes/functions.php), porque la variable $action no está correctamente validada y en algunos casos, ésta puede ser modificada por el cliente. Por ejemplo http://vulnerable.com/wp-admin/plugins.php?action=activate&plugin=<script>alert(/XSS/)<script> es un posible vector de ataque.

php:

function wp_nonce_ays($action) {
        global $pagenow, $menu, $submenu, $parent_file, $submenu_file;

        $adminurl = get_option('siteurl') . '/wp-admin';
        if ( wp_get_referer() )
                $adminurl = wp_get_referer();

        $title = __('WordPress Confirmation');
        // Remove extra layer of slashes.
        $_POST   = stripslashes_deep($_POST  );
        if ( $_POST ) {
                $q = http_build_query($_POST);
                $q = explode( ini_get('arg_separator.output'), $q);
                $html .= "\t<form method='post' action='$pagenow'>\n";
                foreach ( (array) $q as $a ) {
                        $v = substr(strstr($a, '='), 1);
                        $k = substr($a, 0, -(strlen($v)+1));
                        $html .= "\t\t<input type='hidden' name='" . attribute_escape(urldecode($k)) . "' value='" . attribute_escape(urldecode($v)) . "' />\n";
                }
                $html .= "\t\t<input type='hidden' name='_wpnonce' value='" . wp_create_nonce($action) . "' />\n";
X              $html .= "\t\t<div id='message' class='confirm fade'>\n\t\t<p>" . wp_explain_nonce($action) . "</p>\n\t\t<p><a href='$adminurl'>" . __('No') . "</a> <input type='submit' value='" . __('Yes') . "' /></p>\n\t\t</div>\n\t</form>\n";
        } else {
X              $html .= "\t<div id='message' class='confirm fade'>\n\t<p>" . wp_explain_nonce($action) . "</p>\n\t<p><a href='$adminurl'>" . __('No') . "</a> <a href='" . add_query_arg( '_wpnonce', wp_create_nonce($action), $_SERVER['REQUEST_URI'] ) . "'>" . __('Yes') . "</a></p>\n\t</div>\n";
        }
        $html .= "</body>\n</html>";
        wp_die($html, $title);
}

Para corregir este fallo, simplemente hay que aplicar la función wp_specialchars sobre la salida de wp_explain_nonce en las línes marcadas con X:

php:

wp_specialchars(wp_explain_nonce($action));

Aprovechando este suceso, finalmente actualicé el blog a la versión 2.1 de WordPress e instalé el plugin wp-cache; si notan algún error, les estaré muy agradecido si me lo hacen saber.