Recherche de SSID grâce des Probe Request avec la bibliothèque Tins en C++

Récupération de paquets Wi-Fi

Avant de chercher des SSID et des clients qui essayent de se connecter, il faut récupérer des paquets à analyser. Par défaut, il est courant que les interfaces sans-fil n'écoutent que les communications qui les concernent (sous GNU/Linux, c'est le mode managed pour iwconfig). Pour tout écouter (si votre carte Wi-Fi ainsi que son pilote le permettent), il faut passer en mode monitor. Sous GNU/Linux, il faut exécuter avec les droits SuperUtilisateur iwconfig wlan0 mode monitor (en remplaçant wlan0 par votre interface Wi-Fi, dont la liste vous est donné par iwconfig). S'il y a une erreur tel que Error for wireless request "Set Mode" (8B06) : SET failed on device wlan0 ; Device or resource busy., c'est que votre interface est allumée, alors qu'il faut qu'elle soit éteinte pour changer de mode, ifconfig wlan0 down l'éteint et ifconfig wlan0 up l'allume (encore une fois remplacé wlan0 par votre interface Wi-Fi).

Une fois passé en mode monitor, il faut écouter votre interface Wi-Fi. Vous pouvez enregistrer les paquets que vous captez (au format pcap) pour les analyser ultérieurement (c'est ce que je vous conseille dans un premier temps) ou les analyser à la volé puis les jeter avec un script (ce qui est plus efficace mais nécessite d'avoir un script qui marche). Vous pouvez par exemple récupérer des paquets avec WireShark (un logiciel libre connu avec une interface graphique). Il est également possible de le faire avec la bibliothèque Tins en C++.

Usage des Probe Request

Nous sommes dans le cas du Wi-Fi, donc nous nous appuyons sur l'ensemble de normes IEEE 802.11. Dans notre cas, nous cherchons des paquets contenant une Probe Request (correspondant au type Tins::Dot11ProbeResponse pour Tins). Dans celles-ci nous cherchons le SSID, qui se trouve dans un paquet contenu dans la Probe Request, de type "IEEE 802.11 wireless LAN management frame" en tant que "Tagged parameter" pour WireShark et de type Tins::Dot11ManagementFrame pour Tins. Tins::Dot11ManagementFrame a une méthode ssid (sans argument) qui retourne le SSID.

Exemple de scripts

Script de base

Script de base sans using namespace

/* g++ -Wall -Wextra -pedantic -Werror -std=c++11 ssid-searched.cpp -ltins */


#include <stdlib.h>
#include <tins/sniffer.h>
#include <tins/dot11.h>
#include <map>
#include <set>
#include <string>
#include <stdio.h>


typedef Tins::Dot11::address_type dot11_address_t;
typedef std::set<dot11_address_t> set_dot11_address_t;
static std::map< std::string, std::map< dot11_address_t, set_dot11_address_t > > ssid_searched;

static size_t counter = 0;
#define NB_MAX_PACKETS 10000


bool
filter(const Tins::PDU* a_pdu)
{
	a_pdu = a_pdu->find_pdu<Tins::Dot11>();
	if(a_pdu != NULL)
	{
		a_pdu = a_pdu->find_pdu<Tins::Dot11ProbeResponse>();
		if (a_pdu != NULL)
		{
			a_pdu = a_pdu->find_pdu<Tins::Dot11ManagementFrame>();
			return a_pdu != NULL;
		}
	}
	return false;
}

void
process(const Tins::PDU& a_pdu)
{
	const Tins::Dot11ProbeResponse* probe =
		a_pdu.find_pdu<Tins::Dot11ProbeResponse>();
	const Tins::Dot11::address_type addr_src = probe->addr1();
	const Tins::Dot11::address_type addr_dst = probe->addr2();
	
	const Tins::Dot11ManagementFrame* management_frame =
		a_pdu.find_pdu<Tins::Dot11ManagementFrame>();
	const std::string ssid = management_frame->ssid();
	
	ssid_searched[ssid][addr_dst].insert(addr_src);
}

