Trazando la ruta geográfica de nuestra víctima

Índice:
1.-Introducción
2.-Preparando el documento
3.-Analizando el documento usando PHP
4.-Caso real: recopilando, analizando y arreglando

Actualmente no funciona, debido a que al parecer, Google tiene deshabilitada la respuesta JSON de cuando enviamos una petición para geolocalizar

1.-Introducción

Últimamente no paro de hablar de la geolocalización a través de las MAC gracias a Google, y no es para menos. El hecho de que sabiendo una MAC de un router obtengamos la localización geográfica muy exacta (igual falla en unos metros) puede ser benificioso y a la vez peligroso.

Programas como Prey, hacen de esta característica que parezca buena y beneficiosa por si nos roban un dispositivo capacitado para acceder a la red, como un móvil, tablet o notebook.

Sin embargo, todo tiene su lado negativo, y realmente esto de cierta manera atenta contra la privacidad de las personas, en mayor o en menor medida: imaginemos que disponemos de un programa para movil que va captando las MACs y a raiz de eso, se geolocaliza y obtiene la dirección. Tendriamos el móvil totalmente controlado. ¿Y si instalásemos este programa en un dispositivo de una persona ajena? Podriamos saber en todo momento por dónde ha pasado.

De hecho, existe algo muy parecido, y se llama Creepy. Este programa, a partir de una cuenta de twitter, puede situar en el mapa los puntos en los que hay tweets de un usuario en donde se haya geolocalizado a la hora de escribirlos.
Sin embargo, esto no es intrusivo, ya que el usuario es quien decide si poner o no su localización.

Volviendo al tema de antes, se me ocurrió diseñar un script que, a partir de un array con direcciones MACs, te geolocalice y trace una ruta en GMaps. De esta manera, si tuvieramos “algo” capaz de obtener las MACs que nos rodean durante un viaje, podriamos saber la ruta que ha seguido (siempre aproximadamente).

Como no sé programar para Android, al menos todavia, no sé muy bien si esto sería fácil o difícil de programar para un móvil/tablet, pero me he valido de la suite de aircrack (concretamente de airodump y aircrack) para poner a prueba el script que pondré a continuación para probar esto mismo.

Lo que hago es lo siguiente:
1.-Con el airodump capturo paquetes durante todo el viaje o trayecto.
2.-Una vez capturados, uso aircrack y redirecciono la salida para tener todas las MACs en un txt.
3.-Posteriormente lo filtro bien para tener un txt del tipo:
aa:aa:aa:aa:aa:aa
bb:bb:bb:bb:bb:bb
cc:cc:cc:cc:cc:cc
...

4.-Finalmente, leo mediante un script en PHP el txt generado y usando las APIs de GMaps y la de la geolocalización, establezco los puntos y trazo la ruta.

2.-Preparando el documento

Antes de todo, hacemos una captura con el airodump y nos vamos a dar un paseo:
$ airodump-ng mon0 -w captura --output-format pcap

Una vez tengamos todos los datos, nos generará un fichero llamado captura-01.cap. Vamos a abrirlo con el aircrack redireccionando su salida en un txt.
$ aircrack-ng captura-01.cap > documento.txt

Una vez hagamos esto, tenemos todos los datos guardados en el fichero documento.txt. Ahora, simplemente tenemos que filtrar el documento para obtener uno que quede como dije anteriormente:
$ cat documento.txt | grep -e '[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]' -o > macs.txt

Vamos a usar un poco el sentido común: si estamos en una ciudad y damos un paseo de cinco minutos, podemos acabar con varios centenares de direcciones MAC. Esto a la hora de pasarlo como argumento y usarlo para localizar puede que tarde mucho, e incluso es bastante inutil. ¿Para qué queremos 10 direcciones MACs que nos deberian de situar en el mismo sitio? Con una nos deberia bastar, ¿no?

Lo único que se me ocurre para filtrar un poco más, y obtener menos direcciones MAC, son dos cosas: obtener solo las MACs de routers que usan WPA (que son mucho menos que los de WEP, tristemente) o usar las direcciones MAC de redes en las que hemos capturado algún paquete (ya que si vamos andando, de muchas no capturaremos nada).

Para ayudarnos a la hora de crear un filtro para estos dos casos, miraremos la estructura de una captura pasada por aircrack:

Posteriormente, es fácil deducir que podriamos filtrarlos de la siguiente manera. En el primer caso (solo las WPA):
$ cat documento.txt | grep 'WPA (' | grep -e '[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]' -o > macs.tx

En el segundo caso (WEPs con datos)
$ cat documento.txt | grep 'WEP (' | grep -e '[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]' -o > macs.tx

3.-Analizando el documento usando PHP

No tengo mucho que decir aquí, ya que el código viene completamente comentado, así que haré un resumen de su funcionamiento.

Tengo una matriz con las MACs. Lo que hago es, a partir de esa matriz, obtener una matriz de localizaciones (en orden siempre) usando la Google Geolocation API. Posteriormente simplemente es usar la API de Google Maps de la que uso 3 funciones: establecer un mapa, establecer los puntos, y trazar una ruta entre los puntos.

Aquí va el código:




 

';



function trazar_ruta($matriz){
/*A partir de una matriz, trazaremos la ruta entre las direcciones MAC
  ya que tenemos las coordenadas. El contenido será del tipo
  matriz[0]=a,b;
  matriz[1]=c,d; Siendo a,b,c,d coordenadas */
  
echo '
  var flightPlanCoordinates = [
  ';
  //Ponemos todos los valores de los puntos a unir
  foreach($matriz as $clave => $valor)
     echo "new google.maps.LatLng(" . $valor . "),
";
  
//Configuramos las caracteristicas: color, opacidad y tamaño
	echo '
  ];
 
  var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2
  });

 
  flightPath.setMap(map);

	';
	
}

function poner_punto($coordenadas,$titulo){
/* Esta función nos permite poner un punto en el mapa
   tenemos que darle las coordenadas, y el título que tendrá ese punto

*/
	
//Establecemos las coordenadas
echo "var coordenadas = new google.maps.LatLng(" . $coordenadas[0] . "," . $coordenadas[1] . ");
";

//Lo ponemos en el mapa
echo '  var marker = new google.maps.Marker({ //opciones
      position: coordenadas,
      map: map,
      //Nombre del mapa
      title:"' . substr(str_replace("-",":",$titulo), 0, -1) . '"
      //Titulo (visible cuando colocamos el ratón sobre el punto)
  });
';
	
}



function obtener_coordenadas($mac, &$resultado){
/* Esta función nos permite guardar en "resultado" (pasado por referencia)
   las coordenadas de la mac pasada en el primer parámetro
*/ 
	
//Datos que enviaremos
$datos_completos = '{version:"1.1.0",request_address:true,wifi_towers:[{mac_address:"' . $mac . '"}]}';
 
//Iniciamos cURL
$ch = curl_init();
//Configuramos cURL
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $datos_completos);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 
curl_setopt($ch, CURLOPT_URL,'www.google.com/loc/json'); 
 
$respuesta = curl_exec($ch);
curl_close($ch);
 
//Obtenemos la respuesta y posteriormente la decodificamos
$respuesta = json_decode($respuesta, true);
 
//Para terminar, pasamos los resultados a los valores que posteriormente usaremos
$resultado[0]=$respuesta['location']['latitude'];
$resultado[1]=$respuesta['location']['longitude'];

}


?>



  

4.-Caso real: recopilando, analizando y arreglando

Esta mañana decidí poner a prueba lo que he escrito anteriormente: puse el portatil a escanear y me fui desde donde vivo actualmente hasta la universidad para posteriormente analizarlo y ver si consigo trazar la ruta correctamente.

Para empezar, antes de salir de casa, puse la tty3 (para poder cerrar el portatil sin que se suspenda o apague) de mi Fedora escaneando con airodump y recogiendo paquetes de datos. Al llegar a la uni, filtreé los datos recogidos como anteriormente puse, generando 3 resultados distintos:
-606 MACs en total
-33 MACs con datos WEP (de las 606)
-35 MACs con WPA (de las 606)

Al script de geolocalizar y trazar rutas se le pueden pasar todos los datos que queramos, como si le pasamos over 9000 MACs, lo que pasa que hay que recordar que tenemos un timeout por defecto puesto en 60, por lo que dependiendo de nuestra velocidad de conexión podremos tratar más o menos MACs. Por ejemplo, en la uni puedo tratar hasta 225 MACs, pero en casa, alrededor de 100.

