Categories
Internet Explorer Web

Cookies

Una cookie es un fragmento de información que se almacena en el disco duro del visitante de una página web a través de su navegador, a petición del servidor de la página. Esta información puede ser luego recuperada por el servidor en posteriores visitas.

No suelo darle importancia a las novedades de Internet Explorer, pero hoy me pareció interesante algunos consejos que dan desde el blog de éste navegador para reducir el tráfico HTTP que se produce entre un servidor y un cliente.

Antes de continuar, estas son las nuevas limitaciones que impone Internet Explorer para el manejo de Cookies:

  • Se incrementó de 20 a 50 el número de cookies que se puede crear por dominio.
  • document.cookie retornará una cadena vacía si el tamaño de las cookies es mayor a 4096 bytes.
  • El navegador ignorará las cabeceras Set-Cookie si éstas exceden de 5118 bytes.

Volviendo al tema anterior, éstos son los consejos que sugieren para reducir el tráfico HTTP:

  • Reducir el tamaño de las cookies: Recomiendan utilizar nombres y si es posible, valores más cortos. Ejm. en lugar de una cookie denominada username, usar sólo u.
  • Servir el contenido estático desde otro (sub)dominio: Una vez que el servidor envía las cookies usando la cabecera Set-Cookie, un navegador convencional enviará de vuelta estos valores en cada petición que se haga al servidor. Como los valores de las cookies son irrelevantes para los archivos estáticos, entonces se genera tráfico innecesario.
  • Usar el atributo path sólo cuando sea necesario: El atributo path permite manejar cookies para rutas específicas de un dominio, por ejemplo si se envían cookies para la ruta /aplicacion, entonces en el servidor se podrá acceder a estos valores sólo desde esa ruta *. Usar este atributo en general va a depender de los requerimientos de la aplicación, pero si quieres ahorrar unos cuantos bytes entonces haz que la ruta sea para todo el dominio.

Las resultados de estos consejos seguramente van a ser más evidentes en sitios con mucho tráfico que en sitios como éste, donde el número de lectores se puede contar con los dedos de la mano. 😀

*: En realidad se puede acceder a todos los datos de la petición y por consiguiente a todas las cookies, pero de manera convencional algunos lenguajes abstraen esta funcionalidad para dar acceso sólo a las cookies definidas para una ruta.

Categories
Seguridad Web WordPress

¿Estamos seguros con la nueva versión de WordPress?

La salida de la versión 2.2.2 de WordPress me sorprendió un poco porque no incluye las correcciones a algunos problemas de seguridad que fueron reportados hace más de un mes, si bien es cierto que éstos no son muy peligrosos*, no se me ocurre ningún motivo válido para no haberlos resuelto (si mi memoria no me falla, incluso envié parches con posibles alternativas de solución). Todo parece indicar que la única forma de hacer que los desarrolladores de WordPress le den más importancia a este tipo de reportes, es liberar exploits que hagan uso de éstas vulnerabilidades.

Regresando al tema inicial, lamentablemente la última versión incluye -- al igual que las anteriores y la que actualmente está en desarrollo -- muchos problemas de seguridad, que en su mayoría se deben al uso de cadenas (tipo querystring) para pasar parámetros a funciones y a la ausencia de consultas parametrizadas. Unos cuantos bugs son graves (Fig. 1) y otros de relativa peligrosidad*, pero con el antecedente previo, no sé si me vayan a hacer caso.

Exploit for a Remote SQL Injection Vulnerability in WordPress
Fig. 1: Resultados de un exploit para una
vulnerabilidad de inyección de SQL en WordPress 2.x
(no requiere autenticación).

Es muy probable que la vulnerabilidad que se muestra en la imagen, obligue a los desarrolladores de WordPress a liberar una nueva versión y agregar así, otra raya más al tigre. Por otro lado, mientras no termine de escribir el advisory y me desocupe un poco, no tengo intenciones de dar a conocer los detalles y el exploit para este problema de seguridad. 😉

* Esos bugs son bastante más graves en WordPress MU.

A petición de Alex, pongo a disposición parches generados a partir de la versión en desarrollo de WordPress.

Categories
Web WordPress

Plugin para búsquedas de texto completo en WordPress

La entrada de Héctor sobre como integrar el buscador de Google en WordPress, me hizo acordar que tenía que mejorar un plugin que permite realizar búsquedas de texto completo (Full Text Search) en WordPress -- una versión más rústica de este plugin está funcionando cierto tiempo sin problemas en otro blog.

