La lectura del libro Writing Secure Code, últimamente me ha motivado a revisar código de distintas aplicaciones en busca de algunas fallas. Es así que mientras miraba el código fuente de menéame (a.k.a. clon de Digg), ví -valga la redundacia- que éste era suceptible a ataques XSS, posiblemente en los siguientes archivos:
- www\blogscloud.php
- www\cloud.php
- www\comments_rss2.php ¿?
- www\rss2.php ¿?
- www\topstories.php
- www\topusers-big.php
- www\topusers.php
- www\libs\html1.php ¿?
- www\backend\comment_edit.php ¿?
Actualización: El error ha sido solucionado minutos después de haber publicado el bug en http://meneame.wikispaces.com/Bugs, es por eso que me gusta el software libre!.
El error -un viejo conocido de otras aplicaciones- consiste en que no se valida de manera correcta el uso de la variable predefinida PHP_SELF, así por ejemplo en la línea 80 de cloud.php tenemos algo como esto:
A simple vista pareciera que la línea no contiene ningún error, pero el pequeño detalle es que el contenido de PHP_SELF puede ser modificado por el usuario.
'PHP_SELF'
El nombre de archivo del script ejecutándose actualmente, relativo a la raíz de documentos. Por ejemplo, $_SERVER['PHP_SELF'] en un script en la dirección http://example.com/test.php/foo.bar sería /test.php/foo.bar. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).
Si PHP está siendo ejecutado como un procesador de línea de comandos, esta variable contiene el nombre del script a partir de PHP 4.3.0. Anteriormente no estaba disponible.
Fuente: Variables Predefinidas
Ejemplos
Si armamos la siguiente URL, al cargar la página debería aparecer un mensaje mostrando las cookies relacionadas al sitio:
http://meneame.net/cloud.php/"><script>alert(document.cookie)</script><foo"
<!-- El código HTML enviado al cliente -->
<li><a href="/cloud.php/"><script>alert(document.cookie)</script><foo"?range=1">última semana</a></li>
Si esta vez se arma una URL como la siguiente, entonces lo que puede pasar es que las cookies sean enviadas a un servidor remoto, probablemente para fines no muy éticos.
Solución
Usar otra variable predefinida (¿REQUEST_URI?), la función htmlentities para escapar el contenido de PHP_SELF o borrar los caracteres peligrosos de éste.
Actualización: Según la documentación, SCRIPT_NAME debe usarse para referenciar a una misma página.
SCRIPT_NAME
Contiene la ruta del script actual. Ésta es útil para páginas que necesitan apuntar a ellas mismas. La constante __FILE__ contiene la ruta completa y nombre del archivo actual (es decir, incluido).
Fuente: Variables Predefinidas
Notas finales
Debemos tener cuidado en validar correctamente los datos que son enviados y/o aquellos que son modificables por el usuario.
Cabe aclarar que ésta entrada no es ninguna represalia por el hecho que tildaron de spammer -con justa razón- a mi amigo Braulio en uno de sus envíos a Menéame. 😀