Podemos cambiar el timeout yéndonos al fichero php.ini y cambiando los valores (que están en segundos) de max_execution_time y max_input_time. Recordad que si tenemos corriendo nuestro servidor, para que se hagan efectivos los cambios habría que reiniciarlo.

Los puntos verdes muestran el inicio y el fin desde donde recogí datos. La primera imagen refleja el resultado de usar las 33 MACs con datos WEP:

Esta segunda imagen, es la de las 35 MACs que usan WPA:

Como podemos ver, en algunos puntos se nos va un poco de la ruta, pero creo que eso es debido a que hay repetidores aquí por la ciudad para tener WiFi gratis (además de los propios de la uni) y eso desestabiliza un poco.

Vamos a tratar ahora de solucionar el problema del límite de MACs que anteriormente dijimos ya que, esta captura la he realizado en 15 minutos.. Si fueran horas, tendriamos decenas de miles de direcciones. Para ello, lo que hacemos es pasar la matriz por una función cuyo algoritmo determine qué direcciones MAC deberiamos de eliminar para no pasar el límite.

Por ejemplo, si tenemos 5 MACs y queremos buscar dos, pues obviamente cogeriamos la primera y la última. Si tuvieramos 20 MACs con un límite de 4, podriamos coger 1 cada 5, y así sucesivamente.

El siguiente código no es el más eficaz ni el más perfecto, ya que le dediqué 5 minutos en hacerlo, pero funciona, y nos permite parsear una matriz y establecer otra a partir de un límite:

function reducir(&$matriz, &$resultado, $limite=100){
	$total=count($matriz);
	if($total>$limite) {
	  $division = $total/$limite;
	  $division = explode(".",$division);
	  $division = $division[0];
	
	  for($a=0;$a<$limite;$a++)
	    $resultado[$a]=$matriz[$a*$division];
	  unset($matriz);
	 //$matriz = $nueva;
	}
	//En caso contrario no hace falta modificar
	echo "

"; }

Un saludo, lipman

Usando la Geolocalización MAC en nuestro favor. Parte II

Anteriores entradas relacionadas:
[Análisis] Prey, software antirrobo de Código Abierto
Usando la Geolocalización MAC en nuestro favor. Parte I

Actualmente no funciona, debido a que al parecer, Google tiene deshabilitada la respuesta JSON de cuando enviamos una petición para geolocalizar

Índice:
1.-Geolocalización con un script en PHP mediante file_get_contents
2.-Geolocalización con un script en PHP mediante cURL
3.-Geolocalización a través de la shell (también usando cURL)
4.-Geolocation API Specification (W3C)

Siguiendo el hilo argumentativo del análisis que hice a Prey, hice una primera parte que quedó un poco escueta, sobre la que hablé de Geolocalización MAC. Pudimos usar un software para tratar de geolocalizar MACs, e incluso desde la página del MapXSS de Samy. Pero nos quedó pendiente una cosa: geolocalizar MACs por nuestros medios.

En esta entrada voy a tratar 4 formas distintas de geolocalizar una MAC, tres de ellas (las primeras) usando la API de Google. Dos de estas formas serán a través de scripts en PHP: uno de ellos usando cURL, y otro mediante file_get_contains. La otra forma, un tanto curiosa, será a través de la shell (en la que también necesitaremos tener cURL instalado). Con respecto a la forma que no usa la API de Google, usaremos la especificación de la W3C para geolocalizar, que está disponible en algunos navegadores.

1.-Geolocalización con un script en PHP mediante file_get_contents

Los dos primeros métodos funcionan internamente igual: hacemos una enviamos una petición JSON mediante POST, esperando recibir una respuesta que deberiamos de recibir, y posteriormente cuando la tengamos, la decodificamos y obtenemos un array con todos los valores y datos que deseamos, nuestra preciada dirección.

Antes de poner el código, una pequeña aclaración: si probamos este código en un servidor web remoto de algún hosting, es muy probable (casi 100%) de que no funcione. Esto tendriamos que probarlo en nuestro propio servidor PHP. Esto es debido a que los hostings deshabilitan (o deberian) la función file_get_contents por una vulnerabilidad que se encontró en la misma.

Aquí dejo el código explicado:

array(
    'method' => "POST",
    'header'  => 'Content-type: application/x-www-form-urlencoded',
    'content' => $datos
  )
);

