IMA4 2017/2018 P3 : Différence entre versions

De Wiki de Projets IMA
(Réalisation du Projet)
(Semaine 7)
Ligne 1 113 : Ligne 1 113 :
  
 
==Semaine 7==
 
==Semaine 7==
 +
J'ai écrit les programmation à mesurer la puissance du channel et compter le nombre moyen de message, et les fonctions à détecter les attaque de Dos et 'Replay Attack'.
 +
 +
Source:
 +
 +
# -*- coding: utf-8 -*-
 +
 +
 +
from dev_telosb import TELOSB
 +
from dev_apimote import APIMOTE
 +
from zigbeedecode import ZigBeeNWKPacketParser
 +
from zigbeedecode import ZigBeeAPSPacketParser
 +
import sys
 +
import argparse
 +
import time
 +
import math
 +
import threading
 +
import array
 +
 +
<nowiki>
 +
####################################################
 +
#报文说明
 +
#0x17  -> length (总字节数 - 1)
 +
#0x61  -> 报头引导
 +
#0x88  -> 报头引导
 +
#0xd    -> frameID(不确定, 它随报文顺序,而增加)
 +
#0x34  -> PID(LOW)
 +
#0x12  -> PID(HIGH)
 +
#0x3    -> Addr16 of sender (LOW)
 +
#0x0    -> Addr16 of sender (HIGH)
 +
#0x1    -> Addr16 of receiver (LOW)
 +
#0x0    -> Addr16 of receiver (HIGH)
 +
#0xeb  ->  计数器?
 +
#0x0    ->  计数器?
 +
#0x68  |-
 +
#0x65  |-
 +
#0x6c  |-
 +
#0x6c  |-
 +
#0x6f  |-      ->    data
 +
#0x20  |-
 +
#0x77  |-
 +
#0x6f  |-
 +
#0x72  |-
 +
#0x6c  |-
 +
#0xe7  ->  checkSum(LOW)
 +
#0xa9  ->  checkSum(HIGH)
 +
####################################################
 +
</nowiki>
 +
 +
DEVICE = "/dev/ttyUSB1"
 +
CHANNEL = 0x19
 +
 +
class parser_trame:
 +
    def __init__(self, mes=None):
 +
        if mes is None:
 +
            self.mes = None
 +
            return
 +
        mes = array.array('B', packet)
 +
        self.mes = mes
 +
    def get_message(self, mes):
 +
        if(mes is None):
 +
            self.mes = None
 +
        else:
 +
            mes = array.array('B', mes)
 +
            self.mes = mes
 +
    def get_len(self):
 +
        if self.mes is not None:
 +
            return self.mes[0]
 +
    def get_data_len(self):
 +
        return self.get_len() - 13
 +
    def get_frameID(self):
 +
        if self.mes is not None:
 +
            return self.mes[3]
 +
    def get_PINID_LOW(self):
 +
        if self.mes is not None:
 +
            return self.mes[4]
 +
    def get_PINID_HIGH(self):
 +
        if self.mes is not None:
 +
            return self.mes[5]
 +
    def get_addr16_sender_low(self):
 +
        if self.mes is not None:
 +
            return self.mes[6]
 +
    def get_addr16_sender_high(self):
 +
        if self.mes is not None:
 +
            return self.mes[7]
 +
    def get_addr16_receiver_low(self):
 +
        if self.mes is not None:
 +
            return self.mes[8]
 +
    def get_addr16_receiver_high(self):
 +
        if self.mes is not None:
 +
            return self.mes[9]
 +
    def get_data(self):
 +
        if self.mes is not None:
 +
            return self.mes[12:-2]
 +
 +
 +
class PROTECTER:
 +
    def __init__(self, device, channel):
 +
        self.telosb = TELOSB(device)
 +
        self.parser = parser_trame()
 +
        self.channel = channel
 +
        self.telosb.set_channel(channel)
 +
        self.messages = {}
 +
 +
    def get_handle(self):
 +
        return self.telosb
 +
 +
    def sniffer_on(self,channel):
 +
        self.telosb.sniffer_on(channel)
 +
 +
    def sniffer_off(self):
 +
        self.telosb.sniffer_off()
 +
 +
    def open(self):
 +
        self.telosb.open()
 +
 +
    def close(self):
 +
        self.telosb.close()
 +
 +
    def set_channel(self, channel):
 +
        self.telosb.set_channel(channel)
 +
 +
    def get_puissance(self):
 +
        mes = self.telosb.pnext()
 +
        if(mes is None):
 +
            #return [False, self.telosb.get_handle().RF_getrssi() * -1]
 +
            return None
 +
        return [True, mes["dbm"] * -1]
 +
 +
    def get_package(self):
 +
        return self.telosb.get_package()
 +
 +
    def get_data(self):
 +
        self.parser.get_message(self.get_package())
 +
        if self.parser is None:
 +
            return None
 +
        else:
 +
            d = self.parser.get_data()
 +
            return d
 +
 +
    def monitor_puissance(self, channel, puissance_threshold, interval_echantillonnage=1,  period=3600):
 +
        self.sniffer_on(channel)
 +
        counter = 0
 +
        counter_valide = 0
 +
        puissance_sum = 0.0
 +
        start = time.time()
 +
        start_echantiilonage = time.time()
 +
        while(True):
 +
            if(time.time() - start > period):
 +
                self.sniffer_off()
 +
                return False
 +
            if(puissance_sum != 0 and counter != 0):
 +
                print(math.log(puissance_sum/counter))
 +
                print(puissance_sum)
 +
            if(time.time() - start_echantiilonage < interval_echantillonnage):
 +
                #print(counter)
 +
                #print(time.time())
 +
                a = self.get_puissance()
 +
                if(a):
 +
                    puissance_sum += a[1]
 +
                else:
 +
                    puissance_sum += 80
 +
                    counter += 1
 +
                while(time.time() - start_echantiilonage <= interval_echantillonnage):
 +
                    pass
 +
            else:
 +
                if(math.log(puissance_sum/(counter - counter_valide)) > puissance_threshold):
 +
                    self.sniffer_off()
 +
                    return True
 +
                else:
 +
                    counter = 0;
 +
                    counter_valide = 0
 +
                    puissance_sum = 0
 +
                    start_echantiilonage = time.time()
 +
 +
    def mesure_average_puissance(self, channel, interval_echantillonnage = 1, period=3600, duree_de_pulse=15):
 +
        self.sniffer_on(channel)
 +
        puissance_sum = 0.0
 +
        counter = 0
 +
        counter_valide = 0 #le nombre de messages qu'on reussir à récuperer
 +
        start = time.time()
 +
        start_echantiilonage = time.time()
 +
        #max_puissance_dbm = -256
 +
        while(True):
 +
            if(time.time() - start > period):
 +
                break
 +
            a = self.get_puissance()
 +
            if(a):
 +
                puissance_sum += a[1]
 +
            else:
 +
                puissance_sum += 80
 +
                counter += 1
 +
            while(time.time() - start_echantiilonage <= interval_echantillonnage):
 +
                pass
 +
            start_echantiilonage = time.time()
 +
           
 +
        self.sniffer_off()
 +
        #return math.log(puissance_sum/(counter - counter_valide))
 +
        return puissance_sum/counter
 +
        #return max_puissance_dbm
 +
 +
    def mesure_average_num_of_message_par_second(self, channel, period):
 +
        self.sniffer_on(channel)
 +
        counter = 0.0
 +
        start = time.time()
 +
        while(True):
 +
            if(self.telosb.pnext(10) is not None): #pnext(ms)
 +
                counter += 1
 +
            if(time.time() - start > period):
 +
                break
 +
        self.telosb.sniffer_off()
 +
        return counter/period
 +
 +
    def monitor_num_of_message(self, channel, period, interval_echantillonnage, num_threshold):
 +
        #num_threshold -> nombre_de_messages / interval_echantillonnage
 +
        self.sniffer_on(channel)
 +
        start = time.time()
 +
        start_echantiilonage = time.time()
 +
        counter = 0
 +
        while(True):
 +
            if(self.telosb.pnext() is not None):
 +
                counter += 1
 +
            if(time.time() - start >= period):
 +
                self.sniffer_off()
 +
                return False
 +
            if(time.time() - start_echantiilonage > interval_echantillonnage):
 +
                if(counter > 0):
 +
                    if(counter/interval_echantillonnage > num_threshold):
 +
                        self.telosb.sniffer_off()
 +
                        return True
 +
                    else:
 +
                        counter = 0
 +
                        start_echantiilonage = time.time()
 +
 +
 +
 +
    #period 检测的时间, time_danger: 当唱过time再收到相同数据, 收到攻击
 +
    def detect_replay_attack(self, period, time_danger):
 +
        #创建列表,用于保存,收到的数据以及时间戳的元组,
 +
        start = time.time()
 +
        datas = []
 +
        #while
 +
        while(True):
 +
            mes = self.get_data()
 +
            if mes is not None:
 +
                m = hash(mes.tostring())
 +
                print(m)
 +
                for d in datas:
 +
                    if(d[0] == m):
 +
                        if(time.time() - d[1] > time_danger):
 +
                            return True
 +
                datas.append((m, time.time()))
 +
                if(len(datas) > 0):
 +
                    if(time.time() - datas[0][1] > time_danger):
 +
                        del datas[0]
 +
            if(time.time() - start > period):
 +
                return False
 +
        pass
 +
 +
 +
