.*"~~~(     Petite introduction au sniffing    )~~~"*.
                                                ,                                                      ,
                                         =======+======================================================+=======
                                         [ medgi@kernelhacking.net - v1.0 (6Ko) - for CounterStrike Magazine ]
                                         ======================================================================




[ 1 ] Introduction
[ 2 ] Fonctionnement du réseau
        [ 2.1 ] Transfer Control Protocol (TCP)
        [ 2.2 ] Le niveau Ethernet
        [ 2.3 ] La transmission des données sur un LAN
[ 3 ] Sniffer un réseau Ethernet
        [ 3.1 ] Notions de sniffing
        [ 3.2 ] L'outil tcpdump
           [ 3.2.1 ] Notions de base
           [ 3.2.2 ] Format d'output
           [ 3.2.3 ] Les expressions de base
        [ 3.3 ] Filtrage avancé (filtres BPF)
[ 4 ] Programmer son sniffer avec la libpcap
        [ 4.1 ] Introduction a la libpcap
        [ 4.2 ] Explication du code
[ 5 ] Détecter un sniffer & se protéger
[ 6 ] Ressources
[ 7 ] Conclusion


[ A ] Annexe A : psyrus.c [ packet sniffer code ]





[ 1 ] Introduction :


Les sniffers font partis des outils les plus anciens du réseau. En effet, ils était à l'origine utilisées par les administrateurs 
d'un réseau pour surveiller le traffic qui y transitait. Cependant ces outils ont vite été utilisé par les hackers dans le même but,
mais à des fins différentes. Ainsi lorsque qu'un hacker réalise une intrusion, très souvent il placera un sniffer, pour lui aussi 
surveiller le réseau dont il vient d'obtenir l'acces.

Un sniffer est en fait un petit programme qui permet comme nous venons de le voir, "d'écouter" le traffic d'un réseau. Cela pourrait
être comparé aux autoritées d'un gouvernement qui mettent sur écoute le réseau téléphonique : ils peuvent ainsi savoir qui communique
avec qui, et même ce que deux personnes se disent. Bien que le terme sniffer soit aujourd'hui employé très fréquemment, il s'agit
à la base du nom d'un programme de l'entreprise 'Network Associates' ("Sniffer Network Analyzer"). 

Cet article n'as pas la prétention d'expliquer tout le fonctionnement du sniffing, et des différentes méthodes d'attaque que cela
entraine, et encore moins d'expliquer en détail le fonctionnement du réseau et son ensemble de protocoles, mais tout simplement de
vous expliquer au mieux le sniffing. Ainsi il existe sûrement d'autres aspects du sniffing qui ne seront pas traité ici, mais cet
article essaiera tout de même d'être le plus complet possible.