//Utilizamos file_get_contents para hacer la petición a la API de Google
$respuesta = file_get_contents(
    'http://www.google.com/loc/json',
    false,
    stream_context_create($datos_completos)
);

//Decodificamos lo que nos devuelve
$respuesta = json_decode($respuesta, true);

//Obtenemos los resultados
echo "Direccion Geografica aproximada:
"; foreach($respuesta['location']['address'] as $clave => $valor) echo $clave . ": " . $valor . "
"; echo "Coordenadas aproximadas:
"; echo "Latitud: " . $respuesta['location']['latitude'] . "
Longitud: " . $respuesta['location']['longitude']; ?>

A continuación escribiré una estructura de tipo árbol de los datos que nos devuelve Google tras este envio, ya que nos devuelve una matriz multidimensional, y viene bien saber el contenido de esta:


$respuesta (Array)

>access_token
>location: Array
|-->latitude
|-->longitude
|-->accuracy
|-->address: Array
|---|-->country
|---|-->country_code
|---|-->region
|---|-->country
|---|-->city
|---|-->street
|---|-->postal_code

2.-Geolocalización con un script en PHP mediante cURL

Aquí si ponemos el mismo código que enviamos en el script anterior, no nos funciona, así que tendremos que modificar la petición como veremos a continuación de una manera todavía más sencilla. Además de eso, tendriamos que cambiar la parte de file_get_contents por el cURL. Este código si que deberia de funcionarnos en un servidor remoto, y digo deberia porque yo no lo he conseguido, solo he conseguido que me aparezca el robot de Google tan mono advirtiéndome de un error “temporal” que no tengo ni idea de porqué puede ser… Pero vamos, que en nuestro servidor casero si que funciona.

Aquí el código:


//Datos que enviaremos
$datos_completos = '{version:"1.1.0",request_address:true,wifi_towers:[{mac_address:"xx-xx-xx-xx-xx-xx"}]}';

//Iniciamos cURL
$ch = curl_init();
//Configuramos cURL
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $datos_completos);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 
curl_setopt($ch, CURLOPT_URL,'www.google.com/loc/json'); 

$respuesta = curl_exec($ch);
curl_close($ch);

//Obtenemos la respuesta y posteriormente la decodificamos
$respuesta = json_decode($respuesta, true);

//Para terminar, printeamos los resultados
echo "Direccion Geografica aproximada:
"; foreach($respuesta['location']['address'] as $clave => $valor) echo $clave . ": " . $valor . "
"; echo "Coordenadas aproximadas:
"; echo "Latitud: " . $respuesta['location']['latitude'] . "
Longitud: " . $respuesta['location']['longitude'];

Esto nos devolverá exáctamente el mismo resultado que el anterior script.

3.-Geolocalización a través de la shell (también usando cURL)

Ya por último, acabaremos esta entrada geolocalizando de la forma más sencilla, a través de la shell, en la que solo tenemos que escribirlo y lo recibimos inmediatamente, como veremos en la siguiente imagen.

Usaremos el comando de cURL, por lo que propiamente es hacer lo mismo que en el segundo apartado, pero con la shell:


curl -d '{version:1.1.0,request_address:true,wifi_towers:[{mac_address:xx-xx-xx-xx-xx-xx}]}' www.google.com/loc/json

4.-Geolocation API Specification (W3C)

Para los que usamos twitter, esta especificación no nos deberia de parecer nueva, ya que desde hace tiempo tenemos la opción de añadir desde donde twitteamos usando este método.

A continuación, el código que nos permite esto:











Tras ejecutarlo en Firefox por ejemplo, nos saldrá un aviso de si queremos compartir nuestra localización, que igual a alguno le suena haber visto anteriormente:

Y nos saldrá esto:

A veces no me funciona, igual es que tiene algún límite de peticiones por tiempo (como algunas APIs). Lo curioso (y bueno) del asunto, es que si analizamos con Wireshark los datos, podemos ver que pasan por SSL.

Para terminar con este apartado, decir que en el siguiente enlace disponemos más detalladamente datos relativos al uso de esta Geolocation API.

Saludos, lipman