def main():
 +
    protecter = PROTECTER(DEVICE, CHANNEL)
 +
    protecter.set_channel(0x19)
 +
    protecter.sniffer_on(0x19)
 +
    print(protecter.detect_replay_attack(100,10))
 +
    print(protecter.mesure_average_num_of_message_par_second(0x19, 5))                                                           
 +
    print(protecter.monitor_num_of_message(0x19,5,50,2.6))
 +
    print(protecter.mesure_average_puissance(0x19, 3, 10))
 +
 +
    protecter.sniffer_off()
 +
    protecter.close()
 +
 +
if __name__ == "__main__":
 +
    main()
  
 
=Documents Rendus=
 
=Documents Rendus=

Version du 9 avril 2018 à 02:29


Présentation générale

Description

Mon projet est suivant:

Le développement de l'Internet des Objets amène de nouveaux problèmes en terme de sécurité. En effet, ces objets, en général petits, n'embarquent que très peu d'éléments de sécurisation. Par ailleurs, leur mise à jour est souvent très difficile voire impossible. Un défaut de sécurité sur ce type d'objets permet à des utilisateurs malveillants de réaliser des attaques de grande envergure, du fait du grand nombre d'objets (par exemple ici).

Comme il est difficile de sécuriser l'objet par lui même (coût élevé, performances des objets limitées, ...), il est nécessaire de trouver d'autres solutions. Pour cela, nous proposons de développer :

1.une plateforme d'écoute sur les bandes ISM 868 MHZ, 2,4 GHz essentiellement ;

2.un "modèle" normal correspondant à un trafic de données non malveillant ;

3. différents scénarios d'attaques et leurs signatures associées.

Objectifs

Le but du projet est donc de réaliser un système permettant de récupérer et analyser les messages sous le protocole zigbee. Et il peut donner des signaux et messages indiquant si le réseau est sous l'attaque et associer le scénario et l'attaque. Le projet a pour but de récupérer et analyser les messages du réseau d'objet, et après, donner une manière d'indiquer si le réseau subit l'attaque. J'ai choisi le zigbee comme protocole de réseau.

1. Construire la communication avec quelques arduino et Xbee par le protocole zigbee.

2. Faire communiquer les arduino et récupérer les messages, et après, selon les messages, chercher une définition de la commmunication normale.

3. Attaquer le réseau par 'DDos' , 'Replay'.

4. Analyser les messages, et chercher les caractères correspondant aux différentes attaques.

5. Selon les analyses, donner une solution à indiquer si le réseau subit l'attaque.

6. Associer les attaques et les scénarios

Definition des Attaques

Doss[1]

Une attaque par déni de service (abr. DoS attack pour Denial of Service attack en anglais) est une attaque informatique ayant pour but de rendre indisponible un service, d'empêcher les utilisateurs légitimes d'un service de l'utiliser. À l’heure actuelle la grande majorité de ces attaques se font à partir de plusieurs sources, on parle alors d'attaque par déni de service distribuée (abr.DDoS attack pour Distributed Denial of Service attack). Il peut s'agir de :

l’inondation d’un réseau afin d'empêcher son fonctionnement ; la perturbation des connexions entre deux machines, empêchant l'accès à un service particulier ; l'obstruction d'accès à un service pour une personne en particulier ; également le fait d'envoyer des milliards d'octets à une box internet. L'attaque par déni de service peut ainsi bloquer un serveur de fichiers, rendre impossible l'accès à un serveur web ou empêcher la distribution de courriel dans une entreprise.

L'attaquant n'a pas forcément besoin de matériel sophistiqué. Ainsi, certaines attaques DoS peuvent être exécutées avec des ressources limitées contre un réseau de taille plus importante et plus moderne. On appelle parfois ce type d'attaque « attaque asymétrique » en raison de la différence de ressources entre les protagonistes.

Les attaques en déni de service se sont modifiées au cours du temps (voir historique).

Tout d'abord, les premières n'étaient perpétrées que par un seul « attaquant » ; rapidement, des attaques plus évoluées sont apparues, impliquant une multitude de « soldats ». On parle alors de 'DDoS' (distributed denial of service attack). Certains pirates informatiques se sont spécialisés dans la « levée » d’armées de « zombies », qu’ils peuvent ensuite louer à d’autres personnes ou groupes malveillants pour attaquer une cible particulière. Avec la forte augmentation du nombre d’échanges commerciaux sur Internet, le nombre de chantages au déni de service a très fortement progressé. DoSAttacks.jpg

Replay Attacks (Attaque par rejeu)[2]