Ainsi nous expliquerons tout d'abord quelques notions de base sur le fonctionnement du réseau, qui vous seront nécéssaire à la bonne
compréhension de cet article, puis nous etudierons le sniffing à proprement parler (avec l'outil tcpdump). Nous verrons ensuite comment
programmer son propre sniffer, grâce à la libpcap. Enfin nous étudierons les différentes techniques d'attaques possibles basé sur
le sniff, ainsi que les moyens de s'en protéger.




[ 2 ] Fonctionnement du réseau :


Lorque deux stations échangent des données sur le réseu, celui ci fais appel à plusieurs protocoles. Il est nécessaire de bien comprendre
le fonctionnement de ces différents protocoles. Voici donc un court résumé qui vous aidera peut être. Pour plus d'informations vous pouvez
vous réferrer aux RFC suivant :


        * Transfer Control Potocol (TCP)        http://RFC.net/rfc793.html
        * Internet Protocol (IP)                http://RFC.net/rfc791.html
        * Adresse Resolution Protocol (ARP)     http://RFC.net/rfc826.html


Pour plus d'informations sur les différentes documentation sur le réseau qu'il serait utile de consulter, vous pouvez vous rendre à la
section ressource.


        [ 2.1 ] Transfer Control Protocol (TCP) :


        Le protocol TCP à comme but de récupérer les données et de les fragmenter en plusieures datagrammes pour faciliter leur
        transfert. Il doit aussi réassembler à l'arrivée les données qu'il à fragmenté ainsi que les remettre dans le bon ordre.
        Enfin il doit s'occuper de la réémission des données qui ont été perdues. Voici donc le schéma d'une en tête TCP, qui sera
        brievement commentée :


                        0   2   4   6   8   10  12  14  16  18  20  22  24  26  28  30  32
                        +-------------------------------+-------------------------------+
                        |         PORT SOURCE           |       PORT DESTINATION        |
                        +-------------------------------+-------------------------------+
                        |                       NUMERO DE SEQUENCE                      |
                        +---------------------------------------------------------------+
                        |                       ACCUSE DE RECEPTION                     |
                        +-------+-----------+-----------+-------------------------------+
                        | DATA  |           |U|A|P|R|S|F|                               |
                        |OFFSET |  RESERVE  |R|C|S|S|Y|I|            FENETRE            |
                        |       |           |G|K|H|T|N|N|                               |
                        +-------------------+-----------+-------------------------------+
                        |         CHECKSUM TCP          |   POINTEUR DONNEES URGENTES   |       
                        +-------------------------------+-------------------------------+
                        |           OPTIONS             |           PADDING             |
                        +-------------------------------+-------------------------------+
                        |                            DONNEES                            |
                        +---------------------------------------------------------------+


        * PORT SOURCE        :  Il s'agit du port TCP de l'emetteur. Chaque transfert TCP est effectué sur un port de votre machine.
        * PORT DESTINATION   :  C'est le port TCP du recepteur. De meme, un port est ouvert sur la machine cible.
        * NUMERO DE SEQUENCE :  A chaque octet envoyé est attribué un numéro de séquence. Ce numéro correspond au premier numéro de l'octet
                                envoyé (sauf si le flag SYN est marqué). Si le flag SYN est marqué, ce numéro correspond au numéro de
                                séquence initial (ISN), et le premier octet à pour numéro ISN+1.
        * ACCUSE DE RECEPTION:  Ce champ contient le numéro du prochain octet que le recepteur va recevoir. Il s'agit d'une vérification
                                pour les octets qui arrivent. 
        * DATA OFFSET        :  Donne la longueure de l'entete en nombre de mots de 32 bits.
        * RESERVE            :  Espace reservé pour un usage futur. Aucun intéret pour nous :)
        * LES FLAGS          :  URG -> Flag pour les données urgentes. Vaut 1 s'il est activé.
                                ACK -> Accusé de reception. Vaut 1 si celui ci est correct, mais peu prendre d'autres valeures.
                                PSH -> Flag pour la fonction PUSH.
                                RST -> Réinitialisation de la connexion.
                                SYN -> Synchronisation des numéros de séquence (utilisé pour une connexion). Exemples :
                                         SYN = 1 & ACK = 0 correspond à une demande de connexion
                                         SYN = 1 & ACK = 1 correspond à une confirmation de connexion
                                FIN -> Fin de transmission.
        * FENETRE            :  Nombre d'octets que le recepteur est capable de recevoir.
        * CHECKSUM TCP       :  Opération de controle servant à vérifier qu'aucun datagramme TCP n'as été perdu pendant le transfert des
                                données.
        * POINTEUR DONNEE URG:  Indique la position d'une donnée urgente (si le flag URG est marqué), en donnant son décalage par rapport
                                au numéro de séquence.
        * OPTIONS            :  Différentes options. Aucun intérêt pour nous :)
        * PADDING            :  les octets de cette zone termine l'entête TCP (bourrage).
        * DONNEES            :  Les données que votre machine désire transmettre à une machine distante.


        Il faut savoir qu'une connexion TCP s'effectue en trois étapes. Tout d'abord le client envoie une premiere trame au serveur,
        dans laquelle le flag SYN vaut 1 et les autres flags valent 0. Ensuite le serveur envoie une trame de confirmation au client,
        dans laquelle le flag ACK vaut maintenant 1, et le flag SYN vaut toujours 1. Enfin le client établit la connexion en envoyant
        lui aussi une confirmation : SYN=0 et ACK=1. Ainsi une connexion TCP peut se résumer à ce petit schéma :


                CLIENT  (SYN=1 & ACK=0) --> SERVEUR
                SERVEUR (SYN=1 & ACK=1) --> CLIENT
                CLIENT  (SYN=0 & ACK=1) --> SERVEUR
                /* connexion établie ... */


        Je pense que ce petit résumé suffira pour mieux comprendre les raisonnements expliqués plus loin. Pour plus d'information
        lisez le RFC correspondant (Transfer Control Protocol : http://RFC.net/rfc793.html).




        [ 2.2 ] Le niveau Ethernet :


        Un reseau local, contrairement à ce que l'on pourrait penser n'est pas forcément un réseau où toutes les machines sont
        PHYSIQUEMENT reliées entre elles. En effet le terme 'réseau local' désigne un réseau qui partage le meme brin Ethernet
        (c'est par exemple le cas des réseaux cablés). Il faut savoir qu'il existe d'autres types de réseau local tel que le
        'Token Ring' ou le 'FDDI', que nous n'aborderons pas dans cet article. Les réseaux locaux (LAN) utilisant Ethernet, 
        utilisent un type d'adréssage spécifique : l'adressage MAC (Media Access Control).

        Le principe est simple : sur un réseau de type Ethernet, tout les ordinateurs sont connecté sur le même brin, et donc
        les données qui transitent sur le réseau passent par toutes les machines. Ainsi pour des raisons logique, les données ne
        doivent être vues que par la machine à qui elle sont destinées. C'est là qu'intervient l'adressage MAC.

        En effet chaque machine du réseau possède une adresse MAC spécifique qui est inscrite dans sa carte réseau. Cette adresse
        est fixé par le constructeur de la carte. Elle est UNIQUE et ne peut être modifiée. L'adresse MAC est un nombre de 48
        bits : les 24 premiers bits servent à identifier le vendeur de la carte, tandis que les 24 derniers bits sont un numéro
        de série assigné par le revendeur. Ce numéro de série s'appelle le OUI (Organizationally Unique Identifier), et il
        garantit que deux cartes réseau Ethernet ne n'ont pas la meme adresse MAC. 

        Pour trouver votre adresse MAC rien de plus simple. Tapez dans un xterm la ligne 'ifconfig eth0' (eth0 désignant le
        périphérique correspondant à votre carte réseau) :


                [root@subkulture medgi]# ifconfig eth0
                eth0      Lien encap:Ethernet  HWaddr 08:00:17:0A:36:3E
                          inet adr:xxx.xx.xx.xx  Bcast:xxx.xx.xx.xxx  Masque:xxx.xxx.xxx.x
                          UP BROADCAST RUNNING MULTICAST  MTU:1500 Metric:1
                          Paquets Reçus:33285 erreurs:0 jetés:0 débordements:0 trames:0
                          Paquets transmis:41950 erreurs:0 jetés:0 débordements:0 carrier:0
                          collisions:0 lg file transmission:100
                          Interruption:11 Adresse de base:0xcc00

                [root@subkulture medgi]#


        J'ai masqué ici les adresse IP correspondant à mon réseau par des 'xxx.xxx.xxx.xx' (aucun intéret de vous les montrer alors
        pourquoi les laisser :). L'adresse MAC correspond au champ intitulé 'HWaddr', à savoir : "08:00:17:0A:36:3E". Elle est
        introduite dans l'entete Ethernet. Voici un schéma représentant cette entete : 


                 0   2   4   6   8   10  12  14  16  18  20  22  24 26  28  30  32
                 +-------------------------------+-------------------------------+
                 |      Addresse Ethernet de Destination (32 premiers bits)      |
                 +-------------------------------+-------------------------------+
                 |    AED* (16 derniers bits)    |    AES* (16 premiers bits)    |
                 +-------------------------------+-------------------------------+
                 |          Adresse Ethernet Source (32 derniers bits)           |
                 +---------------------------------------------------------------+
                 |                                                               |
                 |    #                                                     #    |
                 |    # Entete IP, puis entete TCP, et enfin vos données... #    |
                 |    #                                                     #    |
                 |    #                 fin de vos données                  #    |
                 |    #                                                     #    |
                 |                                                               |
                 +---------------------------------------------------------------+
                 |                       CHECKSUM ETHERNET                       |
                 +---------------------------------------------------------------+


        Quelques petites explications. AED signifie 'Adresse Ethernet de Destination' et AES 'Adresse Ethernet Source' (j'ai abrégé
        pour une question de place dans le schéma :). Ces adresses Ethernet sont en fait les adresses MAC. Nous avons vu plus haut
        qu'une adresse MAC avait une taille de 48bits, or la taille d'une entête est de 32bits. Ainsi les adresses MAC doivent être
        découpé pour rentrer dans l'entête : nous avons donc deux champs de 32bits et deux champs de 16 bits :


                Adresse Ethernet de Destination = 32 + 16 = 48 bits ------+
                                                                          |----> Les Adresses MAC font bien 48 bits.
                Adresse Ethernet Source         = 32 + 16 = 48 bits  -----+


        Dans cette entete Ethernet se trouve l'entete IP. Celle ci sers à 'guider' les datagrammes TCP à travers le réseau, en 
        fournissant les informations nécéssaires aux routeurs. L'entete IP encapsule l'entete TCP, mais n'intervient pas sur cette
        derniere. Pour plus d'informations, veuiller consulter les RFC correspondants ou encore lire un livre sur le fonctionnement
        des protocoles TCP/IP.

        A la fin de l'entete Ethernet se trouve le checksum qui comme dans les autres entete, sers à vérifier l'intégrité des données
        qui ont été transmises. Maintenant que vous comprennez les bases de fonctionnement d'Ethernet, nous allons pouvoir utiliser
        un petit exemple expliquant la transmission des données.




        [ 2.3 ] La transmission des données sur un LAN :


        Nous allons maintenant expliquer comment fonctionne la transmission des données sur un LAN. Par exemple, imaginons
        que l'host X, ne faisant pas partit du LAN, désire envoyer des données à l'host E. Voici les étapes de la transmission :

        Tout d'abord les données sont fragmentées en plusieurs datagrammes grâce à TCP. Ces datagrammes comporte un header TCP
        comme nous l'avons vu plus haut. Il sont ensuite transmis à IP qui rajoute un header IP (contenant l'adresse IP source
        ainsi que l'adresse IP de destination). Enfin, Ethernet rajoute son header sur le datagramme obtenu. Nous obtenons
        donc un packet de la forme (en résumé) :


                +---    HEADER ETHERNET + HEADER IP + HEADER TCP +  DONNEES + CHECKSUM ETHERNET    ---+


        Ces packet transitent donc sur le réseau. Cependant il est évident qu'il leur faut arriver sur la bonne machine. C'est la
        qu'intervient le protocole ARP. Bien que ce n'est pas la seule fonctionalitée de ce protocole, ARP permet de faire la
        relation entres les adresse MAC et les adresses IP, et donc c'est grâce à ARP que le packet sera routé correctement
        vers la bonne machine.

        Ainsi notre packet arrive sur le réseau local. Nous avons par exemple 8 machines différentes :


                  A  --------->  10.0.0.1 (routeur)             E  ----------> 10.0.0.5 (machine)
                  B  --------->  10.0.0.2 (machine)             F  ----------> 10.0.0.6 (machine)
                  C  --------->  10.0.0.3 (machine)             G  ----------> 10.0.0.7 (machine)
                  D  --------->  10.0.0.4 (machine)             H  ----------> 10.0.0.8 (machine)


        Les données envoyées par 'X' arrivent au routeur 'A' utilise alors ARP pour déterminer à quelle machine le packet est destiné.
        Pour ce faire il fera une requete en broadcast pour déterminer qui possède l'IP (10.0.0.5). Cette IP appartient à la machine
        'E', et donc pour spécifier au routeur que c'est bien son IP, 'E' enverra au routeur son adresse MAC. Le routeur déterminera
        alors quels packets il devra transmettre à 'E' en comparant l'adresse MAC de 'E' avec les adresses MAC contenues dans les
        entetes Ethernet.

        C'est maintenant que vous allez comprendre le rapport entre tout ça et le sniffing (enfin !) : les packets vont donc etre
        transférés du routeur jusqu'à 'E'. Pour ce faire ils vont transiter sur chaque machine, qui ananlysera l'adresse MAC contenu
        dans les header Ethernet du packet, avec l'adresse MAC contenu sur la carte réseau. Comme les packets ne leur seront pas
        destinés, il seront redirigés vers la machine suivante, jusquà qu'ils arrivent à 'E'.



[ 3 ] Sniffer un réseau Ethernet :


Maintenant que nous avons vu la partie 'théorique', vous devez être en mesure de comprendre avec plus de facilitée comment fonctionne
un sniffer, et l'intérêt qu'un tel outil présente, autant dans le but de surveiller son réseau, que d'attaquer un réseau. Voici donc
quelques notions utilies sur le sniffing, qui seront mises en pratique plus loin grâce à l'outil 'tcpdump'.


        [ 3.1 ] Notions de sniffing :


        Comme nous l'avons vaguement expliqué en introduction, le sniffing permet de surveiller le traffic d'un réseau. Cependant
        par défaut il n'est possible que de sniffer que les packets dont l'adresse fournit dans l'entete Ethernet correspond à
        votre adresse MAC, ou plus clairement que les packets qui vous sont destiné. Dans ce cas la le sniffing ne présente aucun
        intérêt, tant pour l'administrateur systeme, que pour le hackers. En effet par défaut, les packets qui ne sont pas destinés
        à votre machine sont tout simplement ignorés.

        Ainsi pour pouvoir sniffer tout les packets qui transitent par votre carte réseau, celle ci doit avoir le mode promiscious
        d'activé. Ce mode permet d'accepter tous les packets, même ceux qui ne sont pas destinés à votre carte réseau. Vous pouvez
        activer le mode promiscious en console grace à la commande ifconfig (man ifconfig). Lorsque vous utilisez un sniffer, celui
        ci mets automatiquement la carte en mode promiscious.

        Il faut savoir aussi que le sniffing ne peut se faire que sur des machines reliées sur le même brin Ethernet. En effet comme
        nous l'avons vu plus haut, les packets traversent le sous réseau et passe par chaque carte réseau. Il est ainsi logique que
        si le sniffer est basé sur une machine qui n'as rien à voir avec le réseau, il n'est pas possible de sniffer ce même réseau.
        UNe comparaison simpliste pourrait être la suivante :


        Deux personnes échange une conversation téléphonique en Europe. Le phreaker désire mettre sur écoute un des deux téléphones,
        cependant il est situé au Japon. Il lui est donc impossible d'écouter ce que disent les deux personnes, car pour cela, il
        faudrait qu'il manipule une partie du réseau téléphonique européen. Il en va de même pour le sniffing : pour sniffer un
        échange de données entre deux machine, il faut que ces données transitent par une machine sur laquelle est basée un sniffer,
        c'est à dire que le sniffer est basé sur un (voir le même) réseau Ethernet que l'une des deux machines utilise.

        En effet, si les deux machines qui communiquent ne sont pas basées sur le même réseau Ethernet, cela ne pose pas de problème,
        puisque le sniffer aura la possibilité d'être basé sur l'un des deux réseaux. Cependant comme nous venons de le voir, cela
        NE PEUT marcher si le sniffer n'est situé sur aucun des deux LAN.


        Dans les parties suivantes nous allons détailler des méthodes de sniffing pour les réseaux cables & xDSL. Il faut savoir
        qu'il est tout aussi possible de sniffer sur un réseau utilisant une connexion ppp (point-per-point). Seulement nous
        n'expliquerons pas les variations avec un réseau cablé, pour deux raisons : tout d'abord parce que les connexions ppp se
        font de plus en plus rares, et surtout car les variations ne sont que très minimes. 

        Nous allons maintenant pouvoir passer à la pratique, gràce à l'outil tcpdump :). 


        [ 3.2 ] L'outil tcpdump :


           [ 3.2.1 ] Notions de base :


           Tcpdump est l'un des sniffer les plus connus et aussi des plus réputés. La version actuelle (TCPDUMP version 3.6.2) utilise
           la libpcap, une librairie comportant de nombreuse fonctions facilitant le sniffing. Tous deux sont disponibles sur le site
           officiel : http://www.tcpdump.org. Pour comprendre les paragraphes suivant, vous devez avoir TCPDUMP d'installé sur votre
           distribution. Si ce n'est pas déja fait, aller le chercher maintenant :).

           Avant de rentrer plus dans les détails, nous allons tout d'abord tester tcpdump d'une façon basique, pour satisfaire votre
           curiosité, et enfin voir quels sont les output d'un sniffer (vous devez être root pour le lancer, étant donné qu'un sniffer
           utilise les socks raw).


                   [root@subkulture medgi]# tcpdump
                   tcpdump: listening on eth0
                   01:55:25.976002 subkulture.b0x.33126 > dns1.isp.fr.domain:  30309+[|domain] (DF)
                   01:55:26.056002 dns1.isp.fr.domain > subkulture.b0x.33126:  30309[|domain]
                   01:55:26.056002 subkulture.b0x.33126 > dns1.isp.fr.domain:  30310+[|domain] (DF)

                   ^C

                   3 packets received by filter
                   0 packets dropped by kernel
                   [root@subkulture medgi]#


           Ainsi lorsque nous ne spécifions aucun argument, TCPDUMP se contente de nous montrer les transferts de données effectués
           entre notre machine et le serveur distant (ici le routeur). J'ai une fois de plus modifié mon adresse IP ainsi que celle
           du routeur, car une fois de plus vous n'avez pas besoin de les connaitre pour comprendre cet article.

           On voit dans ce court example qu'il y a communication entre l'hote 'subkulture.b0x' et 'dns1.isp.fr'. La communication
           utilise le port 33126 (TCP) pour la machine 'subkulture.b0x', et le port réservé 'domain' pour 'dns1.isp.fr'.

           Nous allons avant de poursuivre plus en détail, éxaminer les options les plus courantes de tcpdump. La partie qui suit
           est largement inspiré du man page, avec quelques explications en plus.

                +---------------------- OPTIONS DE TCPDUMP :

                -i [interface]          Permet de spécifier l'interface réseau à utiliser. Tcpdump est capable de choisir automatiquement 
                                        l'interface à sniffer, cependant il est possible d'en posséder plusieurs. Nous pouvons donc choisir
                                        entre toutes ces interfaces. Exemple :

                                        [root@subkulture medgi]# tcpdump -i eth0
                                        tcpdump: listening on eth0

                                        (...)

                -c [X]                  Quitte apres avoir recu X packets.

                -l                      Permet de stocker les output dans un buffer. De ce fait il est alors possible d'afficher le
                                        résultat du sniff et en même temps le stocker dans un fichier. Exemple :
                                        
                                        [root@subkulture medgi]# tcpdump -i eth0 -l | tee [file]
                                        tcpdump: listening on eth0

                                        (...)

                -n                      Permet de ne pas convertir les adresses et les ports. Exemple d'output avec l'option -n :

                                        01:29:54.646002 195.87.28.5.46136 > 194.117.194.120.6667: . ack 84 win 62780 (DF)

                -p                      Desactive le mode 'promiscious' activé par défaut avec tcpdump. Permet ainsi de ne voir que les
                                        données que nous émettons/recevons, et non pas  les packets qui transitent par notre interface
                                        réseau. 

                -s [byte_length]        Permet de ne sniffer que le nombre de byte spécifié. Ainsi si l'on spécifie la valeure 32, seule
                                        le header Ethernet sera sniffé. TCPDUMP rajoute en fin de ligne [|protocole] qui indique à quel
                                        endroit ont été splitté les données (ie: [|ether]). Si l'on spécifie comme valeure '0', la
                                        totalitée du packet sera capturée. 

                -t                      Permet de ne pas afficher le 'timestamp'. Ceci facilite la lecture, car sauf exception, le
                                        timestamp encombre l'affichage sans intérêt. 

                -w [fichier]            Sauvegarde le sniff dans le fichier que vous spécifiez. Utile lorsque l'on désire analyser les
                                        résultat plus tard et ne pas encombrer l'affichage. 

                -X                      Affiche les packets en hexadecimal, mais aussi en ascii. Cela permet de voir le contenu des
                                        packet dans un format à peu pres lisible (-x n'affiche que l'hexadécimal).

                +---------------------+


           Les options qui viennent d'être énumérées ne sont pas TOUTES les options de tcpdump, mais seulement les options les plus
           utiles. Nous allons maintenant étudier le format d'output de TCPDUMP, que vous devez comprendre si vous voulez tirer un
           quelcquonque intérêt d'un résultat de sniffing. 



           [ 3.2.2 ] Format d'output de TCPDUMP :


           Le format d'output de TCPDUMP dépend du protocole que l'on sniff. Dans notre article, nous ne parlons que du protocole
           TCP (le plus communément utilisé). Ainsi si vous voulez en savoir plus sur le format d'output des autres protocoles,
           consultez les manpages. Voici donc le format standard concernant le protocole TCP : 


                source > destination: flags numseq-data ack fenetre urgent options


                ***     Source et destination correspondent respectivement au adresses IP et port de la machine source et de
                        la machine cible. Par exemple nous pourrions avoir pour le champ source un output de ce genre :
                        195.87.25.63.46342 qui signifie que la machine source à pour adresse ip 195.87.25.63 et que le port qu'elle
                        utilise pour recevoir les données de la machine cible est le port 46342.

                ***     Flags indique les flags contenu dans le packet : S (SYN), F (FIN), P (PSH), R (RST) ou encore '.' si il n'y
                        a aucun flags de spécifié. Leur utilitée à été décrite plus haut.

                ***     Numseq-data indique le numéro de séquence initial et final du packet ainsi que ca taille en octet. Le format
                        est le suivant : ISN:SN(taille). Celui ci permet de suivre l'ordre des données. 

                ***     Ack spécifie le numéro d'acknowledgement du packet. Ce numéro, comme nous l'avons vu plus haut sers à vérifier
                        que le packet à été recu correctement. Il s'incrémente de 1 à chaque fois. 

                ***     Fenetre est une option de l'entete TCP, qui permet d'ajuster le flux au débit et à la mémoire disponible, et
                        ceci en indiquant la taille maximale supportée.

                ***     Urgent est aussi une option du header TCP, qui permet de spécifier un pointeur de données urgentes. Relire
                        le RFC 793 (TCP) pour plus de détails.

                ***     Le champ option permet de spécifier différentes options tel que les flags IP par exemple.


           Nous allons maintenant étudier une résultat de sniff par tcpdump, dans le but de vous faire comprendre plus clairement
           le format d'affichage :


                [root@subkulture medgi]# tcpdump -t
                tcpdump: listening on eth0
                medgi.isp.net.46136 > paris.fr.eu.undernet.org.ircd: P 1:47(46) ack 84 win 62780 (DF)
                paris.fr.eu.undernet.org.ircd > medgi.isp.net.46136: . ack 47 win 2874 (DF)

                ^C
                2 packets received by filter
                0 packets dropped by kernel
                [root@subkulture medgi]#


           Nous voyons ici que l'host medgi.isp.net utilise le port 46136 pour communiquer avec le serveur irc paris.fr.eu.undernet.org
           (port 6667). Celui ci insere le flag PUSH (P : PSH) dans le header TCP. Le numéro de sequence des données indique que le
           numéro de séquence initial (ISN) est 1, et que le numéro de séquence actuel (SN) est 47. La taille du packet est de 46 octets,
           comme indiqué entre parenthèses. Le numéro d'acknoledgement est 84 et la taille de la fenetre est 62780. Il y à la une option 
           (DF) qui correspond au flag IP Don't Fragment.

           Vous pouvez maintenant utiliser les différentes options de bases énumérées ci dessus dans le but de mieux connaître les
           différents format d'output possible. Selon moi, l'une des plus intéressante est l'option -X, car elle permet de voir dans
           un format à peu près lisible les données contenues dans les packets TCP :


                [root@subkulture medgi]# tcpdump -t -s 0 -X
                tcpdump: listening on eth0
                medgi.isp.net.46955 > paris.fr.eu.undernet.org.ircd: P 40:80(40) ack 1 win 62464 (DF)
                0x0000   4500 0050 5a50 4000 4006 3096 d45f 573e    E..PZP@.@.0.._W>
                0x0010   811b 0309 b76b 1a0b 65a1 7640 1749 6cd1    .....k..e.v@.Il.
                0x0020   5018 f400 1d3e 0000 5052 4956 4d53 4720    P....>..PRIVMSG.
                0x0030   2373 7562 6b75 6c74 7572 6520 3a73 6e69    #subkulture.:sni
                0x0040   6666 696e 6720 7230 306c 7a20 3a29 0d0a    ffing.r00lz.:)..

                (...)
                ^C

                12 packets received by filter
                0 packets dropped by kernel
                [root@subkulture medgi]#


           En analysant ce résultat on peu déduire qu'il y a une connexion TCP entre medgi.isp.net (port 46955) et paris.fr.eu.undernet.org
           (port 6667). L'host medgi.isp.net envoie un packet avec le flag PSH dont l'ISN est 40, le SN est 80 et la taille est de 40 octets.
           Le numéro d'acknowledgement est 1 et la taille de la fenêtre est 62464. En analysant la partie ascii, on peut en déduire que la 
           personne qui à envoyé ce packet vient d'envoyer un message sur IRC tel que celui ci : 


                [#subkulture] sniffing r00lz :)


           A moins que vous ne préferiez analyser l'hexadécimal, je vous suggère tout de même l'ascii, qui est nettement plus lisible :).
           Maintenant que vous connaissez les bases. Nous allons voir les options de filtrage avancé qu'offre tcpdump.



           [ 3.2.3 ] Les expressions :



           Nous allons étudier ici les expressions de TCPDUMP. Vous vous demander sûrement de quoi il s'agit, et bien c'est tout simple.
           En fait les expressions permettent de passer à tcpdump des arguments plus précis, c'est à dire de choisir les packets que
           nous allons lire. Une expression est constituée de une voire plusieures primitives. Une primitive est constituée d'un
           identifiant, suivie d'une valeure numérique ou alphanumérique. Voici donc les quatres types d'identifiant que vous aller
           pouvoir utiliser :


                TYPE : Peut être 'host', 'net' ou encore 'port'. Host est le type par défaut, et comme son nom l'indique il définit
                       un host :). Par exemple nous pouvons utiliser l'expression 'host medgi.isp.net' pour spécifier d'afficher que
                       les packets dont l'host est medgi.isp.net. De meme net correspond à network. Exemple : 'net 156.54' pour 
                       spécifier le network 156.54. Enfin port permet de spécifier un type de port spécial, comme par exemple le port
                       d'un httpd. Ainsi nous aurions l'expression 'port 80'.

                DIR  : Attributs possible : src, dst, src or dst, src and dst. Permets d'attribuer une règle concernant les packet à
                       filtrer. Vous pouvez ainsi pour l'host 'medgi.isp.net' choisir les packet suivants : 

                                * src medgi.isp.net        : Packet dont la source est medgi.isp.net.
                                * dst medgi.isp.net        : Packet dont la destination est medgi.isp.net.
                                * src or dst medgi.isp.net : Packet dont la source OU la destination est medgi.isp.net.
                                * src and dst isp.net      : Packet dont la source ET la destination est basé sur isp.net.

                       Vous pouvez bien entendu combiner ces primitives avec d'autre primitives que nous avons vu plus haut.

                PROTO: Permet de restreindre les packets à un certain protocole. Les protocols supportés sont ether (Ethernet),
                       fddi (alias d'Ethernet), tr (alias d'Ethernet), ip (Internet Protocol), ip6 (IPv6), arp (Address Resolution
                       Protocol), rarp, decnet, tcp (Transfert Control Protocol), udp. A ces primitives vous pouvez combiner des 
                       'link word' tel que || (or), && (and), ! (not). Voici une liste de primitives que vous pouvez utiliser. Cet
                       extrait n'est que la traduction du man page de TCPDUMP (avec des compléments en plus) :


                      /**************************           Debut de la traduction du man page de tcpdump **************************/

                      dst host [host]
                      True si le champ de destination du packet IPv4/IPv6 est [host], qui peut être soit une addresse IP, soit un
                      nom de domaine.

                      src host [host]
                      True si le champ source du packet IPv4/IPv6 est [host]. Meme principe que plus haut.

                      host [host]
                      True si le l'adresse IPv4/IPv6 source ou destination du packet correspond à [host]. Chaque expressions suivante de
                      l'host peuvent utilisée avec les mots clés 'ip, arp, rarp, or ip6' comme "ip host [host]" qui est équivalent à
                      "ether proto \ip and host [host]". SI [host] est un nom avec plusieures adresse IP, chaque adresse va être vérifiée.

                      ether dst [ehost]
                      True si l'adresse Ethernet de destination correspond à l'adresse [ehost]. [Ehost] peut être un nom tiré de /etc/ethers
                      ou encore un nombre (allez voir ethers(3N) pour les formats numériques). 

                      ether src [ehost]
                      True si l'adresse Ethernet source est [ehost]. 

                      ether host [ehost]
                      True si l'adresse Ethernet source ou destination correspond à [ehost].

                      gateway [host]
                      True si le packet utilise host comme une passerelle. Exemple : l'adresse Ethernet source (ou de destination) était
                      [host] mais ni l'adresse IP source ni l'adresse IP de destination n'était [host]. [Host] doit être un nom et doit
                      être trouvé dans /etc/hosts et /etc/ethers ( Une expression equivalente est "ether host [ehost] and not host [host]".
                      qui peut être utilisé à la fois avec des noms et des nombres pour [host] / [ehost]). Cette syntaxe ne marche pas avec
                      la configuration IPv6 activée pour le moment.

                      dst net [net]
                      True si le packet IPv4/IPv6 à dans son champ destination un numéro de réseau de [net]. Comme ce n'est pas très clair,
                      voici un petit exemple : 'dst net 128.6' sera juste si le champ destination du packet aura une adresse telle que
                      128.6.35.2. [Net] peut être à la fois un nom de /etc/networks ou une adresse réseau (allez voir networks(4) pour
                      plus de détails).

                      src net [net]
                      Meme raisonnement que plus haut, mais avec le champ source correspondant à [net], et non plus le champ destination.

                      net [net]
                      True si l'adresse source ou destination du packet IPv4/IPv6 à une adresse réseau correspondant à [net]. 

                      net [net] mask [mask]
                      True si l'adresse IP correspond à [net] avec le masque réseau spécifié ([mask]). Il est possible de rajouter src ou
                      dst pour lus de précision. NOTE : cette syntaxe n'est pas valide pour les réseau utilisant IPv6.

                      dst port [port]
                      True si le packet est un packet ip/tcp, ip/udp ou ip6/udp et a un port de destination de valeure [port]. Le [port]
                      peut être un nombre ou un nom utilisé dans /etc/services (voir tcp(4P) et udpo(4P)). Si un nom est utilisé, à la fois
                      le numéro de port et le protocole sont vérifiés. Si un nom ou un numéro ambigue est utilisé, seul le numéro de port est
                      vérifié (exemple: 'dst port 513' affichera à la fois le traffique de tcp/login et le traffique de udp/who, et le port
                      domaine affichera à la fois le traffique de tcp/domain et udp/domain).

                      src port [port]
                      True si le packet à la valeure de [port] comme port source.

                      port [port] 
                      True si le port source ou de destination correspond à [port]. Chacune des expressions vues plus haut peuvent être
                      utilisé avec les mots clés, tcp ou udp, comme dans : 'tcp src port [port]', qui affichera que les packets TCP dont
                      le port source est [port].

                      less [length]
                      True si le packet à une longueure inférieure ou égale à [length]. Ceci est équivalent à len <= [length].

                      greater [length]
                      True si le packet à une longueure supérieure ou égale à [length]. Ceci est équivalent à  len >= [length].

                      ip proto [protocol]
                      True si le packet est un packet IP (voir ip(4P)) avec le type de protocole [protocol]. Celui ci peut être un nombre
                      ou un des noms suivants : icmp, icmp6, igmp, igrp, pim, ah, esp, udp ou tcp. Remarquez que les identifiants tcp, udp
                      et icmp sont aussi des mots clés, et doivent ainsi être echappés par un backslash (\). 

                      ip6 proto [protocol]
                      True si le packet est un packet IPv6 de type de protocole [protocol].

                      ether broadcast
                      True si le packet est un packet Ethernet 'broadcast'. Le mots clés 'ether' est optionnel.

                      ip broadcast
                      True si le packet est un packet IP broadcast. Cela vérifie pour les conventions broadcast 'all-zeroes' et 'all-ones',
                      et vérifie le masque de sous réseau.

                      ether multicast
                      True si le packet est un packet Ethernet multicast. Le mot clé 'ether' est optionnel. Il s'agit d'une écriture
                      abrégée pour 'ether[0] & 1 != 0'.

                      ip multicast
                      True si le packet est un packet IP multicast. ip6 multicast True si le packet est un packet IPv6 multicast.

                      ip, ip6, arp, rarp, atalk, aarp, decnet, iso   
                      Abreviations pour ether proto [p], ou [p] est un des protocoles décrit plus haut. 

                      tcp, udp, icmp
                      Abréviations pour ip proto [p], où [p] correspond à l'un des protocoles listé plus haut.

                      iso proto [protocol]
                      True si le packet est un packet OSI de type [protocol]. [Protocol] peut être un nombre ou un des noms
                      suivant : cnlp, esis ou isis. 

                      clnp, esis, isis
                      Abréviation pour 'iso proto [p]', où [p] correspond à l'un des protocoles listés plus haut. Note: tcpdump
                      ne parse pas entierement ces protocoles.

                      (expr) [relop] (expr)
                      Permet de vérifier la relation entre deux expressions. [Relop] peut être l'un des comparateur suivant :
                      >, <, >=, <=, =, != et (expr) est une expression arithmétique composée de constantes entieres (exprimées
                      dans la syntaxe standard C), d'opérateurs bianaires normaux (+, -, *, /, &, |), d'un opérateur de longueure,
                      et un moyen d' acces spécial aux données du packet. Pour accéder aux donnée contenues dans le packet, utilisez
                      la syntaxe suivante :

                          proto [ expr : size ]

                     Proto est un des protocoles suivant : ether, fddi, tr, ip, arp, rarp, tcp, udp, icmp ou ip6, et indique la couche
                     du protocole pour les opérations de l'index. Remarquez que  tcp, udp et les autres types de protocoles de couche
                     supérieure ne s'applique qu'avec IPv4, et non pas IPv6. L'offset byte, relatif à la couche protocole indiquée est
                     donnée par (expr). La taille est optionnelle et indique le nombre de bytes dans le champ interessé; il peut être
                     un, deux, ou quatre, et par défaut un. L'opérateur de longueure, indiqué par le mot clé 'len', donne la longueure
                     du packet.

                     Par exemple, 'ether[0] & 1 !=0' sniff tout les traffic multicasts. L'expression 'ip[0] & 0xf !=5' sniff tout
                     les packets IP avec des option,s. L'expression 'ip[6:2] & 0x1fff = 0' sniff seulement les datagrammes qui ne
                     sont pas fragmenté et le fragment 0 des datagrammes fragmentés. 

                     Il faut savoir que tcp[0] signifie toujours le premier byte d'un header TCP, et jamais le premier byte d'un
                     fragment intervenant.


                /****************************           Fin de la traduction du man page de tcpdump  **************************/



        [ 3.3 ] Filtrage avancé (filtres BPF) :


        Les expressions que nous avons vu plus haut sont extraite du manpage de TCPDUMP. J'ai volontairement omis certaines de ces
        expressions, qui par exemple ne fonctionne que sur les systemes ULTRIX, car d'une part personne n'utilise ce type de système,
        et d'autre part, je ne suis même pas sur que ce type de système existe encore :) !

        Comme vous pouvez le constater, ces options permettent de sniffer les packets avec un tres grande précision, puisque nous
        pouvons utiliser des filtres. Ainsi voyons quelque exemples. Tout d'abord si nous voulons voir toutes les packets qui se
        connectent sur notre serveur HTTPD, puis analyser ces packets en temps réel, nous aurions alors ceci :


                [root@subkulture medgi]# tcpdump -s 0 -i eth0 -X dst port 80  && dst host medgi.httpd.server
                tcpdump: listening on eth0

                (...)
                0x0010   d45f 0706 0050 0d02 18b4 b513 7e38 6166   ._...P......~8af
                0x0020   5018 16d0 5ed8 0000 4854 5450 2f31 2e31   P...^...HTTP/1.1
                0x0030   2034 3034 204e 6f74 2046 6f75 6e64 0d0a   .404.Not.Found..
                0x0040   4461 7465 3a20 5468 752c 2032 3020 5365   Date:.Thu,.20.Se
                0x0050   7020 3230 3031 2031 383a 3431 3a30 3720   p.2001.18:41:07.
                0x0060   474d 540d 0a53 6572 7665 723a 2041 7061   GMT..Server:.Apa
                0x0070   6368 650d 0a43 6f6e 6e65 6374 696f 6e3a   che..Connection:
                0x0080   2063 6c6f 7365 0d0a 436f 6e74 656e 742d   .close..Content-
                0x0090   5479 7065 3a20 7465 7874 2f68 746d 6c3b   Type:.text/html;
                0x00a0   2063 6861 7273 6574 3d69 736f 2d38 3835   .charset=iso-885
                0x00b0   392d 310d 0a0d 0a3c 2144 4f43 5459 5045   9-1....<!DOCTYPE
                0x00c0   2048 544d 4c20 5055 424c 4943 2022 2d2f   .HTML.PUBLIC."-/
                0x00d0   2f49 4554 462f 2f44 5444 2048 544d 4c20   /IETF//DTD.HTML.
                0x00e0   322e 302f 2f45 4e22 3e0a 3c48 544d 4c3e   2.0//EN">.<HTML>
                0x00f0   3c48 4541 443e 0a3c 5449 544c 453e 3430   <HEAD>.<TITLE>40
                0x0100   3420 4e6f 7420 466f 756e 643c 2f54 4954   4.Not.Found</TIT
                0x0110   4c45 3e0a 3c2f 4845 4144 3e3c 424f 4459   LE>.</HEAD><BODY
                0x0120   3e0a 3c48 313e 4e6f 7420 466f 756e 643c   >.<H1>Not.Found<
                0x0130   2f48 313e 0a54 6865 2072 6571 7565 7374   /H1>.The.request
                0x0140   6564 2055 524c 202f 7363 7269 7074 732f   ed.URL./scripts/
                0x0150   2e2e 2532 662e 2e2f 7769 6e6e 742f 7379   ..%2f../winnt/sy
                0x0160   7374 656d 3332 2f63 6d64 2e65 7865 2077   stem32/cmd.exe.w
                0x0170   6173 206e 6f74 2066 6f75 6e64 206f 6e20   as.not.found.on.
                0x0180   7468 6973 2073 6572 7665 722e 3c50 3e0a   this.server.<P>.
                0x0190   3c2f 424f 4459 3e3c 2f48 544d 4c3e 0a     </BODY></HTML>.
                (...)


        Comme vous pouvez le constater, on peut clairement voire qu'une machine à tenter une requete telle que 
        "/scripts/..%2f../winnt/system32/cmd.exe", et qui n'as pas aboutit. Nous voyons donc ici le code HTML que renvoie Apache au
        client (erreur 404). Ainsi vous pouvez constater qu'un sniffer peut s'avérer très utile pour un administrateur puisqu'il permet
        de remarquer que son httpd est en train de subir un scan de failels CGI (*cmd.exe*). C'est d'ailleurs sur le sniffing de packet
        que sont basés les Network Intrusion Detection System (NIDS), dont nous étudierons le principe plus loin.

        Un autre filtrage qui peut s'avérer intéressant, est de repérer les FLAGS des trames TCP. Ainsi nous pouvons aisément déterminer
        les début de connexion (SYN), les fin de connexion (FIN), ou autres ... Voici les expressions correspondantes :


                SYN     --> 'dst port 80 and tcp[13] & 2 != 0'  : Permet de sniffer sur le port destination 80 (http) le treizieme octet
                             du header TCP. Le flag SYN est le deuxieme bit du treizieme octet (2 != 0 indique que le flag est marqué si
                             TRUE).
                ACK     --> 'dst port 80 and tcp[13] & 16 != 0' : Permet de vérifier la présence du flag ACK. Meme raisonnement que plus haut
                FIN     --> 'dst port 80 and tcp[13] & 16 != 0' : Permet de voir si le flag FIN est marqué. 
                RST     --> 'dst port 80 and tcp[13] & 4 != 0'  : Idem mais avec le flag RST. 
                PSH     --> 'dst port 80 and tcp[13] & 8 != 0'  : Idem mais avec le flag PSH.
                URG     --> 'dst port 80 and tcp[13] & 32 != 0' : Idem mais avec le flag URG.


        De meme, il est aussi possible de vérifier la présence de plusieurs flag en même temps en combinant plusieures expressions. Par
        exemple pour vérifier que les flags SYN et ACK sont présent tout les deux, nous pourrions utiliser un filtre BPF tel que :
        'dst port 80 and tcp[13] & 2 !=0 and tcp[13] & 16 !=0'. Vous pouvez ainsi créer une multitude de combinaisons pour filtrer avec
        une grande précision les header tcp. Comme nous l'avons vu un peu plus haut, vous pouvez intervenir directement sur d'autres
        packets, tels que IP ou encore Ethernet. 

        Imaginons par exemple qu'un administrateur veut vérifier si sa machine est en train de se faire smurfer (en général il n'a pas
        le temps mais c'est pour l'exemple :P). Bref, il lui suffira de filtrer les packets IP, sachant que l'adresse de destination est
        de type 'broadcast'. Ainsi il utilisera une expression telle que : 'ip[19] = 255 or ip[19] = 0'. 

        Bref je ne vais pas rentrer plus dans les détails, mais sachez que vous pouvez combiner toutes les options que nous avons vu plus
        haut. Le tout est de savoir le position des différentes options que vous cherchez. Pour cela, n'hésitez pas à lire les RFC :).



