AFFICHER CET ARTICLE EN MODE PAGE ENTIERE
SOMMAIRE
1) C'est quoi un os fingerprint ?
2) Some Basic methods to detect the remote OS
3) Powerful method to detect the remote OS (nmap)
4) Code Source T-Os fingerprint
5) Defeating os fingerprint
6) Test
Chaque os mets dans le champs ttl du header IP une valeur differentes. par ex: linux : 34-64 windows:98-128 freebsd:34-64 le ttl peut varié parce qu'il se decremente fois chaque que le paquet passe par un routeur .
Time to live :
si on envoie un paquet TCP avec le flag FIN activé sur un port ouvert la machine receptrice devra ignorer le paquet . ce que Windows ne fait pas , il repond avec un ack+rst .FIN :
Window Size :
On remarque quand on envoie un paquet TCP avec le flag Syn que chaque os répond avec un paquet tcp (flag syn ack) et la taille de la fenetre qu'il veut . linux : 32767 windows : 16616 freebsd : 65535
Tos (Type Of Service) :
Normalement dans les paquets ICMP la valeur du TOS doit étre à 0. on remarque qu'on envoie un paquet avec le tos different de 0 , windows le mets à 0 par contre linux le laisse .
Nmap est l'outil le plus utilisé et le plus puissant . nmap fait 8 tests pour detecter l'os et compare les resultats avec une base de donnée. On peut remarquer la precision de cet outil puique il ne s'arette pas sur la detection de l'os mais il trouve la version du noyau.
Description des tests :
# T1 est un paquet SYN avec des options à un port ouvert
# T2 est un paquet NULL avec des options à un port ouvert
# T3 est un paquet SYN|FIN|URG|PSH avec des options à un port ouvert
# T4 est paquet ACK avec option à un port ouvert
# T5 est un paquet SYN à un port ouvert avec options
# T6 est un paquet ACK à un port ouvert avec options
# T7 est un paquet FIN|PSH|URG à port fermé avec options
# PU est un paquet UDP à un port fermé
Prenons ce firewall :
Fingerprint Borderware 6.0.2 firewall
Class Borderware | embedded || firewall TSeq(Class=RI%gcd=<6%SI=<1016FC&>291C) T1(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(DF=N%W=4000%ACK=O%Flags=R%Ops=) T5(Resp=N) T6(Resp=N) T7(Resp=N) PU(Resp=N) |
T1 : il repond avec le champs ack = ack+1 ,la taille de la fenetre 403D ,les flags ACK SYN activés et les options à cet ordre MNWNNT .
T3 : champs ack = ack+1 , le bit "DONT FRAGMENT" positionné ,la taille de la fenetre 403D ,les flags ACK SYN activés et les options à cet ordre MNWNNT .
T4 :ack =0 , la taille de la fenetre 4000 ,le flags RST activé , pas d'options .
Le firewall ne repond pas aux autres tests .
<send.c> fonction send() qui envoie le paquet icmp ECHO_REQUEST
#include stdio.h
#include string.h
#include stdlib.h
#include unistd.h
#include stdarg.h
#include netinet/ip.h
#include netinet/ip_icmp.h
#include netinet/in.h
#include sys/time.h
#include sys/types.h
#include sys/socket.h
#include netdb.h
struct paquet_icmp
{
struct iphdr partieIP;
struct icmphdr partieICMP;
char icmpdata[4096];
};
int sendpacket()
{
struct paquet_icmp *icmppaquet;
struct sockaddr_in sock;
int sockraw,i,tailleDATA;
int calccheckICMP=0;
icmppaquet=(struct paquet_icmp *)malloc(sizeof(struct paquet_icmp));
bzero(icmppaquet,sizeof(struct paquet_icmp));
makeheaderIP(&icmppaquet->partieIP);
makeheaderICMP(&icmppaquet->partieICMP);
tailleDATA=makeDATA((char *)&icmppaquet->icmpdata);
icmppaquet->partieICMP.checksum=calcule((unsigned short *)&icmppaquet->partieICMP,sizeof(struct icmphdr)+tailleDATA);
sockraw=socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
sock.sin_family=AF_INET;
sock.sin_addr.s_addr=icmppaquet->partieIP.daddr;
if(sendto(sockraw,icmppaquet,sizeof(struct icmphdr)+sizeof(struct iphdr)+tailleDATA,0,(struct sockaddr *)&sock, |
<checkos.c> fonction principal checkos()
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netdb.h
#include linux/if.h
#include stdio.h
#include arpa/inet.h
#include linux/socket.h
#include linux/ip.h
#include linux/icmp.h
#include linux/if_ether.h
#include sys/ioctl.h
#include sys/stat.h
#include fcntl.h
int sconnect(char *device)
{
int fd;
int s;
fd=socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
if(fd < 0)
{
perror("cant get SOCK_PACKET socket");
exit(0);
}
return fd;
}
int checkos(int mytos)
{
int sock, octets_recus, lendata, j, i=0;
unsigned char *so, *dest;
struct recvpacquet
{
struct ethhdr eth;
struct iphdr ip;
struct icmphdr icmp;
char data[8000];
} buffer;
struct iphdr *ip;
struct icmphdr *icmp;
char *data;
ip=(struct iphdr *)(((unsigned long)&buffer.ip)-2);
icmp=(struct icmphdr *)(((unsigned long)&buffer.icmp)-2);
sock = sconnect("eth0");
sendpacket();
while(1)
{
octets_recus = read(sock, (struct recvpacquet *)&buffer, sizeof(struct recvpacquet));
if(ip->protocol==1 && icmp->type==0) /* paquet echo reply (icmp;)*/
{
if(ip->tos==0)
{
printf("l'os de la machine est windows \n");
}
else if(ip->tos==mytos)
{
printf("l'os de la machine est Linux \n");
}
else{ printf("unknow os\n");}
break;
}
}
}
int main()
{
checkos(15);
return(0);
}
|
Dans cette partie on va essayer de vous montrer une methode pour simuler d'autres machines sur votre os . Comme mentionné plus haut pour une comprehension facile on va essayer de contrer le T-os fingerprint .
Principe :
on va essayer de faire simuler un windows sur linux .
Notre T-os fingerprint envoie un paquet icmp avec TOS different de 0 normalement quand notre machine (linux) le recois et elle va pas toucher au TOS , ce qu'on doit faire c'est d'essayer de réinialiser le Tos à 0 .
par exemple pour les tests Taille de fenetre et TTL il suffira de modifier pour chaque : la taille de la fenetre -> 16616 (voir plus haut) , le TTL -> 128 .
le seul moyen que j'ai trouvé c'est d'utiliser iptables :
Iptables:
IpTables est une solution complète de firewall (noyau 2.4) remplaçant ipchains (noyau 2.2) tournant sous le système GNU/Linux. IpTables permet de faire du firewalling stateful (à états), de la translation de port et d'adresse, du filtrage au niveau 2 et beaucoup d'autres choses que nous n'allons pas aborder.
la table utilisé par défaut c'est la table FILTER . elle contient tous les règles de filtrage, il existe 3 types de chaînes : FORWARD pour les paquets passant par le firewall, INPUT pour les paquets entrant et OUTPUT pour les paquets sortants. Les cibles disponibles sont : ACCEPT(accepté), DENY(refusé), DROP(supprimé) ,QUEUE.
Les commandes de bases et dont on a besoin :
-A --append Ajout de régle :
# iptables -A INPUT ...
-D --delete : Permet de supprimer une régle:
# iptables -D INPUT ...
-p --protocol : Spécifier un protocole : tcp, udp, icmp, all (tous)
Exemple :
# iptables -A INPUT -p icmp -j DENY
la régle qu'on a besoin c'est :
#iptables -A OUTPUT --proto icmp -j QUEUE
cette regle va rediriger les paquets icmp vers notre programme (espace user) qui va modifier les paquets .
on va utiliser la librairie IPQ pour manipuler les paquets .
Voici les principaux fonctions qu'on va utiliser :
- ipq_read elle sert à lire les packets mis en queue .
- ipq_message_type sert à connaitre le type du message (paquet,erreur,...). Ce qui nous interesses c'est IPQM_PACKET.
-ipq_set_verdict elle renvoie au kernel :
__NF_ACCEPT - accepté le paquet .
__NF_DROP - supprimé le paquet
Donc notre programme va modifier les paquets en reinialisant le champs Tos à 0 et recalculer le checksum du header IP ;).
<antitos.c> - la fonction qui recupere les paquets de la queue et les modifie
#include stdio.h
#include string.h
#include netinet/in.h
#include linux/netfilter.h
#include linux/ip.h
#include linux/icmp.h
#include libipq/libipq.h
#define BUFSIZE 65536
unsigned char buf[BUFSIZE];
u_short in_chksum(u_short *ptr, int nbytes)
{
register long sum;
u_short oddbyte;
register u_short answer;
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_char *) &oddbyte) = *(u_char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return((u_short) answer);
}
void scan_queue()
{
int len,status,loop,nplen;
struct ipq_handle *h;
ipq_packet_msg_t *m;
/* Initialisation de la connexion */
h = ipq_create_handle(0, PF_INET);
if (!h)
return (0);
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0)
return (0);
do {
len = ipq_read(h, buf, BUFSIZE, 0);
switch (ipq_message_type(buf)) {
case IPQM_PACKET:
m = ipq_get_packet(buf);
struct iphdr *iph = ((struct iphdr *)m->payload);
iph->tos=0;
memset(&iph->check,0,2);
iph->check=in_chksum((u_short *)iph,iph->ihl*4);
status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, m->data_len, m->payload);
break;
default:break
}
} while (loop);
ipq_destroy_handle(h);
}
int main(int argc, char **argv)
{
scan_queue();
return(0);
}
|
On compile l'T-os fingerprint :
root@ttyp1[Desktop]# make gcc checkos.o send.o -o fingerprint |
On active la régle iptables et on compile le packet remaker :)
root@ttyp0[Desktop]# modprobe ip_tables root@ttyp0[Desktop]# modprobe ip_queue root@ttyp0[Desktop]# iptables -A OUTPUT --proto icmp -j QUEUE root@ttyp0[anti os fingerprint]# make make: `remaker' is up to date. |
On lance T-os finger print
root@ttyp1[Desktop]# ./fingerprint entrez ip machine dest 127.0.0.1 entrez ip de votre machine 127.0.0.1 l'os de la machine est Linux |
Maintenant on lance notre packetremaker
root@ttyp0[anti os fingerprint]# ./antitos |
On relance le fingerprinter dans un autre terminal
root@ttyp1[Desktop]# ./fingerprint entrez ip machine dest 127.0.0.1 entrez ip de votre machine 127.0.0.1 l'os de la machine est windows |
Ca marche :) , on a reussit a faire croire au programme T-os fingerprint que l'on est sous windows.
J'espere que vous avez compris comment fonctionne les os-fingerprinter et comment on peut developper un anti one :). Je suis entrain de coder l'anti-nmap finger print,c'est presque fini, c'est vrai que c'est plus compliqué que ce qu'on a fait mais le principe reste le meme . Je le termine je le commente dans le prochain article...
Have fun !
BY DEEPFEAR
Copyright © 2005 ARENHACK - DHS