Une attaque par rejeu (en anglais, replay attack ou playback attack) est une forme d'attaque réseau dans laquelle une transmission est malicieusement répétée par un attaquant qui a intercepté la transmission. Il s'agit d'un type d'usurpation d'identité.

Exemple d'attaque par rejeu:

L'exemple suivant présente une attaque par rejeu où Ève usurpe l'identité d'Alice en volant son mot de passe. Supposons qu'Alice veuille communiquer avec Bob. Pour être certain de communiquer avec Alice, Bob lui demande son mot de passe, qu'Alice lui envoie (possiblement après l'avoir chiffré avec une fonction de hachage cryptographique). Pendant ce temps, Ève écoute la conversation et enregistre le mot de passe (ou le résultat de l'application de la fonction de hachage sur le mot de passe, ce résultat est souvent appelé digest). Une fois l'échange terminé, Ève contacte Bob en prétendant qu'elle est Alice. Quand Bob lui demande son mot de passe pour vérifier son identité, Ève renvoie le mot de passe (ou son digest) qu'elle avait préalablement intercepté.

Les attaques par rejeu ne sont pas limitées au vol de mot de passe, ce genre d'attaque peut se faire dans d'autres situations. Une autre attaque permettant d'entrer dans un véhicule au moyen d'une attaque par rejeu est décrite plus bas dans cet article.

Replay attack on hash.jpg

Analyse du projet

Positionnement par rapport à l'existant

L'idée du projet est de construire un système de IOT , et essayer d'attaquer le réseau avec 'Dos' et 'Replay Attack', et après, récupérer les messages de IOT, analyser si il est sur des attaques.Si oui, on associe les scénarios et les attaques.

Forescout et Bitdefender sont deux entreprises célèbre dans le domaine de sécurité de IOT, ils utilisent quelques astuces pour identifier rapidement l’utilisateur, le propriétaire, le système d’exploitation, la configuration de l’appareil, les logiciels, les services, l’état des patchs et la présence d’agents de sécurité. Leur produits peuvent savoir si la périphérie est dangereux selon leur base de donnée des caractères des attaques du IOT. Ils peuvent aussi offrir les service d'afficher tous les information de périphérie connectés au réseau pour aider leur client à observer et contrôler le réseau. Leur produit est bon, mais ils ne peuvent supporter que les protocoles: wifi , bluetooch, 4G, Ethernet, IP etc.

Par contre,rapport à mon projet, mon produit a pour le but de la sécurité de IOT dont protocol est Zigbee et il surveille le réseau de IOT en à deux aspects. Un est la surveillance du contenu de messages envoyé dans le réseau. L'autre est la surveillance de la caractère physique -- puissance du channel.

Analyse du premier concurrent

Forescout

Forescout.png

ForeScout peut identifier les appareils Internet des objets (IoT), par example les ordinateurs,

les tablettes ou smartphones non gérés, les contrôler et organiser une réponse à l'échelle

du système.


Les spécialités principales sont:

1. Identifier les appareils et les détails indétectables par d'autres systèmes

2. Contrôler l'accès, refuser le chaos

3. Organiser la sécurité à l'échelle du système


Il a une grande base de donnée de sécurité qui lui aide à trouver les IOT vulnérable,

dangerous ou qui a des hautes risques. Son advantage principale est ce qu'il peut

détecter, identifier les IOT qui connecte au réseau et donner leur détails.

La façon de l'utiliser est suivant:

Projet 2.png

Analyse du second concurrent

Bitdefender BOX

Bitdefender BOX.png

BitDefender Box est une solution de protéger le IOT en l'autre manière,

Elle peut aussi detecter les apparails connectés au réseau, mais son acte

principal de protection est de dentifiez les failles de sécurité et les risques

sur le réseau, Lorsqu'elle détecte quelque chose, elle passe à l'action. BOX

fait correspondre les informations collectées à partir de vos appareils avec

des bases de données de vulnérabilités en ligne, avant de fournir un rapport

détaillé de l'opération. Elle fournit également des conseils sur la manière

de gérer et de sécuriser votre réseau, en fonction des vulnérabilités détectées.

Scénario d'usage du produit ou du concept envisagé

Mon produit est construit par un telsob. Il est utilisé à surveiller le IOT de Zigbee pour détecter les attaques de 'Dos' et 'Replay Attack'. Il peut récupère des trames du IOT et mesurer la puissance du channel. La utilisation est sample qu'on insère un telosb à pc ou l'autre appareil qui a le serial et peut lancer le scénario de python, après, lance mon scénario de python. Mon Produit offre des fonction: mesurer le nombre moyen de message dans un réseau et la puissance moyenne dans une channel, détecter l'attaque de Dos avec 2 manières: surveillance le nombre moyen de message, et la puissance moyenne dans une channel. Et il offre aussi la fonction pour détecter l'attaque de 'Replay Attack'.


L'idée des trois manière des surveillances est suivant:


Surveillance du nombre moyen de message

Quand le réseau est sur attaque de Dos, les appareils du IOT envoient plus de messages que quand il n'est pas sous attaque. Donc on peut d'abord mesurer le nombre moyen de message quand il n'est pas sous attaque, après, on entend les messages dans le réseau et les compte, si le nombre moyen de message que on compte est supérieur que le nombre moyen de message qu'on mesure d'abord, c'est à dire que le réseau est sous attaque de Dos.

Surveillance de la puissance du channel

L'idée de la manière est comme dont Surveillance du nombre moyen de message. Quand le réseau est sur attaque de Dos, les appareils du IOT envoient plus de messages que quand il n'est pas sous attaque, donc la puissance de channel va augmenter. Donc on peut d'abord mesurer la puissance du channel quand il n'est pas sous attaque, après, on mesure la puissance du channel, si la puissance du channel que on mesure est supérieur que le la puissance du channel qu'on mesure d'abord, c'est à dire que le réseau est sous attaque de Dos.

Détection l'attaque de 'Replay Attack

On suppose que chaque message dans le réseau apporte une identité spéciale qui change avec le temps, il n'est pas possible que il y a deux même message dans le réseau. donc mon produit offre une méthode à obtenir les message et les enregistrer, chaque fois il récupère un message, il va vérifier si le nouveau message est dans la liste de message enregistré, sinon, c'est à dire que le réseau n'est pas sous attaque, or, il est sur l'attaque de 'Replay Attaque'.

Réponse à la question difficile

Quel est le matériel ?

Je utilise 4 Arduino Uno, 4 Xbee Adapteur, 4 Arduino_xbee_shield, 4 Xbee, 1 telosb.


Quel est le protocole ?

Je utilise Zigbee comme le protocol de IOT.


L'acte d'analyser les donner?

Je utilise la surveillance du nombre moyen de message, la surveillance de la puissance du channel et la détection l'attaque de 'Replay Attack à analyser pour juger si le réseau est sous attaque.

Préparation du projet

Cahier des charges

Choix techniques : matériel et logiciel

4 Arduino Uno

Arduino Uno.jpg

1 Xbee Adapteur

Xbee adapteur.jpg


4 Arduino_xbee_shield


Arduino xbee shield.jpg

4 Xbee

Xbee.jpg


1 telosb

Telosb.jpg

4 piles extérieurs


Logiciel:

Python, Goodfet.

Liste des tâches à effectuer

1. Construire un IOT avec 3 arduino sous le protocole zigbee.

2. Faire communiquer les arduino et récupérer les messages, et après, selons les messages, chercher une définition de 'commmunication normale'.

3. Attaquer le réseau par Dos, 'Replay Attack'.

4. Analyser les messages, et chercher les caractères correspondant à la façon d'attaque.

5. Selon les analyses, donner une solution à indiquer si le réseau subit l'attaque.

Calendrier prévisionnel

Réalisation du Projet

Feuille d'heures

Tâche Prélude Heures S1 Heures S2 Heures S3 Heures S4 Heures S5 Heures S6 Heures S7 Heures S8 Heures S9 Heures S10 Total
Analyse du projet 30 10 10 12 10 14 15 13 12

Prologue

Semaine 1

J'ai obtenu les matériaux et construit un IOT simple qui contenait 4 arduinos avec Xbee. Les arduinos peuvent se communiquer entre eux.

Après, je vais faire quelles attaquer(par exemple Doss et 'reply attack' etc.) à l'IOT et récuper les trames pour analyser.

Semaine 2

J'ai changé le mode de communication de Xbee de AT à API, et maintenant, ils peuvent non se communiquer entre des end-points. Et j'ai écrit un simple protocole de communication pour simuler la communication réelle. Après, je vais commencer à attaquer le système avec Ddos. Je vais utiliser un arduino avec xbee pour envoyer les trame très fréquemment à le coordinateur et le end-point, et utiliser un xbee lié avec pc à récupérer les trame et calculer la fréquence des trames, leur puissances etc.

Média:Api2 communication.mp4

Semaine 3

J'ai chercher les arts d'attaquer le IOT avec DDos, et je vais attaquer le IOT par 2 façon, le premier est d'utiliser un arduino à envoyer très fréquement les trames à un arduino de le IOT, et tester si le IOT se communique normalement, si non, de quelle fréquence, elle n'est pas fonctionne normalement. L'autre façon est d'envoyer les trame avec très grande de taille, et tester si le IOT se communique normalement, si non, à quel taille de trame, elle n'est pas fonctionne normalement.


Semaine 4

J'ai complété la communication de IOT. La communication est simple, mais practical: il y a 3 arduino(on va s'appleler A,B,C à la suite) avec xbee dans le réseau, dont 3 se communiquent, une est comme le coordinateur, les autres 2 sont comme end_point devices. Le fonctionnement est: 1. A envoie un message 'allumer B' à B, et reste allumé 3 seconds, après il éteint 3 seconds, et envoie un message 'allumer B' à B. 2. Quand B récupère 'allumer B' de A, il va allumer le Led, et après, envoyer 'allumer C à C. Quand B récupère 'éteindre B' de A, il va éteindre le Led, et après, envoyer 'éteindre C à C. 3. Quand c récupère 'allumer c' de B, il va allumer le Led. Quand c récupère 'éteindre c' de B, il va éteindre le Led, et après, envoyer 'éteindre C à C.