Luego de unas cuantas pruebas sobre WordPress 2.2.1 y 2.0.11, al parecer está funcionando como debería (aunque el hack para 2.0.11 no me convence del todo 🙂 ):

Opciones del plugin para búsquedas de texto completo en WordPress
Plugin para búsquedas de texto completo en WordPress

Características

  • Permite -- desde el panel de opciones del plugin -- eliminar y crear un índice FULLTEXT sobre los campos post_title y post_content.
  • Permite escoger ciertos modificadores para la realización de búsquedas de texto completo (búsquedas booleanas y con expansión de consulta).
  • Ejecuta la búsqueda normal si la palabra tiene menos de cuatro letras (limitación de las búsquedas de texto completo).
  • Ordena las entradas de acuerdo a la relevancia del texto encontrado.

Para los interesados en este plugin, pueden descargar la primera beta desde este blog.

Changelog

  • Corrección de un bug en el que se usaban campos no definidos en el índice para hacer la búsqueda. Gracias Marce 😉
Categories
Seguridad Sql Injection Web WordPress XSS

7 nuevos problemas de seguridad en WordPress

Actualización: g30rg3_x me comenta que ya están disponibles los parches oficiales para estos problemas de seguridad, pueden ver los archivos modificados para las versiones 2.2.x (zip) y 2.0.x (zip).

Hace algunas horas acaban de reportar 7 problemas de seguridad en WordPress:

  1. WordPress Persistant XSS Vulnerability in the Default Theme (v.2.2): Los parámetros para la imagen y color de la cabecera en el tema por omisión de WordPress (Kubrick) son vulnerables. Aunque no lo probé, me parece que es parecido al que reporté hace tiempo.
  2. WordPress /options.php SQL Injection Vulnerability: El parámetro page_options no está correctamente validado en wp-admin/options.php. Sólo los usuarios con nivel Administrador pueden explotar esta vulnerabilidad.
  3. WordPress /options.php Information Disclosure: Esta vulnerabilidad se deriva de la anterior, porque en wp-admin/options.php se asume que el nombre de las opciones son seguras.
  4. WordPress /edit-comments.php Database Error (Bug): Simplemente muestra un error en la consulta si el valor de la página es negativo.
  5. WordPress /link-import.php XSS Vulnerability: El parámetro cat_id no es filtrado adecuadamente, para explotarlo requiere tener un valor adecuado para el parámetro _wpnonce.
  6. WordPress /upload.php XSS Vulnerability: En este caso el parámetro style es inseguro.

La misma persona que reportó estos bugs se tomó el trabajo de realizar un gusano que se encarga de parchar los blogs vulnerables, siempre y cuando se el servidor web tenga permisos de escritura en los archivos afectados.

En cada uno de los tickets abiertos ya existen parches oficiales disponibles (4689, 4690, 4691 y 4692). Mi parche para corregir esos problemas es ligeramente diferente:

diff:

Index: wp-admin/edit-comments.php
===================================================================
--- wp-admin/edit-comments.php  (revision 5825)
+++ wp-admin/edit-comments.php  (working copy)
@@ -76,7 +76,7 @@
 endif;
 
 if ( isset( $_GET['apage'] ) )
-       $page = (int) $_GET['apage'];
+       $page = (int) abs($_GET['apage']);
 else
        $page = 1;
 
Index: wp-admin/link-import.php
===================================================================
--- wp-admin/link-import.php    (revision 5825)
+++ wp-admin/link-import.php    (working copy)
@@ -73,7 +73,7 @@
 
 <h2><?php _e('Importing...') ?></h2>
 <?php
-              $cat_id = $_POST['cat_id'];
+              $cat_id = (int) $_POST['cat_id'];
               if ( $cat_id == '' || $cat_id == 0 )
                      $cat_id  = 1;
 
Index: wp-admin/options.php
===================================================================
--- wp-admin/options.php        (revision 5825)
+++ wp-admin/options.php        (working copy)
@@ -143,6 +143,7 @@
               $options_to_update[] = $option->option_name;
               $class = 'all-options';
        }
+       $option->option_name = attribute_escape($option->option_name);
        echo "
 <tr>
        <th scope='row'><label for='$option->option_name'>$option->option_name</label></th>