[ 4 ] Programmer son sniffer avec la libpcap :


A ce stade la, vous devriez commencer à comprendre à quoi sers le sniffing, et à savoir vous servir d'une manière efficace de tcpdump.
Ainsi, je vous propose de coder un *tout* petit sniffer en C basé sur la libpcap. Certes nous aurions pu le coder en Raw Socket, mais
si une library de capture de packet à été develloppée, ce n'est pas pour que nous ne l'utilisions pas ! 


        [ 4.1 ] Introduction à la libpcap :


        La libcap est (comme je viens de le dire juste au dessus) une library de fonction qui sert d'interface à la capture de packets.
        Elle permet de sniffer les réseau et d'utiliser différents filtres qui sont basés sur le Berkeley Packet Filter (BPF). Vous
        pouvez télécharger la derniere version sur le site de TCPDUMP : http://www.tcpdump.org. Il faut maintenant l'installer. Pour
        ce faire rien de plus simple : 


                [medgi@subkulture medgi]$ tar -xvzf libpcap.tar.gz ; cd libpcap
                [medgi@subkulture medgi]$ ./configure
                [medgi@subkulture medgi]$ su
                Password:
                [root@subkulture medgi]# make ; make install


        Ce n'était pas bien difficile comme vous pouvez le constater. Pour connaitre les différentes fonctions, il n'y à qu'une solution :
        lire les man pages (man pcap). Il est à noter qu'il est indispensable d'inclure la library en haut de votre code.


        [ 4.2 ] Explication du code :


        Nous allons coder ce *tout* petit sniffer étape par étape. Tout d'abord, il nous faut spécifier les bibliothèques de fonctions
        que nous souhaitons utiliser dans notre programme. Les voici donc : 


                #include <stdio.h>                      /* Pour les entrees et sortit standard           */
                #include <string.h>                     /* Pour les fonctions de manipulation de chaines */
                #include <unistd.h>                     /* Pour la gestions des arguments (getopt())     */
                #include <pcap.h>                       /* Pour utiliser la libpcap bien sur :)          */
                #include <signal.h>                     /* Pour intercepter le SIGINT                    */
                #include <stdarg.h>                     /* Pour la gestion des arguments (bis)           */


        Definissons maintenant deux chaines de caracteres constantes qui serviront pour l'aide et la version :


                #define VERSION "Psyrus v.ALPHA http://subkulture.unixlover.com"
                #define NAME "Psyrus v.ALPHA"


        Maintenant, spécifions les fonctions que nous allons utiliser dans notre code. DisplayHelp sers à afficher l'aide et GetSignal
        à recevoir un signal d'intérruption (^C) : 


                void DisplayHelp(char *version);
                void GetSignal(int signal);


        Ensuite, il faut définir toutes nos variables. Dans ce code seule le descripteur de type pcap_t sera définit en tant que variable
        globale. Les autres ne seront que des variables locales contenues dans la fonction main : 

                pcap_t *peer;                                   /* Le descripteur pour pcap_open_live()            */

                int main(int argc, char *argv[]) {

                 int option;                                    /* Descripteur pour utiliser getopt()              */
                 int pmode;                                     /* Variable pour le mode promiscious               */
                 int i;                                         /* Pour la boucle permettant de lire les packets   */

                 char *opt_list = "i:phv";                      /* Liste des options disponibles                   */
                 char errbuf[PCAP_ERRBUF_SIZE];                 /* Buffer pour les erreures de PCAP                */
                 char *device = NULL;                           /* Char contenant la carte reseau à utiliser       */

                 struct pcap_pkthdr usefull;                    /* Ne nous sers que pour la fonction pcap_next()   */
                 u_char *packet;                                /* Variable de type u_char contenant les packets   */


        Nous allons maintenant définir une structure qui nous permettra d'intercepter le signal ^C. Pour plus d'informations,
        consultez 'man sigaction' :


                 struct sigaction termsignal;                    /* Definition du nom de la structure              */
                 termsignal.sa_handler = (void*)GetSignal;       /* Action ( ici GetSignal() )                     */
                 termsignal.sa_flags = 0 ;                       /* Flag de la structure                           */
                 sigaction(SIGINT,&termsignal,NULL);             /* Permet de modifier l'action du processus du    */
                                                                 /* sniffer à la reception d'un signal.            */


        Ensuite, "remplissons" les variables que nous n'avons pas encore remplies : 


                 opterr = 0;                                     /* Permet de ne pas afficher les erreur de getopt */
                 pmode  = 0;                                     /* 0: normal mode | 1: promiscious mode           */


        Maintenant que les variables sont déclarée, nous allons devoir vérifier les arguments et effectuer les opérations en conséquence.
        Pour ce faire nous utilisons la fonction getopt() (man getopt) : 


                 while ((option = getopt (argc, argv, opt_list)) !=-1)                  /* Parsing des arguments   */
                    {
                      switch (option)                                                   /* L'argument est à chaque */
                                                                                        /* stocké dans 'optarg'.   */
                        {
                        case 'i':                                                       /* Si l'option vaut -i ... */
                          device = (char *)malloc(sizeof(optarg)*32);                   /* Allocation mémoire      */
                          strncpy(device, optarg, sizeof(optarg));                      /* Copie de optarg         */
                          break;
                        case 'p':
                          pmode = 1;                                                    /* pmode = 1 -> PROMISC.   */
                          break;
                        case 'h':
                          DisplayHelp(NAME);                                            /* Affichage de l'aide     */
                          exit(0);                                                      /* Fin du programme        */
                          break;
                        case 'v':                                                       /* Affichage de la version */
                          fprintf(stdout, "%s\n", VERSION);
                          exit(0);
                        default:                                                        /* Aucune option ou erreur */
                          fprintf(stdout,"ERROR : You must select a valid option. Use -h for help !\n");
                          exit(-1);
                          break;
                        }
                    }


        Si aucune carte réseau n'a été spécifié par l'option -i, nous allons demander à pcap qu'il choisisse la carte par défaut.
        Ainsi sera selectionnée la premiere carte réseau qui n'est pas du loopback. Voici donc le code : :


                 if(device==NULL) {                                                           /* Si aucune interface     */
                    if((device=pcap_lookupdev(errbuf))==NULL) {                               /* Interface default       */
                      fprintf(stderr,"ERROR : detecting device : %s failed !\n", errbuf);     /* Erreur :) ...           */
                      exit(-1);
                    }
                  }


        Nous allons maintenant passer au choses sérieuse, à savoir obtenir un déscripteur pour la capture de packet, grace à la fonction
        pcap_open_live(). Je rappelle vite fait la syntaxe : 


                 pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)

                        -> char *device : Correspond à l'interface à sniffer (dans notre code le char device).
                        -> int snaplen  : Le nombre maximum de bytes à capturer. 
                        -> int promisc  : 0 correspond au mode normal, 1 au mode promiscious.
                        -> int to_ms    : Le temps en milliseconde avant que le packet ne tombe en timeout.
                        -> char *ebuf   : Le buffer pour les erreures.

                Ainsi notre code est de la sorte :


                if((peer=pcap_open_live(device,1500,pmode,1000,errbuf))==NULL) {
                            fprintf(stderr,"ERROR : unable to open descriptor : %s !\n", errbuf);
                            exit(-1);
                }
        

        Il ne nous reste plus qu'à commencer le sniffing. Pour ce faire utilisons une boucle infinie, dans laquelle nous utiliserons
        la fonciton pcap_next pour récupérer les packet que nous afficherons.
        

         printf("Starting %s on %s\n\n", NAME, device);                 /* Stupid stats :)  */

         while (1) {                                                    /* boucle infinie   */
          packet = (u_char *) pcap_next(peer, &usefull);                /* packet suivant   */
          if (packet != NULL) {
           for (i=0; i<26;i++) {                                        /* 26 premiers bits */
             printf("%.2x", *packet);                                   /* Affichage        */
             packet++;                                                  /* Packet suivant   */
           }
          }
          printf("\n");
         }

        
        Enfin pour finir voila les deux fonctions externes, à savoir DisplayHelp() et GetSignal, qui je pense, n'ont pas besoin d'être
        commentée...
        

        void DisplayHelp(char *version) {
         fprintf(stdout, "Help menu for %s\n", NAME);
         fprintf(stdout, "-i [device]           Use a special device\n");
         fprintf(stdout, "-p                    Sniff packet in promiscious mode\n");
         fprintf(stdout, "-v                    Print the version of Psyrus\n");
         fprintf(stdout, "-h                    This little Help menu\n");

        }


        void GetSignal(int signal) {
          pcap_close(peer);
          printf("Received TERM signal, now stopping.\n");
          exit(0);
        }


        Notre sniffer est maintenant terminé, nous allons donc pouvoir le tester. Il faut savoir que les résultats qui seront affiché
        seront en hexadecimal. Pour la compilation, n'oubliez pas de linker avec la libpcap : "gcc psyrus.c -o psyrus -lpcap". Vous 
        pouvez trouver le code complet à l'annexe A.