Média:Communication 3 arduino.mp4

source:

Arduino A:

  1. include <XBee.h>
  2. include <inttypes.h>

//pour indiquer l'action;

  1. define ALLUMER 0
  2. define ETEINDRE 1

enum status_t{allumee, eteindu}; typedef enum status_t status;

const uint8_t id_arduino_local = 'a'; const uint8_t id_arduino_dest = 'b'; const uint8_t id_arduino_previous = 0; uint8_t id_message = 0;

//pour controler les de l'id_arduino prochain uint8_t action = ALLUMER;

uint8_t payload[] = {0,0,0}; //test -> {id_arduino,id_message,action}; uint8_t address_local = 0x00; uint8_t address_dest = 0x01;

status led_etat_self = eteindu;

struct message{

   uint8_t id_arduino;
   uint8_t id_message;
   uint8_t mes;

}; typedef struct message MESSAGE;

XBee xbee = XBee();


Tx16Request tx = Tx16Request(address_dest, payload, sizeof(payload)); TxStatusResponse txStatus = TxStatusResponse();

XBeeResponse response = XBeeResponse(); Rx16Response rx16 = Rx16Response(); Rx64Response rx64 = Rx64Response(); void sendMessageAllumer(){

   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
           id_message = 0;
       }
   else{
           id_message += 1;
       }
   payload[2] = ALLUMER;
   xbee.send(tx);


   // after sending a tx request, we expect a status response
   // wait up to 5 seconds for the status response
   if (xbee.readPacket(500)) {
       // got a response!
       // should be a znet tx status
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           // get the delivery status, the fifth byte
           if (txStatus.getStatus() == SUCCESS) {
               // success.  time to celebrate
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}


void sendMessageEteindre(){

   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
           id_message = 0;
       }
   else{
           id_message += 1;
       }
   payload[2] = ETEINDRE;
   xbee.send(tx);
   // after sending a tx request, we expect a status response
   // wait up to 5 seconds for the status response
   if (xbee.readPacket(500)) {
       // got a response!
       // should be a znet tx status
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           // get the delivery status, the fifth byte
           if (txStatus.getStatus() == SUCCESS) {
               // success.  time to celebrate
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}

MESSAGE getMessage(){

   xbee.readPacket();
   MESSAGE mes;
   mes.id_arduino = 0;
   mes.id_message = 0;
   mes.mes = 0;
   if (xbee.getResponse().isAvailable()) {
       // got something
       if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE) {
           // got a rx packet
           if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
               xbee.getResponse().getRx16Response(rx16);
               //option = rx16.getOption();
               //data = rx16.getData(0);
               mes.id_arduino = rx16.getData(0);
               mes.id_message = rx16.getData(1);
               mes.mes = rx16.getData(2);
           }
       }
   }
   return mes;

}

void setup() {

   Serial.begin(9600);
   xbee.setSerial(Serial);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)

}

void loop() {

   if(led_etat_self == eteindu){
       led_etat_self = allumee;
       digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
       delay(1000);
       sendMessageAllumer();
       delay(2000);
   }
   else if(led_etat_self == allumee){
       led_etat_self = eteindu;
       digitalWrite(LED_BUILTIN, LOW);
       delay(1000);
       sendMessageEteindre();
       delay(2000);
   }

}

Arduino B:

  1. include <XBee.h>
  2. include <inttypes.h>

//pour indiquer l'action;

  1. define ALLUMER 0
  2. define ETEINDRE 1

enum status_t{allumee, eteindu}; typedef enum status_t status;

const uint8_t id_arduino_local = 'b'; const uint8_t id_arduino_dest = 'c'; const uint8_t id_arduino_previous = 'a'; uint8_t id_message = 0;

