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

 



Le but de cet article est de vous montrer comment les os fingerprint fonctionnent et comment on peut les contrer en simulant d'autres os.

1) C'est quoi un os fingerprint ?


Os fingerprint c'est l'identification du systeme d'exploitation d'une machine distante. c'est un outil utilisé plus par les administrateurs que par des personnes malveillantes. la detection de l'OS d'un systeme distant est une étape majeur pour un attaquant essayant de le compromettre , supposez par exemple que vous avez trouver un port ouvert d'une machine distante cela vous donnera une idée sur le service lancé et le fait de connaitre l'os va faciliter de savoir si ce service est vulnérable donc de coder ou trouver l'exploit équivalent . le principe d'os fingerprint consiste à envoyer des paquets specialement forgés et d'analyser la réponse , ces réponses varient d'un os à autre .

 

 

2) Some Basic methods to detect the remote OS

 

Time to live :

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 .
 

FIN :

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 .
 

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 .

 

 

3) Powerful method to detect the remote OS (nmap)

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 .

 

4) Code Source T-Os fingerprint


Pour une bonne comprehension je vais me contenter de tester juste la methose basique TOS qui fait la difference entre linux et windows .
le programme va envoyer un paquet icmp (echo request type:8 avec le champs TOS différent de 0 dans la source 15) et on va analyser la réponse si le champs ne change pas de valeur la machine distante est un linux sinon ben c'est windows :)

<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,
sizeof(struct sockaddr))==-1) { printf("erreur d'envoi"); } close(sockraw); return(0); } int makeheaderICMP(struct icmphdr *icmp) { icmp->type=8; /* echo request */ icmp->code=0; icmp->un.echo.id=1337; icmp->un.echo.sequence=1337; return(0); } int makeheaderIP(struct iphdr *ip) { int j=0; char ipdest[50]; char ipsource[50]; struct hostent *host; ip->version=4; ip->ihl=5; ip->tos=15; /* type of service */ ip->id=12345; ip->frag_off=htons(16384); ip->ttl=200; ip->protocol=1; printf("entrez ip de la machine dont vous souhaitiez connaitre OS"); scanf("%s",ipdest); printf("entrez votre ip"); scanf("%s",ipsource); host=gethostbyname(ipsource); if(host==NULL) { printf("erreur source host"); exit(1); } memcpy(&ip->saddr,host->h_addr,host->h_length); host=gethostbyname(ipsource); if(host==NULL) { printf("erreur dest host"); exit(1); } memcpy(&ip->daddr,host->h_addr,host->h_length); return(0); } int makeDATA(char *data) { int compteur=0; char caractere; while((caractere=getchar()) != '\n') { compteur++; *data=caractere; data++; } return(compteur); } unsigned short calcule(u_short *addr,int len) { register int nleft=len; register int sum=0; u_short answer=0; while(nleft>1) { sum +=*addr++; nleft -=2; } if(nleft==1) { *(u_char *)(&answer)=*(u_char *)addr; sum +=answer; } sum=(sum >>16)+(sum & 0xffff); sum +=(sum >> 16); answer = ~sum; return(answer); }

 

 

<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);
}
     

 

 

5) Defeating os fingerprint


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);
}

 

 

6) Test

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


HAUT DE PAGE