bool
callback(const Tins::PDU& a_pdu)
{
	if(filter(&a_pdu))
	{
		process(a_pdu);
		++counter;
	}
	return counter <= NB_MAX_PACKETS;
}

void
sum_up_csv(void)
{
	for(const std::pair<std::string, std::map< dot11_address_t, set_dot11_address_t > >& ssid : ssid_searched)
	{
		for(const std::pair< dot11_address_t, set_dot11_address_t >& addr_ssid : ssid.second)
		{
			for(const Tins::Dot11::address_type& addr_client : addr_ssid.second)
			{
				printf("%s;%s;%s\n",
				       ssid.first.c_str(),
				       addr_ssid.first.to_string().c_str(),
				       addr_client.to_string().c_str());
			}
		}
	}
}

int
main(int argc, const char* argv[])
{
	if(argc == 1)
	{
		Tins::SnifferConfiguration sniffer_conf;
		sniffer_conf.set_promisc_mode(true);
		Tins::Sniffer sniffer("wlan0", sniffer_conf);
		sniffer.sniff_loop(callback);
	}
	else
	{
		Tins::FileSniffer sniffer(argv[1]);
		sniffer.sniff_loop(callback);
	}
	
	sum_up_csv();
	
	return EXIT_SUCCESS;
}

Script de base avec using namespace

/* g++ -Wall -Wextra -pedantic -Werror -std=c++11 ssid-searched.cpp -ltins */


#include <stdlib.h>
#include <tins/sniffer.h>
#include <tins/dot11.h>
#include <map>
#include <set>
#include <string>
#include <stdio.h>

using namespace Tins;
using namespace std;


static map< string, map< Dot11::address_type, set<Dot11::address_type> > > ssid_searched;
static size_t counter = 0;
#define NB_MAX_PACKETS 10000


bool
filter(const PDU* a_pdu)
{
	a_pdu = a_pdu->find_pdu<Dot11>();
	if(a_pdu != NULL)
	{
		a_pdu = a_pdu->find_pdu<Dot11ProbeResponse>();
		if (a_pdu != NULL)
		{
			a_pdu = a_pdu->find_pdu<Dot11ManagementFrame>();
			return a_pdu != NULL;
		}
	}
	return false;
}

void
process(const PDU& a_pdu)
{
	const Dot11ProbeResponse* probe =
		a_pdu.find_pdu<Dot11ProbeResponse>();
	const Dot11::address_type addr_src = probe->addr1();
	const Dot11::address_type addr_dst = probe->addr2();
	
	const Dot11ManagementFrame* management_frame =
		a_pdu.find_pdu<Dot11ManagementFrame>();
	const string ssid = management_frame->ssid();
	
	ssid_searched[ssid][addr_dst].insert(addr_src);
}

bool
callback(const PDU& a_pdu)
{
	if(filter(&a_pdu))
	{
		process(a_pdu);
		++counter;
	}
	return counter <= NB_MAX_PACKETS;
}

void
sum_up_csv(void)
{
	for(const pair<string, map< Dot11::address_type, set<Dot11::address_type> > >& ssid : ssid_searched)
	{
		for(const pair< Dot11::address_type, set<Dot11::address_type> >& addr_ssid : ssid.second)
		{
			for(const Dot11::address_type& addr_client : addr_ssid.second)
			{
				printf("%s;%s;%s\n",
				       ssid.first.c_str(),
				       addr_ssid.first.to_string().c_str(),
				       addr_client.to_string().c_str());
			}
		}
	}
}

int
main(int argc, const char* argv[])
{
	if(argc == 1)
	{
		SnifferConfiguration sniffer_conf;
		sniffer_conf.set_promisc_mode(true);
		Sniffer sniffer("wlan0", sniffer_conf);
		sniffer.sniff_loop(callback);
	}
	else
	{
		FileSniffer sniffer(argv[1]);
		sniffer.sniff_loop(callback);
	}
	
	sum_up_csv();
	
	return EXIT_SUCCESS;
}