//pour controler les de l'id_arduino prochain uint8_t action = ALLUMER;

uint8_t payload[] = {0,0,0}; //test -> {id_arduino,id_message,action}; uint8_t address_local = 0x01; uint8_t address_dest = 0x02;

status led_etat_self = eteindu;

struct message{

   uint8_t id_arduino;
   uint8_t id_message;
   uint8_t mes;

}; typedef struct message MESSAGE;


XBee xbee = XBee();


Tx16Request tx = Tx16Request(address_dest, payload, sizeof(payload));

TxStatusResponse txStatus = TxStatusResponse();

XBeeResponse response = XBeeResponse(); Rx16Response rx16 = Rx16Response(); Rx64Response rx64 = Rx64Response(); void sendMessageAllumer(){

   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
       id_message = 0;
   }
   else{
       id_message += 1;
   }
   payload[2] = ALLUMER;
   xbee.send(tx);
   if (xbee.readPacket(1000)) {
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           if (txStatus.getStatus() == SUCCESS) {
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}


void sendMessageEteindre(){

   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
       id_message = 0;
   }
   else{
       id_message += 1;
   }
   payload[2] = ETEINDRE;
   xbee.send(tx);
   // after sending a tx request, we expect a status response
   // wait up to 5 seconds for the status response
   if (xbee.readPacket(1000)) {
       // got a response!
       // should be a znet tx status
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           // get the delivery status, the fifth byte
           if (txStatus.getStatus() == SUCCESS) {
               // success.  time to celebrate
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}

MESSAGE getMessage(){

   xbee.readPacket();
   MESSAGE mes;
   mes.id_arduino = 0;
   mes.id_message = 0;
   mes.mes = 0;
   if (xbee.getResponse().isAvailable()) {
       // got something
       if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE) {
           // got a rx packet
           if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
               xbee.getResponse().getRx16Response(rx16);
               //option = rx16.getOption();
               //data = rx16.getData(0);
               mes.id_arduino = rx16.getData(0);
               mes.id_message = rx16.getData(1);
               mes.mes = rx16.getData(2);
           }
       }
   }
   return mes;

}

void setup() {

   Serial.begin(9600);
   xbee.setSerial(Serial);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)

}

void loop() {

   MESSAGE mes = getMessage();
   if(mes.id_arduino == id_arduino_previous){
       if(mes.mes == ALLUMER){
           digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
           led_etat_self = allumee;
           delay(1000);
           sendMessageAllumer();
       }
       else if(mes.mes == ETEINDRE){
           digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
           led_etat_self = eteindu;
           delay(1000);
           sendMessageEteindre();
       }
   }

}


Arduino C:

  1. include <XBee.h>
  2. include <inttypes.h>

//pour indiquer l'action;

  1. define ALLUMER 0
  2. define ETEINDRE 1

enum status_t{allumee, eteindu}; typedef enum status_t status;

const uint8_t id_arduino_local = 'c'; const uint8_t id_arduino_dest = 'd'; const uint8_t id_arduino_previous = 'b'; uint8_t id_message = 0;

//pour controler les de l'id_arduino prochain uint8_t action = ALLUMER;

uint8_t payload[] = {0,0,0}; //test -> {id_arduino,id_message,action}; uint8_t address_local = 0x02; uint8_t address_dest = 0x03;

status led_etat_self = eteindu;

struct message{

   uint8_t id_arduino;
   uint8_t id_message;
   uint8_t mes;

}; typedef struct message MESSAGE;


XBee xbee = XBee();


Tx16Request tx = Tx16Request(address_dest, payload, sizeof(payload));

TxStatusResponse txStatus = TxStatusResponse();

XBeeResponse response = XBeeResponse(); Rx16Response rx16 = Rx16Response(); Rx64Response rx64 = Rx64Response();

void sendMessageAllumer(){

   // start transmitting after a startup delay.  Note: this will rollover to 0 eventually so not best way to handle
   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
       id_message = 0;
   }
   else{
       id_message += 1;
   }
   payload[2] = ALLUMER;
   xbee.send(tx);
   if (xbee.readPacket(1000)) {
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           if (txStatus.getStatus() == SUCCESS) {
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}


void sendMessageEteindre(){

   payload[0] = id_arduino_local;
   payload[1] = id_message;
   if(id_message == 255){
       id_message = 0;
   }
   else{
       id_message += 1;
   }
   payload[2] = ETEINDRE;
   xbee.send(tx);
   // after sending a tx request, we expect a status response
   // wait up to 5 seconds for the status response
   if (xbee.readPacket(1000)) {
       // got a response!
       // should be a znet tx status
       if (xbee.getResponse().getApiId() == TX_STATUS_RESPONSE) {
           xbee.getResponse().getTxStatusResponse(txStatus);
           // get the delivery status, the fifth byte
           if (txStatus.getStatus() == SUCCESS) {
               // success.  time to celebrate
           } else {
           }
       }
   } else if (xbee.getResponse().isError()) {
   } else {
   }

}

MESSAGE getMessage(){

   xbee.readPacket();
   MESSAGE mes;
   mes.id_arduino = 0;
   mes.id_message = 0;
   mes.mes = 0;
   if (xbee.getResponse().isAvailable()) {
       if (xbee.getResponse().getApiId() == RX_16_RESPONSE || xbee.getResponse().getApiId() == RX_64_RESPONSE) {
           // got a rx packet
           if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
               xbee.getResponse().getRx16Response(rx16);
               //option = rx16.getOption();
               //data = rx16.getData(0);
               mes.id_arduino = rx16.getData(0);
               mes.id_message = rx16.getData(1);
               mes.mes = rx16.getData(2);
           }
       }
   }
   return mes;

}

void setup() {

   //    pinMode(statusLed, OUTPUT);
   //   pinMode(errorLed, OUTPUT);
   Serial.begin(9600);
   xbee.setSerial(Serial);
   pinMode(LED_BUILTIN, OUTPUT);
   digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)

}

void loop() {

   MESSAGE mes = getMessage();
   if(mes.id_arduino == id_arduino_previous){
       if(mes.mes == ALLUMER){
           digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
           led_etat_self = allumee;
           //delay(1000);
           //sendMessageAllumer();
       }
       else if(mes.mes == ETEINDRE){
           digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
           led_etat_self = eteindu;
           //delay(1000);
           //sendMessageEteindre();
       }
   }

}

Semaine 5

J'ai trouvé un outil qui s'appelle Killerbee. Il est très utile à attaquer le réseau de Zigbee, et on peut aussi l'utiliser à surveiller le réseau, il offre la méthode de 'sniffer' pour récupérer tous les message dans un channel(par contre, xbee ne peut que récupérer les message spécialement à un address), mais si on veut l'utiliser, on dois utiliser les hardware spéciale: ApiMote v4beta (and v3), Texas Instruments CC2530/1 EMK, MoteIV Tmote Sky, TelosB mode ou Atmel RZ RAVEN USB Stick. Mais je n'ai pas des hardware, donc j'ai essayer à implémenter killerbee à Xbee, mais j'ai échoué, le plus grand problème est que xbee ne peut que récupérer les message spécialement à un address, donc il ne peut pas 'sniffer'. Et j'ai demandé à professeur un hardware qui peut implémenter killerbee.

