Chapitre 2.1 - Analyse de paquets et dissection de protocoles
Module 2 : Analyse du trafic et detection des intrusions Niveau : Intermediaire a avance | Duree estimee de lecture : 60-75 min
Table des matieres
- Pourquoi l'analyse de paquets est importante
- Anatomie d'un paquet - De la trame Ethernet au payload
- Outils et techniques de capture
- Wireshark - Inspection approfondie
- Dissection de protocoles - TCP, UDP, HTTP, DNS, TLS
- Detection des patterns de trafic malveillants
- Forensique reseau - Reconstruction des sessions
- Diagramme d'architecture
1. Pourquoi l'analyse de paquets est importante
L'analyse de paquets est la discipline consistant a capturer, decoder et interpreter le trafic reseau brut. Elle se situe a l'intersection de l'offense et de la defense :
- Pour les defenseurs : detecter les balises C2, l'exfiltration de donnees, le mouvement lateral, l'abus de protocoles
- Pour les intervenants en cas d'incident : reconstruire ce qui s'est passe, etablir des chronologies, recuperer les fichiers transferes
- Pour les red teamers : comprendre l'apparence de vos outils sur le reseau et comment vous fondre dans la masse
- Pour les ingenieurs : deboguer les problemes de protocole, valider le chiffrement, confirmer les regles de pare-feu
Le principe fondamental : chaque interaction reseau laisse une trace. Les paquets ne mentent pas. Les journaux peuvent etre supprimes, mais si vous capturez le trafic au niveau du fil, les preuves sont preservees.
L'etat d'esprit de l'analyste
Lors de l'examen d'une capture, posez-vous les questions suivantes :
- Quelle est la base de reference de ce reseau ? A quoi ressemble le comportement normal ?
- Ce trafic est-il attendu de cette paire source/destination ?
- Le volume, le timing et la direction correspondent-ils a l'usage declare ?
- Le protocole est-il utilise comme prevu, ou est-il detourne ?
2. Anatomie d'un paquet - De la trame Ethernet au payload
Chaque paquet traversant un reseau Ethernet est un oignon d'en-tetes encapsules. Comprendre les champs de chaque couche est un prerequis pour les lire.
2.1 Structure en couches
+------------------------------------------------------------------+
| Trame Ethernet |
| +------------+------------+-------------------------------+ |
| | MAC Dst | MAC Src | EtherType (0x0800=IPv4) | |
| | 6 octets | 6 octets | 2 octets | |
| +------------+------------+-------------------------------+ |
| +------------------------------------------------------------+ |
| | En-tete IP (20+ octets) | |
| | Ver|IHL|DSCP|ECN| Longueur totale | Identification | |
| | Drapeaux|Decalage fragment|TTL|Protocole|Somme de ctrl | |
| | IP source (4 octets) | IP destination (4 octets) | |
| +------------------------------------------------------------+ |
| +------------------------------------------------------------+ |
| | En-tete TCP/UDP | |
| | Port Src (2) | Port Dst (2) | Numero de sequence (4) | |
| | Numero d'acquittement (4) | Decalage|Drapeaux|Fenetre | |
| +------------------------------------------------------------+ |
| +------------------------------------------------------------+ |
| | Donnees applicatives | |
| | (HTTP, DNS, enregistrement TLS, payload brut...) | |
| +------------------------------------------------------------+ |
+------------------------------------------------------------------+
2.2 Champs de l'en-tete IP - Pertinence securitaire
| Champ | Taille | Importance pour la securite |
|---|---|---|
| TTL | 8 bits | Empreinte du systeme d'exploitation (Linux=64, Windows=128, Cisco=255) ; decremente a chaque saut |
| Protocole | 8 bits | 6=TCP, 17=UDP, 1=ICMP - les canaux dissimules utilisent des protocoles inattendus |
| IP source | 32 bits | Peut etre usurpee (outil d'attaquant pour DoS, obscurcissement du scan) |
| Decalage fragment | 13 bits | Attaques par chevauchement de fragments pour contourner l'IDS |
| Drapeaux (DF, MF) | 3 bits | DF=Ne pas fragmenter ; fragments chevauchants utilises pour l'evasion |
| DSCP/ECN | 6+2 bits | Parfois utilise pour les canaux dissimules |
| Identification | 16 bits | Les ID sequentiels fuient des infos OS ; utilise pour le scan inactif (Nmap -sI) |
2.3 Champs de l'en-tete TCP - Pertinence securitaire
| Champ | Taille | Importance pour la securite |
|---|---|---|
| Port source | 16 bits | Les plages de ports ephemeres different par OS (Linux : 32768-60999, Windows : 49152-65535) |
| Numero de sequence | 32 bits | ISN previsible = risque de detournement de session ; attaques par reinitialisation TCP |
| Numero ACK | 32 bits | Doit correspondre a la seq attendue - les non-correspondances indiquent une injection |
| Drapeaux | 9 bits | SYN/FIN/RST/PSH/ACK/URG - combinaisons inhabituelles (Xmas, NULL, scan FIN) |
| Taille de fenetre | 16 bits | Empreinte OS ; fenetre zero = controle de flux |
| Pointeur d'urgence | 16 bits | Rarement utilise legitimement ; parfois utilise pour les donnees dissimulees |
2.4 Drapeaux TCP et types de scan
Drapeaux de communication normale :
SYN -> Initiation de connexion
SYN + ACK -> Acquittement du serveur
ACK -> Acquittement de donnees
FIN + ACK -> Fermeture gracieuse de connexion
RST -> Reinitialisation abrupte de connexion
Combinaisons de drapeaux de scan :
SYN uniquement -> Scan SYN (furtif -- pas de poignee de main complete)
FIN uniquement -> Scan FIN (contourne les filtres de paquets sans etat)
FIN + URG + PSH -> Scan Xmas (tous "allumes" -- inhabituel, contourne certains IDS)
Pas de drapeaux -> Scan NULL (zero drapeaux -- non conforme RFC, evasion)
ACK uniquement -> Scan ACK (cartographie les regles de pare-feu -- revele filtre vs non filtre)
SYN + FIN -> Invalide -- signal d'alarme immediat dans l'IDS
SYN + RST -> Invalide -- signal d'alarme
Filtres tcpdump pour les combinaisons de drapeaux suspects :
tcpdump -i eth0 'tcp[tcpflags] & (tcp-fin|tcp-syn|tcp-rst|tcp-push|tcp-urg) == 0'
tcpdump -i eth0 'tcp[tcpflags] & (tcp-fin|tcp-urg|tcp-push) == (tcp-fin|tcp-urg|tcp-push)'
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-fin) == (tcp-syn|tcp-fin)'
3. Outils et techniques de capture
3.1 tcpdump - Capture en ligne de commande
tcpdump est l'outil de capture universel sur Linux/Unix. Sa syntaxe Berkeley Packet Filter (BPF) est partagee par tcpdump, Wireshark, Snort, Suricata et de nombreux autres outils.
# Capture basique sur l'interface eth0
tcpdump -i eth0
# Capturer dans un fichier (toujours faire cela -- analyser hors ligne)
tcpdump -i eth0 -w capture.pcap
# Capturer avec un tampon plus grand (reduit les paquets perdus sur les liens charges)
tcpdump -i eth0 -B 4096 -w capture.pcap
# Capturer avec horodatages et sans resolution DNS (plus rapide, affiche les IP brutes)
tcpdump -i eth0 -nn -tttt -w capture.pcap
# -nn : ne pas resoudre les noms d'hotes ou les noms de port
# -tttt : afficher l'horodatage absolu avec la date
# Rotation des fichiers de capture : nouveau fichier tous les 100 Mo ou toutes les 3600 secondes
tcpdump -i eth0 -C 100 -G 3600 -w capture_%Y%m%d_%H%M%S.pcap
# -- Filtres BPF --
# Capturer uniquement le trafic vers/depuis un hote specifique
tcpdump -i eth0 host 10.0.0.50
# Capturer un port specifique
tcpdump -i eth0 port 443
# Capturer un sous-reseau
tcpdump -i eth0 net 10.0.0.0/24
# Capturer TCP uniquement (exclure le bruit UDP/ICMP)
tcpdump -i eth0 tcp
# Capturer les requetes DNS (port UDP 53) ET les reponses
tcpdump -i eth0 'udp port 53'
# Capturer le trafic HTTP et afficher le payload ASCII
tcpdump -i eth0 -A 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
# Capturer tout le trafic SAUF SSH (eviter de capturer sa propre session)
tcpdump -i eth0 'not port 22'
# Detecter les scans de ports potentiels : paquets SYN vers plusieurs ports depuis une source
tcpdump -i eth0 'tcp[tcpflags] == tcp-syn' -nn | \
awk '{print $3}' | \
cut -d. -f1-4 | \
sort | uniq -c | sort -rn | head
# Capturer ICMP et afficher type/code
tcpdump -i eth0 icmp -v
3.2 tshark - Interface CLI de Wireshark
tshark fournit le moteur de dissection de Wireshark en ligne de commande - ideal pour l'analyse automatisee et les scripts.
# Lire un pcap et afficher avec des champs specifiques
tshark -r capture.pcap \
-T fields \
-e frame.time \
-e ip.src \
-e ip.dst \
-e tcp.dstport \
-e http.request.method \
-e http.request.uri \
-E header=y \
-E separator=, \
> requetes_http.csv
# Extraire toutes les requetes DNS d'une capture
tshark -r capture.pcap \
-Y "dns.flags.response == 0" \
-T fields \
-e frame.time \
-e ip.src \
-e dns.qry.name \
-e dns.qry.type
# Suivre un flux TCP specifique (reconstruire la conversation)
tshark -r capture.pcap \
-z follow,tcp,ascii,0 # Indice de flux 0
# Statistiques : principaux emetteurs par octets
tshark -r capture.pcap -q -z conv,ip | head -20
# Hierarchie de protocoles (quels protocoles sont dans la capture)
tshark -r capture.pcap -q -z io,phs
# Extraire les fichiers du trafic HTTP (images, executables, documents)
tshark -r capture.pcap \
--export-objects http,/tmp/fichiers_extraits/
# Trouver les sessions TCP de longue duree (balises C2 potentielles)
tshark -r capture.pcap -q -z conv,tcp | \
awk '{print $1, $3, $5, $9}' | \
sort -k4 -rn | head -20 # Trier par duree
# Dechiffrer le trafic TLS (necessite un fichier journal de cles)
tshark -r capture.pcap \
-o "tls.keylog_file:/tmp/clessl.log" \
-Y "http" \
-T fields -e http.request.full_uri
3.3 Positions de capture dans le reseau
La position de votre capteur de capture determine ce que vous pouvez voir :
SPAN / Miroir de port (Switched Port Analyzer) :
Dans un reseau commute, vous ne pouvez pas simplement brancher un portable et voir le trafic de tout le monde (contrairement aux hubs). Un port SPAN copie tout le trafic des ports sources vers un port de surveillance.
# Commutateur Cisco : configurer le port SPAN
Switch(config)# monitor session 1 source interface Gi0/1 - Gi0/24
Switch(config)# monitor session 1 destination interface Gi0/25
# Connecter maintenant le dispositif de capture a Gi0/25 -- voit tout le trafic de Gi0/1-24
# Linux : intercepter une interface bridge pour voir le trafic entre deux segments
ip link add br0 type bridge
ip link set eth0 master br0
ip link set eth1 master br0
ip link set br0 up
tcpdump -i br0 -w capture.pcap
4. Wireshark - Inspection approfondie
4.1 Filtres essentiels
Les filtres d'affichage Wireshark utilisent une syntaxe differente des filtres BPF tcpdump - ils operent sur les champs de protocole decodes.
# -- Filtres de base --
ip.addr == 10.0.0.50 # Trafic vers ou depuis cette IP
ip.src == 10.0.0.50 # Trafic depuis cette source
ip.dst == 10.0.0.50 # Trafic vers cette destination
tcp.port == 443 # Port source ou destination 443
tcp.dstport == 8080 # Port destination 8080
tcp.flags.syn == 1 # Drapeau SYN active
tcp.flags == 0x002 # SYN uniquement (detection de scan)
tcp.flags.syn == 1 && tcp.flags.ack == 0 # SYN sans ACK (scan semi-ouvert)
# -- Filtres specifiques aux protocoles --
http.request.method == "POST" # Requetes HTTP POST
http.response.code >= 500 # Erreurs serveur
dns.qry.name contains "evil" # Requete DNS contenant "evil"
dns.resp.ttl < 60 # Reponses DNS a faible TTL (fast-flux C2)
tls.handshake.type == 1 # TLS ClientHello
tls.record.version == 0x0301 # TLS 1.0 (depreciee)
smtp.req.command == "AUTH" # Tentatives d'authentification SMTP
ftp.request.command == "PASS" # Mot de passe FTP (en clair !)
# -- Filtres d'analyse avancee --
frame.len > 1400 # Grands paquets (exfiltration ? fragmentation ?)
tcp.analysis.retransmission # Retransmissions TCP (problemes reseau ou evasion)
tcp.analysis.zero_window # Fenetre zero -- problemes de controle de flux
tcp.analysis.duplicate_ack # ACK dupliques -- indicateur de perte de paquets
ip.ttl < 10 # Faible TTL -- paquet a traverse de nombreux sauts ou manipulation TTL
icmp.type == 8 && frame.len > 100 # Ping ICMP surdimensionne (tunneling ICMP)
# -- Chasse aux identifiants --
http contains "password" # Trafic HTTP contenant la chaine "password"
ftp # Tout FTP (identifiants en clair)
telnet # Tout Telnet (identifiants en clair)
pop || imap # Protocoles email (authentification souvent en clair)
4.2 Statistiques et fonctions d'analyse
Outils d'analyse du menu Wireshark :
Statistiques -> Hierarchie de protocoles
-> Affiche tous les protocoles dans la capture, % d'octets utilises
-> Anomalie : protocole inattendu (ex. IRC, IMAP dans le trafic d'entreprise)
Statistiques -> Conversations
-> Liste toutes les conversations TCP/UDP/IP avec les octets transferes
-> Trier par octets : grands transferts vers des IP externes = candidats a l'exfiltration
Statistiques -> Points de terminaison
-> Affiche tous les points de terminaison IP/MAC, paquets envoyes/recus
-> IP internes communicant avec de nombreuses IP externes = scanner ou botnet
Statistiques -> Graphique E/S
-> Volume de trafic dans le temps
-> Pics reguliers a intervalles fixes = battement de balise C2
Analyser -> Informations expertes
-> Detection automatique d'anomalies par Wireshark
-> Erreurs (rouge) : retransmissions TCP, echecs de somme de controle
-> Avertissements (jaune) : reinitialisation de connexion, problemes de fenetre
-> Notes (cyan) : anomalies de protocole
Analyser -> Suivre -> Flux TCP
-> Reconstruit la conversation de la couche applicative
-> Affiche requete + reponse sous forme lisible
-> Critique pour : analyse de session HTTP, capture d'identifiants en clair
Statistiques -> HTTP -> Requetes
-> Toutes les requetes HTTP par hote, chemin, agent utilisateur
-> Agents utilisateurs inhabituels = maliciels ou outils de scan
4.3 Regles de colorisation pour l'analyse de securite
La colorisation par defaut de Wireshark aide a reperer les problemes :
- Fond noir (texte rouge) : Erreurs TCP, mauvaises sommes de controle
- Rouge fonce : Erreurs HTTP (4xx, 5xx)
- Violet clair : TCP SYN
- Bleu clair : DNS
- Vert clair : Trafic HTTP
Regle personnalisee pour la detection C2 :
# Ajouter une regle de colorisation personnalisee pour les connexions longues suspects :
# Modifier -> Regles de colorisation -> Nouveau
# Nom : "TCP Long Suspect"
# Filtre : tcp.time_relative > 3600 && tcp.flags.syn == 0
# Couleur : fond rouge vif
5. Dissection de protocoles
5.1 TCP - Analyse de la poignee de main a trois voies
# Capturer et annoter une poignee de main TCP
tcpdump -i eth0 -nn 'host 10.0.0.50 and port 80' -v
# Sortie attendue pour une poignee de main normale :
# 10:00:01.000 IP 10.0.0.10.54321 > 10.0.0.50.80: Flags [S], seq 0, win 64240, length 0
# ^ ^SYN ^ISN
# 10:00:01.001 IP 10.0.0.50.80 > 10.0.0.10.54321: Flags [S.], seq 0, ack 1, win 65535, length 0
# ^ ^SYN+ACK
# 10:00:01.002 IP 10.0.0.10.54321 > 10.0.0.50.80: Flags [.], ack 1, win 502, length 0
# ^ ^ACK
# Detecter les tempetes RST (tentative d'intrusion / DoS)
tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0' -nn | \
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn
# Detecter les connexions semi-ouvertes (inondation SYN)
ss -ant | grep SYN_RECV | wc -l
# Plus de 200 SYN_RECV est suspect
netstat -ant | grep SYN_RECV | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn
5.2 HTTP - Analyse des requetes/reponses
# Extraire toutes les requetes HTTP avec horodatages, methode, URI, code de reponse
tshark -r capture.pcap \
-Y "http.request or http.response" \
-T fields \
-e frame.time_relative \
-e ip.src \
-e ip.dst \
-e http.request.method \
-e http.request.uri \
-e http.response.code \
-e http.user_agent \
-E separator="|"
# Agents utilisateurs suspects a rechercher dans le trafic HTTP :
# curl/7.x.x -> requetes scriptees (automatisation / outils d'attaquant)
# python-requests -> scripte (tests d'intrusion, maliciels)
# Go-http-client -> outils bases sur Go (de nombreux frameworks C2)
# Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) -> tres ancien UA, probablement un maliciel
# (agent utilisateur vide) -> connexion socket brute, outil automatise
# Nikto, sqlmap, Masscan, dirbuster -> outils de scan
# Chasser les grands corps POST (exfiltration potentielle ou payload d'exploit)
tshark -r capture.pcap \
-Y "http.request.method == POST && http.content_length > 10000" \
-T fields \
-e ip.src -e http.request.uri -e http.content_length
# Detecter les tentatives de traversee de repertoire dans les URI HTTP
tshark -r capture.pcap \
-Y 'http.request.uri contains "../"' \
-T fields -e ip.src -e http.request.uri
# Detecter les patterns d'injection SQL dans les URI
tshark -r capture.pcap \
-Y 'http.request.uri matches "(?i)(union|select|insert|drop|exec|xp_)"' \
-T fields -e ip.src -e http.request.uri
5.3 DNS - Analyse des requetes
Le DNS est le protocole le plus riche en informations pour detecter l'activite malveillante - presque toute action reseau necessite du DNS.
# Extraire toutes les requetes DNS avec les IP de reponse
tshark -r capture.pcap \
-Y "dns" \
-T fields \
-e frame.time \
-e ip.src \
-e dns.qry.name \
-e dns.a \
-e dns.flags.response \
| grep "0$" # Uniquement les requetes (indicateur reponse = 0)
# Trouver les domaines avec un TTL suspicieusement bas (fast-flux C2)
tshark -r capture.pcap \
-Y "dns.flags.response == 1" \
-T fields \
-e dns.qry.name \
-e dns.resp.ttl \
| awk '$2 < 60 {print}' | sort -u
# Detecter le tunneling DNS : rechercher les etiquettes de sous-domaine longues
tshark -r capture.pcap \
-Y "dns" \
-T fields \
-e dns.qry.name \
| awk '{if(length($1) > 50) print $1}' | sort -u
# Calculer l'entropie des noms de requetes DNS (detection DGA)
python3 << 'EOF'
import math
from collections import Counter
# Coller les noms de requetes DNS ici (depuis la sortie tshark ou les journaux DNS)
domaines = [
"www.google.com",
"api.github.com",
"aGVsbG8.evil-c2.net", # Sous-domaine encode en base64
"xkjhdfqwer.biz", # Style DGA
"mail.company.com"
]
def entropie(s):
comptes = Counter(s)
total = len(s)
return -sum((c/total) * math.log2(c/total) for c in comptes.values())
for d in domaines:
etiquette = d.split('.')[0] # Premiere etiquette
e = entropie(etiquette)
drapeau = "SUSPECT" if e > 3.5 or len(etiquette) > 30 else "OK"
print(f"{d:45s} entropie={e:.2f} {drapeau}")
EOF
# Detecter le rebinding DNS (changement d'IP en succession rapide pour le meme domaine)
# L'attaquant change le DNS vers une IP interne apres que le navigateur a mis en cache la resolution initiale
tshark -r capture.pcap -Y "dns.flags.response == 1" \
-T fields -e dns.qry.name -e dns.a | \
sort | awk 'seen[$1]++ && seen[$1]==2 {print "PLUSIEURS IPs: "$0}'
5.4 TLS - Inspection de la poignee de main sans dechiffrement
Meme sans dechiffrer le TLS, la poignee de main revele des informations significatives.
# Extraire les details du TLS ClientHello (ce que le client supporte)
tshark -r capture.pcap \
-Y "tls.handshake.type == 1" \
-T fields \
-e ip.src \
-e tls.handshake.extensions_server_name \
-e tls.handshake.ciphersuite \
-e tls.handshake.extensions.supported_versions
# Empreinte JA3 : identifier les clients TLS par les parametres de poignee de main
# JA3 = MD5 de (SSLVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePoints)
# Les familles de maliciels ont des hachages JA3 caracteristiques independamment du payload
# Installer ja3 pour tshark
pip3 install pyshark
python3 << 'EOF'
import pyshark
import hashlib
def calculer_ja3(pkt):
"""Calculer le hachage JA3 depuis le TLS ClientHello"""
try:
tls = pkt.tls
if int(tls.handshake_type) != 1:
return None
version = tls.handshake_version
ciphers = tls.handshake_ciphersuite.replace(':', '-')
extensions = getattr(tls, 'handshake_extensions_type', '').replace(':', '-')
curves = getattr(tls, 'handshake_extensions_supported_group', '').replace(':', '-')
points = getattr(tls, 'handshake_extensions_ec_point_format', '').replace(':', '-')
ja3_str = f"{version},{ciphers},{extensions},{curves},{points}"
ja3_hash = hashlib.md5(ja3_str.encode()).hexdigest()
return ja3_hash, ja3_str
except AttributeError:
return None
cap = pyshark.FileCapture('capture.pcap', display_filter='tls.handshake.type==1')
for pkt in cap:
result = calculer_ja3(pkt)
if result:
ja3_hash, ja3_str = result
print(f"src={pkt.ip.src} JA3={ja3_hash}")
# Comparer avec les hachages JA3 connus de maliciels :
# Cobalt Strike par defaut : 72a589da586844d7f0818ce684948eea
# Metasploit par defaut : d4e457bda4060ac3a1e0ce55df394aa6
EOF
# Empreinte JARM -- identifier les SERVEURS TLS
# JARM envoie 10 TLS ClientHellos specialement construits, identifie les reponses du serveur
# Utile pour identifier l'infrastructure C2 independamment du certificat
pip3 install jarm-fingerprinter
python3 -m jarm 10.0.0.1 443
# Sortie : hachage JARM (ex. "07d14d16d21d21d00042d43d000000...")
# Comparer avec les hachages de serveurs C2 connus dans les flux de renseignement sur les menaces
6. Detection des patterns de trafic malveillants
6.1 Detection de balises C2
La balise C2 se caracterise par des connexions periodiques et regulieres vers une IP/domaine externe. L'intervalle de rappel est un signal de detection cle.
# Detecter les balises : trouver les connexions avec des intervalles de temps reguliers
# Extraire les horodatages de connexion par destination
python3 << 'EOF'
import subprocess, json
from collections import defaultdict
import statistics
# Lancer tshark pour extraire les horodatages TCP SYN par IP destination
sortie = subprocess.check_output([
'tshark', '-r', 'capture.pcap',
'-Y', 'tcp.flags.syn==1 && tcp.flags.ack==0',
'-T', 'fields',
'-e', 'frame.time_epoch',
'-e', 'ip.dst'
], text=True)
# Grouper par IP destination
connexions = defaultdict(list)
for ligne in sortie.strip().split('\n'):
if '\t' in ligne:
ts, dst = ligne.split('\t')
connexions[dst].append(float(ts))
# Analyser les intervalles pour chaque destination
print(f"{'IP Destination':20s} {'Connexions':12s} {'Intervalle moy':15s} {'Ecart-type':12s} {'Balise?'}")
print("-" * 75)
for dst, horodatages in sorted(connexions.items()):
if len(horodatages) < 4:
continue
horodatages.sort()
intervalles = [horodatages[i+1]-horodatages[i] for i in range(len(horodatages)-1)]
moy = statistics.mean(intervalles)
std = statistics.stdev(intervalles) if len(intervalles) > 1 else 0
ratio_gigue = std / moy if moy > 0 else 1
balise = "BALISE" if ratio_gigue < 0.1 and moy < 3600 else ""
print(f"{dst:20s} {len(horodatages):12d} {moy:15.1f}s {std:12.1f} {balise}")
EOF
6.2 Patterns d'exfiltration de donnees
# Detecter les grands transferts de donnees sortants
tshark -r capture.pcap -q -z conv,tcp | \
awk 'NR>5 {
split($1, src, ":")
split($3, dst, ":")
if ($6+0 > $8+0) { # Plus d'octets envoyes que recus = transfert sortant
print $1, "->", $3, "Sortant:", $6, "octets"
}
}' | sort -k5 -rn | head -20
# Detecter l'exfiltration DNS (volume eleve de requetes par domaine)
tshark -r capture.pcap -Y "dns.flags.response==0" \
-T fields -e dns.qry.name | \
awk -F. '{
n = NF; domaine = $(n-1)"."$n;
compteur[domaine]++
}
END {
for (d in compteur) if (compteur[d] > 100) print compteur[d], d
}' | sort -rn
# Detecter l'exfiltration HTTPS via des volumes de transfert inhabituels
# Grand POST vers une IP externe a des heures inhabituelles
tshark -r capture.pcap \
-Y "http.request.method==POST" \
-T fields \
-e frame.time \
-e ip.src \
-e ip.dst \
-e http.content_length | \
awk -F'\t' '$4+0 > 100000 {print}' # Corps POST > 100 Ko
6.3 Detection de scan de ports
# Detecter un scan horizontal : une source touchant de nombreuses destinations sur le meme port
# (ex. propagation de ver, mouvement lateral)
tshark -r capture.pcap \
-Y "tcp.flags.syn==1 && tcp.flags.ack==0" \
-T fields -e ip.src -e ip.dst | \
awk '{srcdst[$1][$2]=1} END {
for (src in srcdst) {
n = 0
for (dst in srcdst[src]) n++
if (n > 20) print src, "->", n, "destinations"
}
}'
# Detecter un scan vertical : une source touchant de nombreux ports sur la meme destination
# (enumeration de services)
tshark -r capture.pcap \
-Y "tcp.flags.syn==1 && tcp.flags.ack==0" \
-T fields -e ip.src -e ip.dst -e tcp.dstport | \
awk '{cle=$1" "$2; ports[cle][$3]=1}
END {
for (k in ports) {
n=0; for (p in ports[k]) n++
if (n > 15) print k, ":", n, "ports"
}
}'
# Detecter les sondes de detection OS de Nmap (envoie des paquets avec des options TCP inhabituelles)
# Rechercher les paquets TCP avec des tailles de fenetre et combinaisons d'options inhabituelles
tcpdump -r capture.pcap -v 'tcp[tcpflags] == tcp-syn' 2>/dev/null | \
grep -E "win [0-9]+ " | \
awk '{print $NF}' | \
sort | uniq -c | sort -rn
# Le scan SYN de Nmap utilise les tailles de fenetre 1024, 2048, 4096 en sequence
6.4 Anomalies de protocole
# Detecter des protocoles communs sur des ports non standards
# HTTP sur des ports autres que 80/443 (evasion ou pivot possibles)
tshark -r capture.pcap \
-Y "http && not tcp.port == 80 && not tcp.port == 443 && not tcp.port == 8080" \
-T fields -e ip.src -e ip.dst -e tcp.dstport -e http.request.uri
# DNS sur un port non standard (evasion par tunneling DNS)
tshark -r capture.pcap \
-Y "dns && not udp.port == 53 && not tcp.port == 53" \
-T fields -e ip.src -e ip.dst -e udp.dstport
# Paquets ICMP avec grand payload (tunneling)
tshark -r capture.pcap \
-Y "icmp && frame.len > 100" \
-T fields -e ip.src -e ip.dst -e frame.len -e data.len
# Identifiants en clair sur le reseau (protocoles historiques)
tcpdump -r capture.pcap -A -l 'port ftp or port 23 or port 110 or port 143' | \
grep -iE "(user|pass|login|password|auth)" | \
grep -v "^[[:space:]]*$"
7. Forensique reseau - Reconstruction des sessions
7.1 Extraction de fichiers depuis les captures
# Extraire les fichiers transferes par HTTP (executables, documents, images)
tshark -r capture.pcap \
--export-objects http,/tmp/http_extraits/
ls -la /tmp/http_extraits/
# Les fichiers sont nommes par le chemin URI HTTP
# Verifier les fichiers extraits pour les maliciels :
file /tmp/http_extraits/*
for f in /tmp/http_extraits/*; do
hachage=$(sha256sum "$f" | awk '{print $1}')
echo "$f: $hachage"
# Interroger VirusTotal, MalwareBazaar, etc.
done
# Extraire les fichiers transferes par SMB
tshark -r capture.pcap \
--export-objects smb,/tmp/smb_extraits/
# Reconstruire un flux TCP vers un fichier
tshark -r capture.pcap \
-z follow,tcp,raw,0 \
| xxd | head -50 # Afficher en hexadecimal
# Alternative : dpkt Python pour le reassemblage de flux brut
python3 << 'EOF'
import dpkt, socket
with open('capture.pcap', 'rb') as f:
pcap = dpkt.pcap.Reader(f)
flux = {}
for ts, buf in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
if not isinstance(eth.data, dpkt.ip.IP): continue
ip = eth.data
if not isinstance(ip.data, dpkt.tcp.TCP): continue
tcp = ip.data
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
cle = f"{src}:{tcp.sport}->{dst}:{tcp.dport}"
if tcp.data:
flux.setdefault(cle, b'')
flux[cle] += tcp.data
except:
continue
for flux_id, donnees in flux.items():
if len(donnees) > 1000:
print(f"Flux {flux_id}: {len(donnees)} octets")
# Sauvegarder les grands flux pour analyse
fname = flux_id.replace(':', '_').replace('>', '_').replace('/', '_')
with open(f"/tmp/flux_{fname}.bin", 'wb') as out:
out.write(donnees)
EOF
7.2 Reconstruction de la chronologie
# Construire une chronologie des evenements reseau depuis une capture
tshark -r capture.pcap \
-T fields \
-e frame.time \
-e ip.src \
-e ip.dst \
-e _ws.col.Protocol \
-e _ws.col.Info \
-E separator="|" \
| sort > chronologie_reseau.txt
# Trouver la premiere et derniere occurrence de chaque connexion
tshark -r capture.pcap -q -z conv,tcp | \
awk 'NR>5 {print $1, "premier:", $5, "dernier:", $6, "duree:", $9}'
# Corroller avec les journaux systeme (combiner les artefacts reseau et hote)
# Joindre la chronologie reseau avec les horodatages auth.log
join <(awk -F'|' '{print $1, $2}' chronologie_reseau.txt | sort) \
<(grep "Failed password" /var/log/auth.log | awk '{print $1, $2, $3, $9}' | sort)
7.3 Automatisation de l'analyse Pcap avec Scapy
from scapy.all import *
from collections import defaultdict
import statistics
def analyser_pcap(fichier_pcap):
"""Analyse pcap comprehensive pour les incidents de securite"""
paquets = rdpcap(fichier_pcap)
print(f"Charge {len(paquets)} paquets\n")
# Suivre les statistiques
compteurs_syn = defaultdict(int)
requetes_dns = defaultdict(list)
grands_transferts = []
identifiants_clair = []
for pkt in paquets:
# Detection de scan SYN
if TCP in pkt and pkt[TCP].flags == 'S':
src = pkt[IP].src if IP in pkt else "inconnu"
compteurs_syn[src] += 1
# Journalisation des requetes DNS
if DNS in pkt and pkt[DNS].qr == 0:
requete = pkt[DNS].qd.qname.decode('utf-8', errors='ignore').rstrip('.')
src = pkt[IP].src if IP in pkt else "inconnu"
requetes_dns[src].append(requete)
# Detection de grand payload TCP (>10 Ko par paquet)
if TCP in pkt and Raw in pkt:
if len(pkt[Raw].load) > 10000:
grands_transferts.append({
'src': pkt[IP].src,
'dst': pkt[IP].dst,
'taille': len(pkt[Raw].load),
'temps': float(pkt.time)
})
# Detection d'identifiants FTP en clair
if TCP in pkt and Raw in pkt:
payload = pkt[Raw].load.decode('utf-8', errors='ignore')
if payload.startswith(('USER ', 'PASS ')):
identifiants_clair.append({
'src': pkt[IP].src,
'dst': pkt[IP].dst,
'donnees': payload.strip()
})
# Rapport des resultats
print("=== CANDIDATS SCAN DE PORTS ===")
for src, compteur in sorted(compteurs_syn.items(), key=lambda x: -x[1]):
if compteur > 50:
print(f" {src}: {compteur} SYNs")
print("\n=== VOLUME ELEVE DE REQUETES DNS ===")
for src, requetes in requetes_dns.items():
if len(requetes) > 100:
print(f" {src}: {len(requetes)} requetes")
# Afficher les domaines les plus interroges
from collections import Counter
top = Counter(requetes).most_common(5)
for domaine, cnt in top:
print(f" {domaine}: {cnt}x")
print("\n=== GRANDS TRANSFERTS ===")
for t in sorted(grands_transferts, key=lambda x: -x['taille'])[:10]:
print(f" {t['src']} -> {t['dst']}: {t['taille']:,} octets")
print("\n=== IDENTIFIANTS EN CLAIR ===")
for c in identifiants_clair:
print(f" {c['src']} -> {c['dst']}: {c['donnees']}")
# analyser_pcap('capture.pcap')