Index: wp-admin/upload-functions.php
===================================================================
--- wp-admin/upload-functions.php       (revision 5825)
+++ wp-admin/upload-functions.php       (working copy)
@@ -104,6 +104,8 @@
 function wp_upload_form() {
        $id = get_the_ID();
        global $post_id, $tab, $style;
+       $style = attribute_escape($style);
+       $post_id = (int) $post_id;
        $enctype = $id ? '' : ' enctype="multipart/form-data"';
 ?>
        <form<?php echo $enctype; ?> id="upload-file" method="post" action="<?php echo get_option('siteurl') . "/wp-admin/upload.php?style=$style&tab=upload&post_id=$post_id"; ?>">
Index: wp-includes/functions.php
===================================================================
--- wp-includes/functions.php   (revision 5825)
+++ wp-includes/functions.php   (working copy)
@@ -206,6 +206,7 @@
 function get_option($setting) {
        global $wpdb;
 
+       $setting = $wpdb->escape(stripslashes($setting));
        // Allow plugins to short-circuit options.
        $pre = apply_filters( 'pre_option_' . $setting, false );
        if ( $pre )
@@ -305,6 +306,7 @@
 function update_option($option_name, $newvalue) {
        global $wpdb;
 
+       $name = preg_replace('/[^a-z\d_-]/i', '', trim($name));
        wp_protect_special_option($option_name);
 
        if ( is_string($newvalue) )
@@ -352,6 +354,7 @@
 function add_option($name, $value = '', $description = '', $autoload = 'yes') {
        global $wpdb;
 
+       $name = preg_replace('/[^a-z\d_-]/i', '', trim($name));
        wp_protect_special_option($name);
 
        // Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
@@ -391,6 +394,7 @@
 
        wp_protect_special_option($name);
 
+       $name = $wpdb->escape(stripslashes($name));
        // Get the ID, if no ID then return
        $option = $wpdb->get_row("SELECT option_id, autoload FROM $wpdb->options WHERE option_name = '$name'");
        if ( !$option->option_id ) return false;
 

Los que no sepan -- o no quieran -- aplicar manualmente este parche no oficial, pueden descargar el conjunto de archivos modificados para la versión 2.2.1, úsenlo bajo vuestra propia responsabilidad. 🙂

Actualización (03/08/2007): Miquel encontró un bug en el parche que publiqué.

Categories
Sql Injection Web WordPress

SQL Injection en el plugin de estadísticas de WordPress.com

Todos aquellos que estén usando el plugin de estadísticas de WordPress.com, es recomendable que desactiven cuanto antes el mismo, porque incluye una vulnerabilidad bastante grave que permite a un atacante remoto obtener las credenciales de cualquier usuario conociendo sólo su ID.

Detalles de la vulnerabilidad

El mencionado plugin registra dos nuevos métodos en el servidor XMLRPC que todo blog con WordPress tiene, éstos son wpStats.get_posts y wpStats.get_blog -- internamente implementados por stats_get_posts y stats_get_blog respectivamente. El que más nos interesa en este caso, es la función stats_get_posts:

[php start=1]function stats_get_posts( $args ) {
list( $post_ids ) = $args;

$r = 'include=' . join(',', $post_ids);
$posts = get_posts( $r );
$_posts = array();

foreach ( $post_ids as $post_id )
$_posts[$post_id] = stats_get_post($post_id);

return $_posts;
}[/php]

A simple vista se puede ver que no existe ningún tipo de validación en los parámetros que esa función recibe, y como mencioné en ocasiones anteriores, usar esta forma (query string) para pasar parámetros a otras funciones es bastante peligroso, porque permite a un atacante modificar a su gusto los valores.

Por ejemplo, si hacemos que $post_ids contenga algo como:

code:

5&meta_key=%27) UNION ALL SELECT 1,2,3,4,5,user_login,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,user_pass,23,24,25,26,27,28 FROM wp_users/*&meta_value=1

El valor de la variable $r será:

code:

$r = 'include=5&meta_key=%27) UNION ALL SELECT 1,2,3,4,5,user_login,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,user_pass,23,24,25,26,27,28 FROM wp_users/*&meta_value=1'

Haciendo unos cambios en el valor de $post_ids se recupera toda la lista de usuarios con sus respectivas contraseñas en MD5, pero para obtener estos valores todavía hay que tener en cuenta las líneas 6, 8 y 9.

Dejo intencionalmente incompleta la prueba de concepto y exploit como reto para los que le gustan estas cosas y como medida de protección de los script kiddies.