Le github de killerbee: [3]

Semaine 6

J'ai pris un telosb de Professeur Vantroys. et j'ai écrit deux scénario de python à mesurer le RSSI et sniffer les message. la source est suivante:

  • pour fonctionner on doit utiliser les packets de killerbee: GoodFETCCSPI.py, GoodFET.py et dev_telosb.py, mais j'ai changé quelque chose de dev_telosb.py pour faciliter à actualiser quelques fonction.
  • Le protocol de message de telosb est different que dont xbee, et j'ai écrit un classe parser_trame pour l'analyse syntaxique.

dev_telosb.py:

Support for the TelosB / Tmote Sky platforms, and close clones.

Utilizes the GoodFET firmware with CCSPI application, and the GoodFET client code.

import os import time import struct import time from datetime import datetime, timedelta from kbutils import KBCapabilities, makeFCS from GoodFETCCSPI import GoodFETCCSPI

CC2420_REG_SYNC = 0x14

class TELOSB:

   def __init__(self, dev):
       
       Instantiates the KillerBee class for our TelosB/TmoteSky running GoodFET firmware.
       @type dev:   String
       @param dev:  Serial device identifier (ex /dev/ttyUSB0)
       @return: None
       @rtype: None
       
       self._channel = None
       self.handle = None
       self.dev = dev
       os.environ["board"] = "telosb" #set enviroment variable for GoodFET code to use
       self.handle = GoodFETCCSPI()
       self.handle.serInit(port=self.dev)
       self.handle.setup()
       self.__stream_open = False
       self.capabilities = KBCapabilities()
       self.__set_capabilities()
   def close(self):
       self.handle.serClose()
       self.handle = None
   def check_capability(self, capab):
       return self.capabilities.check(capab)
   def get_capabilities(self):
       return self.capabilities.getlist()
   def __set_capabilities(self):
       
       Sets the capability information appropriate for GoodFETCCSPI client and firmware.
       @rtype: None
       @return: None
       
       self.capabilities.setcapab(KBCapabilities.FREQ_2400, True)
       self.capabilities.setcapab(KBCapabilities.SNIFF, True)
       self.capabilities.setcapab(KBCapabilities.SETCHAN, True)
       self.capabilities.setcapab(KBCapabilities.INJECT, True)
       self.capabilities.setcapab(KBCapabilities.PHYJAM_REFLEX, True)
       self.capabilities.setcapab(KBCapabilities.SET_SYNC, True)
       return
   def get_rssi(self):
       return  self.handle.RF_getrssi()


   # KillerBee expects the driver to implement this function
   #def get_dev_info(self, dev, bus):
   def get_dev_info(self):
       
       Returns device information in a list identifying the device.
       @rtype: List
       @return: List of 3 strings identifying device.
       
       return [self.dev, "TelosB/Tmote", ""]
   # KillerBee expects the driver to implement this function
   def sniffer_on(self, channel=None):
       
       Turns the sniffer on such that pnext() will start returning observed
       data.  Will set the command mode to Air Capture if it is not already
       set.
       @type channel: Integer
       @param channel: Sets the channel, optional
       @rtype: None
       
       self.capabilities.require(KBCapabilities.SNIFF)
       self.handle.RF_promiscuity(1);
       self.handle.RF_autocrc(0);
       if channel != None:
           self.set_channel(channel)
       self.handle.CC_RFST_RX();
       print "Sniffer started (listening as %010x on %i MHz)" % (self.handle.RF_getsmac(), self.handle.RF_getfreq()/10**6);
       self.__stream_open = True
   # KillerBee expects the driver to implement this function
   def sniffer_off(self):
       
       Turns the sniffer off, freeing the hardware for other functions.  It is
       not necessary to call this function before closing the interface with
       close().
       @rtype: None
       
       #TODO actually have firmware stop sending us packets!
       self.__stream_open = False
   # KillerBee expects the driver to implement this function
   def set_channel(self, channel):
       
       Sets the radio interface to the specifid channel (limited to 2.4 GHz channels 11-26)
       @type channel: Integer
       @param channel: Sets the channel, optional
       @rtype: None
       
       self.capabilities.require(KBCapabilities.SETCHAN)
       if channel >= 11 or channel <= 26:
           self._channel = channel
           self.handle.RF_setchan(channel)
       else:
           raise Exception('Invalid channel')
   def get_channel(self):
       return self._channel
   def get_handle(self):
       return self.handle
   # KillerBee expects the driver to implement this function
   def inject(self, packet, channel=None, count=1, delay=0):
       
       Injects the specified packet contents.
       @type packet: String
       @param packet: Packet contents to transmit, without FCS.
       @type channel: Integer
       @param channel: Sets the channel, optional
       @type count: Integer
       @param count: Transmits a specified number of frames, def=1
       @type delay: Float
       @param delay: Delay between each frame, def=1
       @rtype: None
       
       self.capabilities.require(KBCapabilities.INJECT)
       if len(packet) < 1:
           raise Exception('Empty packet')
       if len(packet) > 125:                   # 127 - 2 to accommodate FCS
           raise Exception('Packet too long')
       if channel != None:
           self.set_channel(channel)
       self.handle.RF_autocrc(1)               #let radio add the CRC
       for pnum in range(0, count):
           gfready = [ord(x) for x in packet]  #convert packet string to GoodFET expected integer format
           gfready.insert(0, len(gfready)+2)   #add a length that leaves room for CRC
           self.handle.RF_txpacket(gfready)
           # Sleep was for 1 second but testing by Gianfranco Costamagna suggested lowering to 1/100th of a second
           time.sleep(0.01)                    #TODO get rid of completely, and just check CC2420 status
           # https://github.com/alvarop/msp430-cc2500/blob/master/lib/cc2500/cc2500.c
   def get_package(self,timeout=0.1):
       packet = None;
       start = time.time()
       while (packet is None and (time.time() - start < timeout)):
           packet = self.handle.RF_rxpacket()
       return packet
   # KillerBee expects the driver to implement this function
   def pnext(self, timeout=1000):
       
       Returns a dictionary containing packet data, else None.
       @type timeout: Integer
       @param timeout: Timeout to wait for packet reception in usec
       @rtype: List
       @return: Returns None is timeout expires and no packet received.  When a packet is received, a dictionary is returned with the keys bytes (string of packet bytes), validcrc (boolean if a vaid CRC), rssi (unscaled RSSI), and location (may be set to None). For backwards compatibility, keys for 0,1,2 are provided such that it can be treated as if a list is returned, in the form [ String: packet contents | Bool: Valid CRC | Int: Unscaled RSSI ]
       
       if self.__stream_open == False:
           self.sniffer_on() #start sniffing
       packet = None;
       start = datetime.utcnow()
       while (packet is None and (start + timedelta(microseconds=timeout) > datetime.utcnow())):
           packet = self.handle.RF_rxpacket()
           rssi = self.handle.RF_getrssi() #TODO calibrate
       if packet is None:
           return None
       frame = packet[1:]
       if frame[-2:] == makeFCS(frame[:-2]): validcrc = True
       else: validcrc = False
       #Return in a nicer dictionary format, so we don't have to reference by number indicies.
       #Note that 0,1,2 indicies inserted twice for backwards compatibility.
       result = {0:frame, 1:validcrc, 2:rssi, 'bytes':frame, 'validcrc':validcrc, 'rssi':rssi, 'location':None,'packet':packet}
       result['dbm'] = rssi - 45 #TODO tune specifically to the Tmote platform (does ext antenna need to different?)
       result['datetime'] = datetime.utcnow()
       return result
   def test_rssi(self, timeout=1000):
       
       Returns a dictionary containing packet data, else None.
       @type timeout: Integer
       @param timeout: Timeout to wait for packet reception in usec
       @rtype: List
       @return: Returns None is timeout expires and no packet received.  When a packet is received, a dictionary is returned with the keys bytes (string of packet bytes), validcrc (boolean if a vaid CRC), rssi (unscaled RSSI), and location (may be set to None). For backwards compatibility, keys for 0,1,2 are provided such that it can be treated as if a list is returned, in the form [ String: packet contents | Bool: Valid CRC | Int: Unscaled RSSI ]
       
       if self.__stream_open == False:
           self.sniffer_on() #start sniffing
       packet = None;
       start = datetime.utcnow()
       while (packet is None and (start + timedelta(microseconds=timeout) > datetime.utcnow())):
           packet = self.handle.RF_rxpacket()
           rssi = self.handle.RF_getrssi() #TODO calibrate
       return rssi
   def ping(self, da, panid, sa, channel=None):
       
       Not yet implemented.
       @return: None
       @rtype: None
       
       raise Exception('Not yet implemented')
   def jammer_on(self, channel=None):
       
       Not yet implemented.
       @type channel: Integer
       @param channel: Sets the channel, optional
       @rtype: None
       
       self.capabilities.require(KBCapabilities.PHYJAM_REFLEX)
       self.handle.RF_promiscuity(1)
       self.handle.RF_autocrc(0)
       if channel != None:
           self.set_channel(channel)
       self.handle.CC_RFST_RX()
       self.handle.RF_reflexjam()
   def set_sync(self, sync=0xA70F):
       Set the register controlling the 802.15.4 PHY sync byte.
       self.capabilities.require(KBCapabilities.SET_SYNC)
       if (sync >> 16) > 0:
           raise Exception("Sync word (%x) must be 2-bytes or less." % sync)
       return self.handle.poke(CC2420_REG_SYNC, sync)
   def jammer_off(self, channel=None):
       
       Not yet implemented.
       @return: None
       @rtype: None
       
       #TODO implement
       raise Exception('Not yet implemented')


