Nous avons vu dans l'article précédent qu'il était difficile d'empêcher de manière pratique l'identification d'un système par son empreinte réseau. Il existe cependant une solution à la fois efficace et facile à mettre en oeuvre
Cette solution consiste à retourner contre les applications de type nmap ce qui leur permet de fonctionner, en filtrant les requêtes spécifiques qu'elles emploient à l'aide d'un pare-feu.
Système FreeBSD contre Nmap (2/2)
Solutions avancées
Nous avons vu dans l'article précédent qu'il était difficile d'empêcher de
manière pratique l'identification d'un système par son empreinte réseau.
Il existe cependant une solution à la fois efficace et facile à mettre en ?uvre
!
Cette solution consiste à retourner contre les applications de type nmap ce qui
leur permet de fonctionner, en filtrant les requêtes spécifiques qu'elles
emploient à l'aide d'un pare-feu.
Les tests suivants ont été réalisés entre deux machines FreeBSD 4.7-RELEASE, la
machine cible étant équipée du pare-feu IPFW :
# cd /sys/i386/conf
# cp GENERIC GENERICFW
# echo "options IPFIREWALL" >> GENERICFW
# echo "options IPFIREWALL_DEFAULT_TO_ACCEPT" >> GENERICFW
# config GENERICFW
# cd ../../compile/GENERICFW
# make depend
# make
# cp kernel /
# reboot
L'empreinte réseau d'une telle machine est (pour le moment) identique à celle
d'une machine sans pare-feu :
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
Pour comprendre la signification de cette empreinte, je vous invite à vous
reporter à l'excellent article de l'institut SANS sur le principe des
empreintes réseau.
A ce stade des opérations, il suffit de savoir que cette empreinte est
constituée du résultat de 9 tests (TSeq, T1 à T7 et PU) dont nous allons
maintenant attaquer les spécificités, d'abord pas à pas, puis globalement.
Les deux premiers tests sont des tests de connexion initiale sur un port TCP
ouvert. Pour les contrer, nous allons procéder aux man?uvres suivantes
(sachant que les seuls ports TCP ouverts sont les ports 22 (ssh), 25 (smtp) et
587 (submission)) :
defenseur# ipfw add 100 deny tcp from any to me 22,25,587
tcpflags !fin,syn,!rst,!psh,!ack,!urg
tcpoptions mss,window,!sack,ts,!cc
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
T1(Resp=N)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
Le test T1 passe d'une réponse assez caractéristique à pas de réponse
("Resp=N"). Le résultat du test TSeq, quant à lui, disparait totalement et
Nmap affiche des messages tels que :
Insufficient responses for TCP sequencing (0), OS detection may be less
accurate
Il faut cependant noter que la règle de pare-feu proposée induit certains
effets de bord puisqu'elle accroche 0,1 à 0,3% de paquets potentiellement
licites, ce qui n'est pas négligeable...
Le test suivant (T2) étant déjà sans réponse, on ne fait rien de particulier.
Le test T3 (celui que bloquait l'option TCP_DROP_SYNFIN du noyau) est un test
sur un port TCP ouvert avec une combinaison de drapeaux vraiment atypique :
defenseur# ipfw del 100
defenseur# ipfw add 100 deny tcp from any to me 22,25,587
tcpflags fin,syn,!rst,psh,!ack,urg
tcpoptions mss,window,!sack,ts,!cc
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=N)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
Le test T4 est un test d'acceptation de connexion sur un port TCP ouvert :
defenseur# ipfw del 100
defenseur# ipfw add 100 deny tcp from any to me 22,25,587
tcpflags !fin,!syn,!rst,!psh,ack,!urg
tcpoptions mss,window,!sack,ts,!cc
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=N)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
Les tests T5 à T7 sont des tests sur un port TCP fermé, qu'un pare-feu est
justement habituellement là pour filtrer (c'est également ce que fait la
fonctionnalité de "blackhole" sur les ports TCP décrite dans l'article
précédent) :
defenseur# ipfw del 100
defenseur# ipfw add 100 deny tcp from any to me 0-21
defenseur# ipfw add 101 deny tcp from any to me 23,24
defenseur# ipfw add 102 deny tcp from any to me 26-586
defenseur# ipfw add 103 deny tcp from any to me 588-1023
defenseur# ipfw add 104 deny tcp from any to me 1024-65535 setup
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=N)
T6(Resp=N)
T7(Resp=N)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
A noter : les règles de pare-feu données ici ne sont là que pour illustrer cet
article (pour un système utilisé comme station de travail, il ne faudrait pas
nécessairement procéder ainsi...).
Le test PU est un test sur un port UDP fermé (ici également, voir la
fonctionnalité de "blackhole" sur les ports UDP) :
defenseur# ipfw del 100 101 102 103 104
defenseur# ipfw add 100 deny udp from any to me
attaquant# nmap -sS -PT -PI -O -vv -T 3 defenseur
| egrep "^TSeq|^T[1-7]|^PU"
TSeq(Class=TR%IPID=I%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=N)
Encore une fois, la règle utilisée ici est un peu excessive. On aurait pu, par
exemple, se contenter d'un ipfw add 100 deny udp from any to me 1 puisque Nmap
suppose (incorrectement) que le port 1 n'est pas protégé par un pare-feu :
For OSScan assuming that port 22 is open and port 1 is closed and neither are
firewalled
La solution intégrée
En définitive, on remarque que pratiquement tous les tests de Nmap ont recours
à une combinaison d'options très particulière, qu'on ne rencontre que très peu
dans la nature. Il est donc possible de condenser toutes les opérations
précédentes en seulement deux règles :
defenseur# ipfw del 100
defenseur# ipfw add 100 deny tcp from any to me
tcpoptions mss,window,!sack,ts,!cc
defenseur# ipfw add 200 deny udp from any to me 1
attaquant# nmap -sS -PT -PI -O --osscan_guess -vv -T 3 defenseur
Starting nmap V. 3.10ALPHA3 ( www.insecure.org/nmap/ )
Host defenseur appears to be up ... good.
Initiating SYN Stealth Scan against defenseur
Adding open port 22/tcp
Adding open port 587/tcp
Adding open port 25/tcp
The SYN Stealth Scan took 9 seconds to scan 1604 ports.
For OSScan assuming that port 22 is open and port 1 is closed and neither are
firewalled
Insufficient responses for TCP sequencing (0), OS detection may be less
accurate
For OSScan assuming that port 22 is open and port 1 is closed and neither are
firewalled
Insufficient responses for TCP sequencing (0), OS detection may be less
accurate
For OSScan assuming that port 22 is open and port 1 is closed and neither are
firewalled
Insufficient responses for TCP sequencing (0), OS detection may be less
accurate
Interesting ports on defenseur:
(The 1601 ports scanned but not shown below are in state: closed)
Port State Service
22/tcp open ssh
25/tcp open smtp
587/tcp open submission
Too many fingerprints match this host for me to give an accurate OS guess
TCP/IP fingerprint:
SInfo(V=3.10ALPHA3%P=i386-unknown-freebsd4.7%D=11/13%Time=3DD2BFCF%O=22%C=1)
T1(Resp=N)
T2(Resp=N)
T3(Resp=N)
T4(Resp=N)
T5(Resp=N)
T6(Resp=N)
T7(Resp=N)
PU(Resp=N)
Nmap run completed -- 1 IP address (1 host up) scanned in 34.862 seconds
Voilà ! Il y a encore d'autres façons de traiter ce problème (notamment avec
des programmes altérant le fonctionnement de la pile IP), mais je trouve que
ce genre de solution a le mérite de la simplicité (suivant le bon vieux
"principe du bisou"1).
Quelques notes complémentaires
Il existe une option du noyau, RANDOM_IP_ID, qui ne permet d'altérer que le
test TSeq (ce qui la met au même niveau d'efficacité relative que
TCP_DROP_SYNFIN, c'est-à-dire qu'elle empêche l'identification du système par
Nmap sans l'option scan_guess), mais reste malgré tout intéressante en
complément de l'approche par pare-feu :
# more /sys/i386/conf/LINT
# RANDOM_IP_ID causes the ID field in IP packets to be randomized
# instead of incremented by 1 with each packet generated. This
# option closes a minor information leak which allows remote
# observers to determine the rate of packet generation on the
# machine by watching the counter.
Sur un noyau l'intégrant, elle donne ceci :
# nmap -sS -PT -PI -O -vv -T 3 defenseur
Starting nmap V. 3.10ALPHA3 ( www.insecure.org/nmap/ )
[...]
TSeq(Class=TR%IPID=RD%TS=100HZ)
T1(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=E000%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(Resp=Y%DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=0%ULEN=134%DAT=E)
Uptime 0.004 days (since Tue Nov 12 00:33:10 2002)
TCP Sequence Prediction: Class=truly random
Difficulty=9999999 (Good luck!)
TCP ISN Seq. Numbers: 87880010 9AC064AC E3C94638 8914CB4B
IPID Sequence Generation: Randomized
Nmap run completed -- 1 IP address (1 host up) scanned in 30.641 seconds
|