24 de abril de 2011

Firesheep bajo Linux

Mucho se ha hablado de Firesheep, esa pequeña extension de Firefox que nos permite capturar las sesiones HTTP que estén presentes en nuestro mismo dominio de colisión.
Cierto es que este tipo de ataques se conocen desde hace bastante tiempo, como se puede ver en http://www.defcon.org/images/defcon-16/dc16-presentations/defcon-16-perry.pdf

En este artículo no se va a tratar de aspectos técnicos de la implementación de Firesheep, ni de session sidejacking, eso lo haremos en artículos posteriores.
Por ahora, nos vamos a concentrar en la compilación y ejecución de Firesheep sobre Linux.

El código de Firesheep está disponible en https://github.com/codebutler/firesheep
La extensión está programada en C++ y JavaScript usando como backend de captura las libpcap (winpcap en el caso de Windows).

En principio, esta extensión estaba disponible sólo para Windows y MAC, pero el 5 de Noviembre de 2010 se realizó el commit con el código de Linux como se puede ver aquí https://github.com/codebutler/firesheep/commit/f6ced0af100df60d472f760bc9b47fa05f4ebfb1

Si nos fijamos en los comentarios de los commits, podemos leer:

* Added linux support using Michajlo Matijkiw's work with various fixes
* Needs policykit installed (no need to manualy set permissions on backend)

Para bajar y compilar Firesheep, usamos git & autotools:


git clone git://github.com/mickflemm/firesheep.git
cd firesheep
git submodule update --init
./autogen.sh --with-xulrunner-sdk=/usr/lib/xulrunner-devel-1.9.2.13
make
firefox build/firesheep.xpi
cd ~/.mozilla/firefox/iquftp6a.default/extensions/firesheep@codebutler.com/platform/Linux_x86_64-gcc3sudo
./firesheep-backend --fix-permissions
airmon-ng wlan0 start


Como se puede intuir, Firesheep usa un binario de backend, el cual le hace de interfaz con las libpcap y los dispositivos de captura de la máquina. Este binario se suele encontrar en ~/.mozilla/firefox/xxxXXXxXX.default/extensions/firesheep@codebutler.com/platform/Linux_x86_64-gcc3/firesheep-backend en las máquinas de 64bits una vez instalada la extensión en el navegador Firefox.


usuario@studio:~/.mozilla/firefox/asddas.default/extensions/firesheep@codebutler.com/platform/Linux_x86_64-gcc3$ ./firesheep-backend --help
Syntax: ./firesheep-backend <iface> <capture filter>


Si miramos el código que procesa los *argv[] del backend en backend/src/main.cpp, allí podemos ver los parámetros que le podemos pasar al binario, justo a partir de la línea 52:


53 if (argc > 1) {
54 if (argv[1] == string("--fix-permissions")) {
55 if (platform.is_root()) {
56 if (platform.check_permissions()) {
57 /* Nothing to do */
58 return EXIT_SUCCESS;
59 } else {
60 platform.fix_permissions();
61 return EXIT_SUCCESS;
62 }
63 } else {
64 bool success = platform.run_privileged();
65 return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
66 }
67 } else if (argv[1] == string("--list-interfaces")) {
68 list_interfaces(&platform);
69 return EXIT_SUCCESS;
70 }
71 }
72
73 if (!platform.is_root()) {
74 cerr << "Run --fix-permissions first." << endl;
75 return EXIT_FAILURE;
76 }
77
78 if (argc < 3) {
79 cerr << "Syntax: " << argv[0] << " <iface> <capture filter>" << endl;
80 return EXIT_FAILURE;
81 }


Tras ver el código, comprobamos que las opciones que podemos usar son: --fix-permissions --list-interfacesy los parámetros son los necesarios para que el backend haga su tarea.Si observamos las líneas 73 a 76 del archivo main.cpp, podemos ver cómo es necesario ejecutar --fix-permissions:


73 if (!platform.is_root()) {
74 cerr << "Run --fix-permissions first." << endl;
75 return EXIT_FAILURE;
76 }


Vamos a probar si Firesheep detecta bien las interfaces de nuestra máquina. Para esto, usamos la opción --list-interfaces del backend:


firesheep-backend --list-interfacesterminate called after throwing an instance of 'std::runtime_error'
what(): libhal_device_get_property_string failed: org.freedesktop.Hal.NoSuchProperty
No property info.vendor on device with id /org/freedesktop/Hal/devices/net_0a_00_27_00_00_00
Abortado


Uf, parece que ha petado bien! Si nos fijamos en el error que nos da, dice que lo que ha fallado ha sido justamente libhal_device_get_property_string. Vamos a buscar ese método get en el código del backend del Firesheep:


usuario@studio:~/firesheep/backend/src$ grep -n libhal_device_get_property_string *
linux_platform.cpp:44: char *buf = libhal_device_get_property_string(context, device.c_str(), key.c_str(), error);
linux_platform.cpp:46: runtime_error ex(str(format("libhal_device_get_property_string failed: %s %s") % error->name % error->message));
usuario@studio:~/firesheep/backend/src$


Vemos que en el archivo linux_platform.cpp hay coincidencias, así que le echamos un vistazo:


41
42 string device_get_property_string(LibHalContext *context, string device, string key, DBusError *error)
43 {
44 char *buf = libhal_device_get_property_string(context, device.c_str(), key.c_str(), error);
45 if (dbus_error_is_set(error)) {
46 runtime_error ex(str(format("libhal_device_get_property_string failed: %s %s") % error->name % error->message));
47 dbus_error_free(error);
48 throw ex;
49 }
50 return string(buf);
51 }


Éste es el código que lanza el error, justo en la línea 46.Como esto no nos aclara mucho, vamos a buscar el string device_get_property_string en el código del backend, a ver si encontramos algo más interesante:


usuario@studio:~/firesheep/backend/src$ grep device_get_property_string *
linux_platform.cpp:string device_get_property_string(LibHalContext *context, string device, string key, DBusError *error)
linux_platform.cpp: char *buf = libhal_device_get_property_string(context, device.c_str(), key.c_str(), error);
linux_platform.cpp: runtime_error ex(str(format("libhal_device_get_property_string failed: %s %s") % error->name % error->message));
linux_platform.cpp: string iface = device_get_property_string(context, devices[i], "net.interface", &error);
linux_platform.cpp: string category = device_get_property_string(context, devices[i], "info.category", &error);
linux_platform.cpp: string parent = device_get_property_string(context, device, "net.originating_device", &error);
linux_platform.cpp: string parent_subsystem = device_get_property_string(context, parent, "info.subsystem", &error);
linux_platform.cpp: parent = device_get_property_string(context, parent, "info.parent", &error);
linux_platform.cpp: string vendor = device_get_property_string(context, parent, "info.vendor", &error);
linux_platform.cpp: string product = device_get_property_string(context, parent, "info.product", &error);
usuario@studio:~/firesheep/backend/src$


Bingo! Editamos el archivo linux_platform.cpp a partir de la línea 123. Ahí comentamos las dos llamadas a device_get_property_string que son las que fallan, y ponemos las string vendor y product que nosotros queramos:


121 /* Get device properties */
122
123 //string vendor = device_get_property_string(context, parent, "info.vendor", &error);
124 //string product = device_get_property_string(context, parent, "info.product", &error);
125 string vendor = "Surmano Fumano";
126 string product = "FireDev";
127 string description(str(format("%s %s") % vendor % product));


Por último, recompilamos e instalamos de nuevo la extensión.Perfecto! Podemos ver en las opciones de interface de Firesheep, cómo las interfaces aparecen con el vendor y product que hemos harcodeado en el archivo linux_platform.cppYa no falla Firesheep al ejecutarse y podemos usarlo justo para lo que fue creado: hacer sidejacking