test_rssi.py(messurer rssi):

  1. -*- coding: utf-8 -*-

from dev_telosb import TELOSB import time

count = 0 telosb = TELOSB("/dev/ttyUSB0") telosb.set_channel(0x19) telosb.sniffer_on() start = time.time() for i in range(100000):

   print(telosb.test_rssi())
   while(time.time() - start < 1):
       pass
   start = time.time()
   #mes = telosb.pnext(1000)
   #if(mes != None):
   #    print(mes["dbm"])
   #else:
   #    print(telosb.get_handle().RF_getrssi())

telosb.close()


sniffer_test.py(sniffer les message):

  1. -*- coding: utf-8 -*-

from dev_telosb import TELOSB from dev_apimote import APIMOTE from zigbeedecode import ZigBeeNWKPacketParser from zigbeedecode import ZigBeeAPSPacketParser

import array

#################################################### #报文说明 #0x17 -> length (总字节数 - 1) #0x61 -> 报头引导 #0x88 -> 报头引导 #0xd -> frameID(不确定, 它随报文顺序,而增加) #0x34 -> PID(LOW) #0x12 -> PID(HIGH) #0x3 -> Addr16 of sender (LOW) #0x0 -> Addr16 of sender (HIGH) #0x1 -> Addr16 of receiver (LOW) #0x0 -> Addr16 of receiver (HIGH) #0xeb -> 计数器? #0x0 -> 计数器? #0x68 - #0x65 - #0x6c - #0x6c - #0x6f - > data #0x20 - #0x77 - #0x6f - #0x72 - #0x6c - #0xe7 -> checkSum(LOW) #0xa9 -> checkSum(HIGH) ####################################################

DEVICE = "/dev/ttyUSB0"

class parser_trame:

   def __init__(self, packet=None):
       if packet is None:
           self.mes = None
           return
       mes = array.array('B', packet['packet'])
       self.mes = mes
   def get_message(self, mes):
       mes = array.array('B', mes['packet'])
       self.mes = mes
   def get_len(self):
       if self.mes is not None:
           return self.mes[0]
   def get_frameID(self):
       if self.mes is not None:
           return self.mes[3]
   def get_PINID_LOW(self):
       if self.mes is not None:
           return self.mes[4]
   def get_PINID_HIGH(self):
       if self.mes is not None:
           return self.mes[5]
   def get_addr16_sender_low(self):
       if self.mes is not None:
           return self.mes[6]
   def get_addr16_sender_high(self):
       if self.mes is not None:
           return self.mes[7]
   def get_addr16_receiver_low(self):
       if self.mes is not None:
           return self.mes[8]
   def get_addr16_receiver_high(self):
       if self.mes is not None:
           return self.mes[9]
   def get_data(self):
       if self.mes is not None:
           return self.mes[12:-2]


def main():

   telosb = TELOSB(DEVICE)
   telosb.sniffer_on(0x19)
   nwk = ZigBeeNWKPacketParser()
   aps = ZigBeeAPSPacketParser()
   parser = parser_trame()
   while(True):
       mes = telosb.pnext()
       if(mes != None):
           print('----------------------------------------')
           parser.get_message(mes)
           print(parser.get_data())
           for i in parser.get_data():
               print('%#x'%i)
               print('%c'%i)

if __name__ == "__main__":

   main()

Semaine 7

J'ai écrit les programmation à mesurer la puissance du channel et compter le nombre moyen de message, et les fonctions à détecter les attaque de Dos et 'Replay Attack'.

Source:

  1. -*- coding: utf-8 -*-


from dev_telosb import TELOSB from dev_apimote import APIMOTE from zigbeedecode import ZigBeeNWKPacketParser from zigbeedecode import ZigBeeAPSPacketParser import sys import argparse import time import math import threading import array