[ 5 ] Détecter un sniffer et s'en protéger :


Lorsque vous envoyez une requete à une machine, celel ci vous répondra. Ainsi pour détecter un sniffer, il vous faut envoyer
une requete à l'adresse IP de la machine, mais non pas à son Adresse MAC.

Je m'explique : si vous lancer par exemple une requete ICMP Echo (Ping) vers une machine, mais que dans cette requete, le champ
IP soit correct, mais pas le champ MAC Adresse. Le packet va alors traverser le réseau (tout les packets sont sur le meme brin 
Ethernet), et chaque machine va comparer l'adresse MAC de Destination à la sienne. Ainsi en théorie vous ne devriez pas avoir de
réponses, puisque l'adresse MAC est érronée et n'existe pas. Cependant si par hasard vous obtenez tout de meme une réponse, alors
cela signifie que la machine qui vous à répondu utilise un sniffer...

Il existe une multitude d'autres méthode pour se détecter un sniffer. Pour les découvrir, aller voir la section ressource.
Pour se protéger d'un sniffer par contre, il n'y a pas vraiment de solution miracle. Etant donné qu'un sniffer ne se lance qu'en
root, il pourrait etre simpliste de dire qu'il faut faire en sorte qu'aucun intrus ne gagne le privilège super utilisateur.