Script malin

/* g++ -Wall -Wextra -pedantic -Werror -std=c++11 ssid-searched.cpp -ltins */


#include <stdlib.h>
#include <tins/sniffer.h>
#include <tins/dot11.h>
#include <map>
#include <set>
#include <string>
#include <stdio.h>

using namespace Tins;
using namespace std;


static map< string, map< Dot11::address_type, set<Dot11::address_type> > > ssid_searched;
static size_t counter = 0;
#define NB_MAX_PACKETS 10000


static inline
bool
file_exists(const char* file_path)
{
	FILE* file = fopen(file_path, "r");
	if(file == NULL)
	{
		return false;
	}
	fclose(file);
	return true;
}

static inline
bool
filter(const PDU* a_pdu)
{
	a_pdu = a_pdu->find_pdu<Dot11ProbeResponse>();
	if(a_pdu != NULL)
	{
		a_pdu = a_pdu->find_pdu<Dot11ManagementFrame>();
		return a_pdu != NULL;
	}
	return false;
}

static inline
bool
filter(const PDU& a_pdu)
{
	return filter(&a_pdu);
}

void
process(const PDU& a_pdu)
{
	const Dot11ProbeResponse* probe =
		a_pdu.find_pdu<Dot11ProbeResponse>();
	const Dot11::address_type addr_src = probe->addr1();
	const Dot11::address_type addr_dst = probe->addr2();
	
	const Dot11ManagementFrame* management_frame =
		a_pdu.find_pdu<Dot11ManagementFrame>();
	const string ssid = management_frame->ssid();
	
	ssid_searched[ssid][addr_dst].insert(addr_src);
}

bool
callback(const PDU& a_pdu)
{
	if(filter(a_pdu))
	{
		process(a_pdu);
		++counter;
	}
	return counter <= NB_MAX_PACKETS;
}

void
sum_up_csv(bool header = true)
{
	if(ssid_searched.empty())
	{
		return;
	}
	
	if(header)
	{
		puts("SSID;SSID_MAC;client_MAC");
	}
	
	for(const pair<string, map< Dot11::address_type, set<Dot11::address_type> > >& ssid : ssid_searched)
	{
		for(const pair< Dot11::address_type, set<Dot11::address_type> >& addr_ssid : ssid.second)
		{
			for(const Dot11::address_type& addr_client : addr_ssid.second)
			{
				printf("%s;%s;%s\n",
				       ssid.first.c_str(),
				       addr_ssid.first.to_string().c_str(),
				       addr_client.to_string().c_str());
			}
		}
	}
}

int
main(int argc, const char* argv[])
{
	if(argc == 1)
	{
		SnifferConfiguration sniffer_conf;
		sniffer_conf.set_promisc_mode(true);
		Sniffer sniffer("wlan0", sniffer_conf);
		sniffer.sniff_loop(callback);
	}
	else
	{
		if(!file_exists(argv[1]))
		{
			fprintf(stderr, "%s does not exist or is not a readable file.\n", argv[1]);
			return EXIT_FAILURE;
		}
		FileSniffer sniffer(argv[1]);
		sniffer.sniff_loop(callback);
	}
	
	sum_up_csv();
	
	return EXIT_SUCCESS;
}

Script très malin

/* g++ -Wall -Wextra -pedantic -Werror -std=c++11 ssid-searched.cpp -ltins */


#include <stdlib.h>
#include <tins/sniffer.h>
#include <tins/dot11.h>
#include <map>
#include <set>
#include <string>
#include <stdio.h>


static inline
bool
file_exists(const char* file_path)
{
	FILE* file = fopen(file_path, "r");
	if(file == NULL)
	{
		return false;
	}
	fclose(file);
	return true;
}