#################################################### #报文说明 #0x17 -> length (总字节数 - 1) #0x61 -> 报头引导 #0x88 -> 报头引导 #0xd -> frameID(不确定, 它随报文顺序,而增加) #0x34 -> PID(LOW) #0x12 -> PID(HIGH) #0x3 -> Addr16 of sender (LOW) #0x0 -> Addr16 of sender (HIGH) #0x1 -> Addr16 of receiver (LOW) #0x0 -> Addr16 of receiver (HIGH) #0xeb -> 计数器? #0x0 -> 计数器? #0x68 |- #0x65 |- #0x6c |- #0x6c |- #0x6f |- -> data #0x20 |- #0x77 |- #0x6f |- #0x72 |- #0x6c |- #0xe7 -> checkSum(LOW) #0xa9 -> checkSum(HIGH) ####################################################

DEVICE = "/dev/ttyUSB1" CHANNEL = 0x19

class parser_trame:

   def __init__(self, mes=None):
       if mes is None:
           self.mes = None
           return
       mes = array.array('B', packet)
       self.mes = mes
   def get_message(self, mes):
       if(mes is None):
           self.mes = None
       else:
           mes = array.array('B', mes)
           self.mes = mes
   def get_len(self):
       if self.mes is not None:
           return self.mes[0]
   def get_data_len(self):
       return self.get_len() - 13
   def get_frameID(self):
       if self.mes is not None:
           return self.mes[3]
   def get_PINID_LOW(self):
       if self.mes is not None:
           return self.mes[4]
   def get_PINID_HIGH(self):
       if self.mes is not None:
           return self.mes[5]
   def get_addr16_sender_low(self):
       if self.mes is not None:
           return self.mes[6]
   def get_addr16_sender_high(self):
       if self.mes is not None:
           return self.mes[7]
   def get_addr16_receiver_low(self):
       if self.mes is not None:
           return self.mes[8]
   def get_addr16_receiver_high(self):
       if self.mes is not None:
           return self.mes[9]
   def get_data(self):
       if self.mes is not None:
           return self.mes[12:-2]


class PROTECTER:

   def __init__(self, device, channel):
       self.telosb = TELOSB(device)
       self.parser = parser_trame()
       self.channel = channel
       self.telosb.set_channel(channel)
       self.messages = {}
   def get_handle(self):
       return self.telosb
   def sniffer_on(self,channel):
       self.telosb.sniffer_on(channel)
   def sniffer_off(self):
       self.telosb.sniffer_off()
   def open(self):
       self.telosb.open()
   def close(self):
       self.telosb.close()
   def set_channel(self, channel):
       self.telosb.set_channel(channel)
   def get_puissance(self):
       mes = self.telosb.pnext()
       if(mes is None):
           #return [False, self.telosb.get_handle().RF_getrssi() * -1]
           return None
       return [True, mes["dbm"] * -1]
   def get_package(self):
       return self.telosb.get_package()
   def get_data(self):
       self.parser.get_message(self.get_package())
       if self.parser is None:
           return None
       else:
           d = self.parser.get_data()
           return d
   def monitor_puissance(self, channel, puissance_threshold, interval_echantillonnage=1,  period=3600):
       self.sniffer_on(channel)
       counter = 0
       counter_valide = 0
       puissance_sum = 0.0
       start = time.time()
       start_echantiilonage = time.time()
       while(True):
           if(time.time() - start > period):
               self.sniffer_off()
               return False
           if(puissance_sum != 0 and counter != 0):
               print(math.log(puissance_sum/counter))
               print(puissance_sum)
           if(time.time() - start_echantiilonage < interval_echantillonnage):
               #print(counter)
               #print(time.time())
               a = self.get_puissance()
               if(a):
                   puissance_sum += a[1]
               else:
                   puissance_sum += 80
                   counter += 1
               while(time.time() - start_echantiilonage <= interval_echantillonnage):
                   pass
           else:
               if(math.log(puissance_sum/(counter - counter_valide)) > puissance_threshold):
                   self.sniffer_off()
                   return True
               else:
                   counter = 0;
                   counter_valide = 0
                   puissance_sum = 0
                   start_echantiilonage = time.time()
   def mesure_average_puissance(self, channel, interval_echantillonnage = 1, period=3600, duree_de_pulse=15):
       self.sniffer_on(channel)
       puissance_sum = 0.0
       counter = 0
       counter_valide = 0 #le nombre de messages qu'on reussir à récuperer
       start = time.time()
       start_echantiilonage = time.time()
       #max_puissance_dbm = -256
       while(True):
           if(time.time() - start > period):
               break
           a = self.get_puissance()
           if(a):
               puissance_sum += a[1]
           else:
               puissance_sum += 80
               counter += 1
           while(time.time() - start_echantiilonage <= interval_echantillonnage):
               pass
           start_echantiilonage = time.time()
           
       self.sniffer_off()
       #return math.log(puissance_sum/(counter - counter_valide))
       return puissance_sum/counter
       #return max_puissance_dbm
   def mesure_average_num_of_message_par_second(self, channel, period):
       self.sniffer_on(channel)
       counter = 0.0
       start = time.time()
       while(True):
           if(self.telosb.pnext(10) is not None): #pnext(ms)
               counter += 1
           if(time.time() - start > period):
               break
       self.telosb.sniffer_off()
       return counter/period
   def monitor_num_of_message(self, channel, period, interval_echantillonnage, num_threshold):
       #num_threshold -> nombre_de_messages / interval_echantillonnage
       self.sniffer_on(channel)
       start = time.time()
       start_echantiilonage = time.time()
       counter = 0
       while(True):
           if(self.telosb.pnext() is not None):
               counter += 1
           if(time.time() - start >= period):
               self.sniffer_off()
               return False
           if(time.time() - start_echantiilonage > interval_echantillonnage):
               if(counter > 0):
                   if(counter/interval_echantillonnage > num_threshold):
                       self.telosb.sniffer_off()
                       return True
                   else:
                       counter = 0
                       start_echantiilonage = time.time()


   #period 检测的时间, time_danger: 当唱过time再收到相同数据, 收到攻击
   def detect_replay_attack(self, period, time_danger):
       #创建列表,用于保存,收到的数据以及时间戳的元组,
       start = time.time()
       datas = []
       #while
       while(True):
           mes = self.get_data()
           if mes is not None:
               m = hash(mes.tostring())
               print(m)
               for d in datas:
                   if(d[0] == m):
                       if(time.time() - d[1] > time_danger):
                           return True
               datas.append((m, time.time()))
               if(len(datas) > 0):
                   if(time.time() - datas[0][1] > time_danger):
                       del datas[0]
           if(time.time() - start > period):
               return False
       pass


def main():

   protecter = PROTECTER(DEVICE, CHANNEL)
   protecter.set_channel(0x19)
   protecter.sniffer_on(0x19)
   print(protecter.detect_replay_attack(100,10))
   print(protecter.mesure_average_num_of_message_par_second(0x19, 5))                                                            
   print(protecter.monitor_num_of_message(0x19,5,50,2.6))
   print(protecter.mesure_average_puissance(0x19, 3, 10))
   protecter.sniffer_off()
   protecter.close()

if __name__ == "__main__":

   main()

Documents Rendus