Supposons que l'on souhaite réaliser un fichier de configuration pour émuler un AmigaOS. Pour cela, on dispose de la signature nmap suivante (se référer à la documentation de nmap pour plus de détails) :
Fingerprint AmigaOS AmiTCP/IP 4.3
TSeq(Class=64K)
T1(DF=N%W=1F0E%ACK=S++%Flags=AS%Ops=M)
T2(Resp=N)
T3(Resp=Y%DF=N%W=1F0E%ACK=O%Flags=A%Ops=)
T4(DF=N%W=2000%ACK=O%Flags=R%Ops=)
T5(DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(DF=N%TOS=0%IPLEN=38%RIPTL=15C%RID=E%RIPCK=0%UCK=0%ULEN=134%DAT=E)
Nous devons commencer la configuration par la définition d'un identifiant, comme suit :
id "AmigaOS";
On souhaite réécrire les connexions TCP entrantes dans un premier temps, et ne pas agir sur les tailles de fenêtres (simplement tromper nmap), aussi utilise-t-on des valeurs génériques pour la section tcp.
tcp {
incoming yes;
outgoing no;
max-window 32768;
}
La ligne TSeq de la signature nmap définit le type de générateur de numéro de séquence initial utiliser. Le paramètre important en est la classe du générateur. On peut rencontrer les classes suivantes :
Ici on utilisera donc :
tcp_isn {
type fixed-inc 64000;
initial-value random;
}
Ensuite on trouve l'ensemble des tests TCP effectués par nmap au sein des lignes Tx. La syntaxe de ces lignes est toujours la même et décrit l'éventuelle réponse reçue par nmap à son test.
Tx(Resp=Y%DF=Y%W=XXXX%ACK=S++%Flags=AS%Ops=M)
La signification des différents champs est la suivante :
Si l'on souhaite émuler le système précisément, il faut déduire des différents résultats l'ordre des options à partir des réponses que nmap reçoit et des paquets initiaux auxquels elles correspondent. Ici, on n'a qu'une option donc la section correspondante est assez simple :
tcp_options {
keep-unknown yes;
keep-unused no;
isolated-packets yes;
code {
copy(mss);
}
}
A ce stade le système ressemble un peu à celui émulé. En revanche sur les tests très précis, nos réponses ne statisferont pas nmap. Afin de le tromper complètement en local, on peut déduire des résultats aux tests TCP les réponses à lui retourner au sein du mode decoy. Pour ce faire on utilise un "squelette" de code adapté aux tests de nmap que l'on complète afin de générer les réponses attendues :
tcp_decoy {
code {
if (option(mss)) {
if (listen) {
if (flags(syn&ece)) {
/* nmap test 1 */
}
if (flags(null)) {
/* nmap test 2 */
}
if (flags(syn&fin&urg&push)) {
/* nmap test 3 */
}
if (ack(0) && flags(ack) && !flags(syn|push|urg|rst)) {
/* nmap test 4 *
}
} else {
if (flags(syn) && !flags(ack)) {
/* nmap test 5 */
}
if (ack(0) && flags(ack) && !flags(syn|push|urg|rst)) {
/* nmap test 6 *
}
if (flags(fin&push&urg)) {
/* nmap test 7 */
}
}
}
}
}
Et il n'y a plus qu'à écrire le code pour chaque test, par exemple pour le premier
set(df, 0);
set(win, 0x1F0E);
set(ack, this + 1);
set(flags, ack|syn);
insert(mss, this+1);
reply;
ou pour le second (pas de réponse) :
drop;
Enfin on peut également réagir localement (au sein de la section udp_decoy) au dernier test de nmap, le test UDP port-unreach (PU), qui a la syntaxe suivante :
PU(DF=N%TOS=0%IPLEN=38%RIPTL=15C%RID=E%RIPCK=0%UCK=0%ULEN=134%DAT=E)
La signification des différents champs est la suivante :
Ici, on pourrait donc utiliser ce qui suit :
udp_unreach {
reply yes;
df no;
max-len 56;
tos 0;
mangle-original {
ip-len 348;
ip-id same;
ip-csum zero;
udp-len 308;
udp-csum zero;
udp-data same;
}
}
Il n'y a plus qu'à tester ! Un tel fichier peut par la suite être amélioré et optimisé afin d'être à la fois plus fiable (le réordonnancement d'option et le générateur de numéros de séquence initiaux ne sont pas simples à "deviner") et plus performant (regrouper les tests, etc.).
Afin de démontrer quelques unes des capacités du module IP Personality, plaçons nous dans le cadre de deux réseaux réduits à une machine, reliés via une machine routeur où tourne le module. La configuration esr la suivante :
+---------+ +---------+ +---------+
| suskind |<--------->| dse2 |<--------->| dse1 |
+---------+ +---------+ +---------+
Les systèmes d'exploitation utilisés pour les tests sont sur chacune des machines :
On peut tout de suite vérifier que ces OS sont mutuellement détectables à l'aide de nmap par exemple, à partir de chacune des machines. (on a laissé les détails afin de voir en quoi ils changent par la suite).
Si l'on effectue un nmap de suskind vers dse2 :
TCP Sequence Prediction: Class=random positive increments
Difficulty=2119945 (Good luck!)
Sequence numbers: 59CEAA9C 5987D082 59CC67D4 59598903 5983CC3D 5971B98C
Remote OS guesses: Linux 2.3.49 x86, Linux 2.3.99-pre2 x86
OS Fingerprint:
TSeq(Class=RI%gcd=1%SI=205909)
T1(Resp=Y%DF=Y%W=7C70%ACK=S++%Flags=AS%Ops=MNNTNW)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=7C70%ACK=S++%Flags=AS%Ops=MNNTNW)
T4(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=)
T5(Resp=Y%DF=Y%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=Y%W=0%ACK=O%Flags=R%Ops=)
T7(Resp=Y%DF=Y%W=0%ACK=S++%Flags=AR%Ops=)
PU(Resp=Y%DF=Y%TOS=C0%IPLEN=164%RIPTL=148%RID=E%RIPCK=E%UCK=E%ULEN=134%DAT=E)
On observe le même résultat avec un nmap de dse1 vers dse2.
Si l'on effectue un nmap de dse1 vers suskind :
TCP Sequence Prediction: Class=random positive increments
Difficulty=9819 (Worthy challenge)
Sequence numbers: 3B1E1359 3B1F0409 3B1F9BAB 3B201E56 3B20B8D2 3B217357
Remote operating system guess: FreeBSD 2.2.1 - 3.2
OS Fingerprint:
TSeq(Class=RI%gcd=1%SI=265B)
T1(Resp=Y%DF=Y%W=403D%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=403D%ACK=S++%Flags=AS%Ops=MNWNNT)
T4(Resp=Y%DF=N%W=4000%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=F%RIPCK=F%UCK=0%ULEN=134%DAT=E)
On se donne maintenant 3 fichiers d'émulation de systèmes d'exploitation, soit amigaos.conf, linux.conf, et win9x.conf.
On décide de faire passer dse2 pour une machine windows auprès de suskind. Il suffit d'utiliser les deux ligne suivantes (sur dse2) :
iptables -t mangle -A PREROUTING -s suskind -d dse2 -j PERS --tweak dst \
--local --conf win9x.conf
iptables -t mangle -A OUTPUT -s dse2 -d suskind -j PERS --tweak src \
--local --conf win9x.conf
On décide ensuite de faire passer dse2 pour une machine amiga auprès de dse1. Il suffit de rajouter les deux lignes suivantes :
iptables -t mangle -A PREROUTING -s dse1 -d dse2 -j PERS --tweak dst \
--local --conf amigaos.conf
iptables -t mangle -A OUTPUT -s dse2 -d dse1 -j PERS --tweak src \
--local --conf amigaos.conf
Pour utiliser le rôle de routeur de la machine on veut également modifier la manière dont dse1 voit suskind, en faisant passer suskind pour une machine sous Linux.
iptables -t mangle -A PREROUTING -s suskind -d dse1 -j PERS --tweak src \
--conf linux.conf
iptables -t mangle -A PREROUTING -s dse1 -d suskind -j PERS --tweak dst \
--conf linux.conf
Voyons maintenant ce que donnent les même tests que précédemment (avec nmap).
Si l'on effectue un nmap de suskind vers dse2 :
TCP Sequence Prediction: Class=trivial time dependency
Difficulty=0 (Trivial joke)
Sequence numbers: A97ECB1D A97ECB1F A97ECB21 A97ECB23 A97ECB25 A97ECB27
Remote operating system guess: Windows NT4 / Win95 / Win98
OS Fingerprint:
TSeq(Class=TD%gcd=2%SI=0)
T1(Resp=Y%DF=Y%W=2017%ACK=S++%Flags=AS%Ops=M)
T2(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
T3(Resp=Y%DF=Y%W=2017%ACK=S++%Flags=AS%Ops=M)
T4(Resp=Y%DF=N%W=0%ACK=S++%Flags=R%Ops=)
T5(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(Resp=Y%DF=N%W=0%ACK=S++%Flags=R%Ops=)
T7(Resp=Y%DF=N%W=0%ACK=S++%Flags=AR%Ops=)
PU(Resp=N)
Si l'on effectue un nmap de dse1 vers dse2 :
TCP Sequence Prediction: Class=64K rule
Difficulty=1 (Trivial joke)
Sequence numbers: D997B378 D998AD78 D999A778 D99AA178 D99B9B78 D99C9578
Remote operating system guess: AmigaOS AmiTCP/IP 4.3
OS Fingerprint:
TSeq(Class=64K)
T1(Resp=Y%DF=N%W=1F0E%ACK=S++%Flags=AS%Ops=M)
T2(Resp=N)
T3(Resp=Y%DF=N%W=1F0E%ACK=O%Flags=A%Ops=)
T4(Resp=Y%DF=N%W=2000%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=15C%RID=E%RIPCK=0%UCK=0%ULEN=134%DAT=E)
Si l'on effectue un nmap de dse1 vers suskind :
TCP Sequence Prediction: Class=random positive increments
Difficulty=188907 (Good luck!)
Sequence numbers: 32BD32 393D33 3B87EE 3FE6A3 4AC5E7 4F9533
No OS matches for host (If you know what OS is running on it,
see http://www.insecure.org/cgi-bin/nmap-submit.cgi).
TCP/IP fingerprint:
TSeq(Class=RI%gcd=1%SI=2EF4C)
TSeq(Class=RI%gcd=1%SI=2EF18)
TSeq(Class=RI%gcd=1%SI=2E1EB)
T1(Resp=Y%DF=Y%W=403D%ACK=S++%Flags=AS%Ops=MNNTNW)
T2(Resp=N)
T3(Resp=Y%DF=Y%W=403D%ACK=S++%Flags=AS%Ops=MNNTNW)
T4(Resp=Y%DF=N%W=4000%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=F%RIPCK=F%UCK=0%ULEN=134%DAT=E)
On constate bien que dans le cas de la machine locale dse2 on peut complètement tromper nmap. En revanche en mode "routeur", les paramètres sur lesquels on joue le perturbent, mais ne suffisent pas à lui faire détecter un autre système.