template <typename T, typename E>
static inline
bool
is_in(T container, E element)
{
	return container.find(element) != container.end();
}


using namespace Tins;
using namespace std;


static map< const string, map< Dot11::address_type, set<Dot11::address_type> > > ssid_searched;
static size_t counter = 0;
#define NB_MAX_PACKETS 10000


struct ssid_and_client_t
{
	const std::string         ssid;
	const Dot11::address_type addr_ssid;
	const Dot11::address_type addr_client;
};
typedef struct ssid_and_client_t ssid_and_client_t;

void process_add(const ssid_and_client_t* data)
{
	ssid_searched[data->ssid][data->addr_ssid].insert(data->addr_client);
}

void process_print_new(const ssid_and_client_t* data)
{
	if(!is_in(ssid_searched[data->ssid][data->addr_ssid], data->addr_client))
	{
		ssid_searched[data->ssid][data->addr_ssid].insert(data->addr_client);
		printf("%s;%s;%s\n",
		       data->ssid.c_str(),
		       data->addr_ssid.to_string().c_str(),
		       data->addr_client.to_string().c_str());
		fflush(stdout);
	}
}

static void (*process)(const ssid_and_client_t* data);


static inline
bool
filter(const Tins::PDU* a_pdu)
{
	a_pdu = a_pdu->find_pdu<Dot11ProbeResponse>();
	if(a_pdu != NULL)
	{
		a_pdu = a_pdu->find_pdu<Dot11ManagementFrame>();
		return a_pdu != NULL;
	}
	return false;
}

static inline
bool
filter(const Tins::PDU& a_pdu)
{
	return filter(&a_pdu);
}

void
prepare_and_process(const Tins::PDU& a_pdu)
{
	const Dot11ProbeResponse* probe =
		a_pdu.find_pdu<Tins::Dot11ProbeResponse>();
	const Dot11ManagementFrame* management_frame =
		a_pdu.find_pdu<Tins::Dot11ManagementFrame>();
	
	ssid_and_client_t data =
	{
		management_frame->ssid().c_str(),
		probe->addr2(),
		probe->addr1()
	};
	process(&data);
}

static inline
bool
callback(const Tins::PDU& a_pdu)
{
	if(filter(a_pdu))
	{
		prepare_and_process(a_pdu);
		++counter;
	}
	return counter <= NB_MAX_PACKETS;
}

void
sum_up_csv(bool header = true)
{
	if(ssid_searched.empty())
	{
		return;
	}
	
	if(header)
	{
		puts("SSID;SSID_MAC;client_MAC");
	}
	
	for(const pair<const string, map< Dot11::address_type, set<Dot11::address_type> > >& ssid : ssid_searched)
	{
		for(const pair< Dot11::address_type, set<Dot11::address_type> >& addr_ssid : ssid.second)
		{
			for(const Dot11::address_type& addr_client : addr_ssid.second)
			{
				printf("%s;%s;%s\n",
				       ssid.first.c_str(),
				       addr_ssid.first.to_string().c_str(),
				       addr_client.to_string().c_str());
			}
		}
	}
}

int
main(int argc, const char* argv[])
{
	if(argc == 1)
	{
		process = process_print_new;
		SnifferConfiguration sniffer_conf;
		sniffer_conf.set_promisc_mode(true);
		/* ifconfig wlan0 down
		 * iwconfig wlan0 mode monitor
		 * ifconfig wlan0 up */
		Sniffer sniffer("wlan0" , sniffer_conf);
		sniffer.sniff_loop(callback);
	}
	else
	{
		if(!file_exists(argv[1]))
		{
			fprintf(stderr, "%s does not exist or is not a readable file.\n", argv[1]);
			return EXIT_FAILURE;
		}
		process = process_add;
		FileSniffer sniffer(argv[1]);
		sniffer.sniff_loop(callback);
		sum_up_csv();
	}
	
	return EXIT_SUCCESS;
}

Sur le même sujet