Advertencia: El ningún caso me hago responsable del mal uso que se le pueda dar a la información que a continuación voy a presentar. Se presenta “tal cual” con el objetivo de que los usuarios de la conocida plataforma que a continuación se menciona tomen medidas preventivas urgentes para evitar que sus blogs sean alterados, borrados, etc.
¿Recordais la canonicalización que aprendísteis en álgebra lineal? Probablemente no. Sin embargo, eso no os hará falta para entender este problema.
La canonicalización es la manera en la que ciertos valores pueden ser representados. Por ejemplo, podríamos representar el número 2 como 10 en la base 2. Así, de esta manera, mediante el cambio de base (que al fin y al cabo son un espacio vectorial) podemos representar lo mismo de distintas maneras.
En lo referente a la informática, la canonicalización se da cuando queremos acceder a recursos de una manera distinta (es decir, en vez de poner la ruta absoluta). Por ejemplo, si estamos en el directorio C:\Windows\System32 y queremos poner la dirección de una ruta que no está por debajo (Como la carpeta C:\Inetpub) tendríamos que escribir C:\Windows\System32\..\..\Inetpub.
Los que llevan tiempo suficiente con la informática como para conocer MS-DOS esto no les resultará demasiado sorprendente, ya que era el pan de cada día en aquellos tiempos, sin embargo, parece que hay mucha gente que lo ha olvidado.
Sobre todo, creo que lo han olvidado los programadores de Open Source que utilizan tecnologías para la web de Microsoft (dígase ASP.NET). Ayer, en un momento de bloqueo desarrollando, decidí descargarme otro de los productos patrocinados por Microsoft: BlogEngine.NET
BlogEngine (http://www.dotnetblogengine.net/) es una de las plataformas de blogs más utilizadas en el mundo Microsoft (así como WordPress es la #1 en el mundo LAMP). Así pues, hice una auditoría informal al código de BlogEngine 1.1 (1.1 es la Release actual en CodePlex) y descubrí que en cada uno de sus handlers File.axd, etc… tenían un fallo de seguridad de canonicalización (del mismo tipo que el que encontré la semana pasada en MyWebPagesStarterKit). Evidentemente los desarrolladores ya están informados y la solución se puede descargar en la última revisión de BlogEngine en Codeplex. (Utilizad para ellos la herramienta CPC).
Bien, ahora entremos en los detalles escabrosos de este “blog engine” (motor de blogging) promocionado por Microsoft en los Starter Kits.
Vamos a pasar por los distintos fallos de seguridad que he encontrado y comentado con su coordinador:
Fallo 1: Contraseñas sin hash
Las contraseñas son almacenadas en un fichero llamado Users.xml en la carpeta App_Data en texto plano (por muy XML que sea XD). Así que alguién con acceso a ese fichero podría después tomar el control del blog. Aunque parezca mentira, aún hay gente que almacena contraseñas sin hash en pleno siglo XXI. (Para ver cómo hacer hash a contraseñas recomiendo echar un vistazo al XmlMemberShipProvider.cs en el MyWebPagesStarterKit).
Fallo 2: Contraseña de la cuenta SMTP
Cuando accedemos a la página ~/Admin/Pages/Settings.aspx (es decir, con un login de administrador válido) podemos ver a todo detalle la configuración del servidor SMTP. Es decir, host, puerto, login y password. Ni siquiera se han molestado en poner el TextBox del password la máscara que se suele utilizar en los campos con contraseña (es decir, que ves la contraseña que escribes tú y el que esté a tu lado).
Para solucionar esto, lo único que habría que hacer es que en el load de la página, este TextBox no se cargue de información. Y al guardar, en caso de que alguién haya introducido algo en el TextBox cambiar la configuración.
Fallo 3: FileHandlers mal implementados.
O lo que es lo mismo: confiar en la entrada del usuario.
Pego aquí el código de la clase: BlogEngine.Core.Web.HttpHandlers.FileHandler
public void ProcessRequest(HttpContext context)
{
OnBeforeServing();
if (!string.IsNullOrEmpty(context.Request.QueryString["file"]))
{
string fileName = context.Request.QueryString["file"];
string folder = BlogSettings.Instance.StorageLocation + "/files/";
if (File.Exists(context.Server.MapPath(folder) + fileName))
{
OnFileServing();
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + context.Server.UrlEncode(fileName));
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Server.Transfer(folder + fileName, false);
}
else
{
OnBadRequest();
context.Response.Status = "404 Bad Request";
}
}
}
La única validación que hace es ver si el QueryString es “algo” o nulo. Pero por lo demás, nada. Con esto quiero decir que si alguién malintencionado hace una Request del tipo:
http://blogengine/file.axd?file=../users.xml
Podría descargarse el fichero con los usuarios y contraseñas de la aplicación web. Recordemos que éstas se almacenan en texto plano.
Pero bueno, esta es sólo la opción por defecto. También existe la posibilidad de utilizar SqlServer como motor de persistencia. Así, para obtener el fichero con las ConnectionStrings (y por tanto tener acceso directo a la base de datos) basta con la url.
http://blogengine/file.axd?file=../../sql.config
Para solucionar el problema de seguridad expuesto por el FileHandler, la solución es cambiar varias lineas del código anterior por estas:
if (!string.IsNullOrEmpty(context.Request.QueryString["file"]))
{
string fileName = context.Request.QueryString["file"].ToLowerInvariant();
string folder = BlogSettings.Instance.StorageLocation + "/files/";
FileInfo info = new FileInfo(context.Server.MapPath(folder) + fileName);
if (info.Exists && info.Directory.FullName.ToLowerInvariant().Contains("\\files"))
Así habremos securizado nuestro BlogEngine.NET.
Ahora la cuestión es… ¿habrá actualizado toda esta gente sus blogs?:
[Ver resultados de la búsqueda en google "Powered by BlogEngine.NET 1.1"]
Esperemos que sí, si no las consecuencias pueden ser desastrosas.

pues te aseguro q de todos los blogs q existen por alli … el 90% no ha modificado esto (5 de 5 en los primeros de google … )
q mal … :S
Saludos y buen post
Realmente lo sé… no te puedo decír cómo :P
Seria bueno un envio de esta info directamente al grupo de desarrollo de blogengine, despues de todo es opensource y se alimenta de las experiencias de otros usuarios con la herramienta.
Gracias.
Ya ha sido reportada antes de ser escrito este post.