Une autre maniere de se protéger est d'utiliser un réseau switché, de tel sorte que le sniff soit plus difficile. Bref je vous
laisse consulter la doc, car ce n'est pas exactement le theme de cet article.



[ 6 ] Ressources :


Cet article étant bien loin d'être complet (il reste de nombreux aspect à traiter) je vous suggère donc quelques petites adresses
de documents en rapport avec ce thème.




        http://www.robertgraham.com/pubs/sniffing-faq.html

        http://ouah.bsdjeunz.org/textes9.html

        http://www.minithins.net/papers/sniff.txt

        http://www.minithins.net/papers/pcap.manual

        http://www.hsc.fr/ressources/breves/pcap.html

        http://www.hsc.fr/ressources/breves/libnids.html

        http://tritheme.sourceforge.net/ressources.html


        
[ 7 ] Conclusion :


C'est la fin de cet article qui n'est en fiat qu'une introduction. En effet de nombreux points n'ont pas été abordés, comme par exemple 
les Network Intrusion Detection System (NIDS) basés eux aussi sur le sniff de packet, ou encore les différentes méthode d'attaque. 
De ce fait cet article est susceptible d'être modifié à l'avenir (pour une version plus complete que vous trouverez sur 
http://subkulture.unixlover.com). 

Bien entendu je n'ai pas la science infuse donc il se peut que je me sois trompé quelque part, ou encore que j'ai été incomplet. Bref
pour toute remarque, n'hésitez pas à me contacter soit par email (medgi@kernelhacking.net) soit sur irc #subkulture@undernet.

Pour finir je tenais à remercier l'ensemble du crew TipiaK pour m'avoir énormément appris depuis que j'ai rejoint leur rang et ceux
autant au niveau de la mentalité qu'au niveau de la technique. Je ne saurais dire comment je leur en suis reconnaissant, et d'ailleur
la plus part d'entre vous s'en foutent je pense, mais voila... MERCI

Merci aussi à Martony, Ad, GangstucK, Spud, descript, renar, Lionel, saur0n, crazyl0rd, wp92, klemm, ahk, mycroft, OUAH, Realist, y0me
Judcious, |Zen|, ...

Special Dedicasse to kraken & devhell crew ...

Have phun - medgi 2001