Blog Haypo

Aller au contenu | Aller au menu | Aller à la recherche

dimanche 13 juillet 2008

Mon poste de travail

Je suis devant mes ordinateurs de 8h jusqu'à plus de 16h certains jour. Mon poste de travail est donc critique. Je vous invite pour une petite visite, voir l'antre depuis lequel je télétravaille.

Bien sûr, j'ai tout rangé pour la photo :-) La chaise avec dossier en cuir est rigide et s'incline quand je me penche en arrière. Les pieds du bureau sont dans les coins, donc en pratique, j'ai énormément d'espace pour les jambes. L'imprimante dans un coin est une imprimante laser noir et blanc : HP LaserJet 2015. Elle est parfaitement compatible Linux, imprime la première page en 8,5 secondes et les suivantes suivent immédiatement. La machine à café, Magimix de Nespresso, n'est pas compatible Linux mais produit un excellent café :-)

J'utilise deux écrans en 1280x1024 pixels côte à côte, chacun branché sur un ordinateur différent : un portable (écran au fond en jaune) et un fixe (fond bleu). C'est des écrans LCD 17 pouces que je trouve agréables. Je n'ai pas réellement noté de différence avec un écran CRT... mis à part l'encombrement : les écrans prennent juste 5 cm en profondeur, ce qui laisse toute la place à mes bras.

Grâce à Synergy, je n'utilise qu'un seul couple clavier-souris pour les deux ordinateurs. Il suffit de passer le curseur de la souris sur le bord de l'écran pour changer de machine. Le copier-coller fonctionne dans les deux sens, même quand j'utilise Windows sur une des machines. Le clavier est un Logitech UltraX : sensisble, silencieux et assez lourd pour être stable. Je voulais essayer un clavier « plat » et j'en suis plutôt satisfait, c'est agréable.

Ma souris n'est pas une souris mais une trackball : Logitech Cordless Optical TrackMan. Ce périphérique épouse la forme de la main. C'est beaucoup plus reposant qu'une souris, les muscles sont moins contractés.

J'ai toujours une souris (secondaire) dans un coin pour Gimp ou quand la trackball m'énerve. Effectivement, une trackball est moins précise qu'une souris, en particulier pour cliquer sur une zone de 10x10 pixels ou moins. Exemples : fermer une fenêtre en cliquant sur la croix, case à cocher dans un formulaire web, sélectionner une ligne de texte dans une page web ou document PDF, etc. Je redécouvre l'ergonomie par la pratique :-)

Pour finir, la déco. En face, un poster de Gilles Tran (Main Street (West)), à côté une peinture de Dalí (Une femme à la fenêtre), et à gauche un poster de Gaston dessiné par Franquin ramené du musée de la bande dessinée de Bruxelles :

Fin de la visite, n'oubliez pas le guide (laissez un commentaire ;-)).

mercredi 9 juillet 2008

Publication de Fusil le fuzzer version 0.9, fuzzing de CPython et de PyPy

Fuzzer Python

Suite à ma conférence sur l'assurance qualité et fuzzing aux RMLL, je me suis remis à jouer avec mon fuzzer Fusil. Dans le TGV retour, 8h quand même pour rentrer à Strasbourg, j'ai écrit un fuzzer pour le langage Python. L'idée est de récupérer la liste des fonctions, classes et méthodes d'une module, et les appeler/instancier avec un nombre d'arguments aléatoires de type aléatoire. Comme je m'y attendais, une fois le fuzzer python écrit, CPython 2.5 a rapidement planté : erreur de segmentation dans le module imageop.

Rapports de bugs Python 2.6

Pour écrire un rapport de bug correct, j'ai reproduit les bugs avec la version trunk (futur CPython 2.6) compilée avec l'option pydebug et... mince, ça plante plus : le bug imageop est déjà corrigé. J'ai donc amélioré le fuzzer pour qu'il ne teste non plus uniquement un seul module, mais toute une liste de modules (j'ai noté ceux écrits en langage C), et j'ai rajouté d'autres types d'argument (nombre flottant, objet, unicode, etc.). Voilà CPython qui plante, ouf, l'honneur du fuzzing est sauf :-) J'ai alors rapporté une quinzaine de bugs (cherchez les bugs rapportés entre le 6 et le 9 juillet), à chaque fois accompagné d'un patch et d'un exemple pour reproduire le crash. Deux patchs sont déjà appliqués.

Publication de Fusil 0.9

Pour fêter ce succès, j'ai publié la version 0.9 de Fusil. Cette nouvelle version contient le nouveau fuzzer pour Python, peut s'exécuter dans l'interprète Python PyPy, gère mieux le logging (sortie plus concise mais contient le nombre de crash et un fichier project.log est conservé dans le dossier du projet), et l'outil IncrMangle est plus rapide et précis.

Fuzzing de PyPy

Enfin, j'ai fuzzé un peu PyPy, mais le seul vrai bug que j'ai trouvé est dans un module que j'ai écrit (module pwd écrit avec ctypes) ! Par contre, Carl (cfbolz sur le salon IRC #pypy du serveur Freenode) a trouvé d'autres bugs dans PyPy en utilisant Fusil.

Classement des interprètes Python

Pour résumer, vu les résultats face aux tests de fuzzing, on peut classer la qualité des interprètes Python comme ceci : CPython 2.5 < CPython trunk << PyPy où << veut dire très supérieur. Effectivement, je n'ai trouvé qu'un seul bug PyPy après une nuit de fuzzing contre une quinzaine dans CPython rapidement détectés.

jeudi 19 juin 2008

Améliorer la ligne de commande

En dehors des raccourcis claviers que j'avais déjà abordé, il existe énormément d'astuces pour améliorer la ligne de commande sous Linux. En voici quelques unes pour gagner encore plus de temps avec la ligne de commande.

Complétion avancée

La touche TAB sert à compléter automatiquement les commandes. C'est diablement efficace, mais bash peut faire mieux ! En chargeant /etc/bash_completion, la complétion dépendra du programme utilisé. « kpdf <tab><tab> » n'affichera que les fichiers PDF (et les répertoires). « apt-get install python-<tab><tab> » affiche les paquets Debian installables dont le nom débute par « python- ». Pour l'activer la complétion avancée, ajoutez dans votre ~/.bashrc :

source /etc/bash_completion

Le chargement de bash sera plus long, mais vous serez beaucoup efficace avec votre ligne de commande !

Ignorer les doublons dans l'historique

Par défaut, bash conserve toutes les commandes tapées. J'ai présenté dans mon billet précédent la variable d'environnement HISTIGNORE pour ignorer certains commandes. Pour ne pas sauver un commande saisie plusieurs fois, utilisez :

export HISTCONTROL=ignoredups

Rappel : CTRL+r permet de rechercher une commande déjà tapée en en saisissant quelques lettres.

Utiliser most plutôt que less pour lire du texte

Pour lire un fichier texte, il existe le programme more qui n'est pas très pratique. Le programme less est mieux : il permet de revenir en arrière, rechercher du texte, etc. Il existe encore mieux ! most utilise des couleurs (meilleur rendu des pages de manuel), permet de découper l'écran en plusieurs vues indépendentes, etc. Lisez l'aide intégrée pour les détails. Installez-le avec « apt-get install most » et choisissez-le par défaut en ajoutant dans votre fichier de configuration ~/.bashrc :

export PAGER=most

Activer les couleurs

Plusieurs programmes permettent d'afficher des couleurs mais ne le font pas par défaut pour des raisons de compatibilité avec les anciens terminaux. Activez les couleurs avec :

alias ls='ls --color=auto'
alias grep='grep --color'
alias egrep='egrep --color'

Tailles de fichier avec des unités humaines

L'option « -h » permet d'afficher les tailles avec des unités plus facilement compréhensibles par un humain (19 Ko, 367 Mo, 1 Go, ...) :

alias du='du -h'
alias df='df -h'

La commande ls supporte également l'option.

Passer en mode verbeux

Par défaut, les programmes sont silencieux : ils ne disent pas ce qu'ils font. Or c'est pratique pour vérifier qu'on a bien fait ce qu'on voulait. Aliases pour activer le mode verbeux :

alias ln='ln -v'
alias cp='cp -v'
alias mv='mv -v'
alias rm='rm -v'

Personnaliser l'invite

L'invite est le court texte invitant à saisir une commande, du style « haypo@marge:~$ ». C'est la variable d'environnement PS1 qui contient l'expression pour générer cette invite. « \u » est remplacé par le nom d'utilisateur, « \h » le nom de la machine, « \w » le répertoire de travail, etc.

Je n'aime pas du tout avoir une invite qui contient le répertoire de travail car l'invite prend rapidement toute la largeur de l'écran. J'utilise donc une invite qui ne contient que le nom de la machine :

export PS1='\h$ '

C'est rudimentaire mais efficace. La commande « pwd » me sert à me rappeler où je suis quand je me perd ;-)

Voilà, j'espère que je vous ai appris des trucs, n'hésitez pas à m'en apprendre d'autres en déposant un commentaire !

Éviter les opérations dangereuses en ligne de commande

L’erreur est humaine, mais pour provoquer une vraie catastrophe, il faut un ordinateur.

Quand on passe trop de temps dans la ligne de commande, on a tendance à oublier qu'on manipule des documents importants et qu'au détour d'une commande on peut les éradiquer à tout jamais ! Voici quelques astuces pour limiter la casse : lignes à ajouter dans votre configuration « ~/.bashrc ».

Option -i pour demander confirmation

Alias qui rajoutent l'option -i sur les opérations dangereuses :

alias ln="ln -i -v"
alias cp='cp -i -v'
alias mv='mv -i -v'
alias rm='rm -i'

Vous pouvez également utiliser l'option -k de tar pour éviter d'écraser les fichiers existant :

alias tar='tar -k'

Option -C de bash

Bash possède une option -C pour interdire les redirections vers un fichier existant :

set -C

Exemple au pif : ça arrive qu'on tape « echo "user:password:" >/etc/passwd » alors qu'on voulait écrire « >>/etc/passwd » :-)

Configurer l'historique

Bash permet de ne pas mettre une commande dans l'historique (touche haut ou CTRL + r) avec la variable HISTIGNORE :

# Ignore commands like:
#  >konsole&<
#  any command starting with a space (eg. " sudo touch /tmp/x")
#  >bg<
#  >fg<
#  >exit<
#  >svn revert*<
#  >hg revert*<
#  >*rm *<   (eg. "svn rm file", "rm -rf dir", ...)
#  >tee *<
export HISTIGNORE='*&: *:[bf]g:exit:*>|*:history*:svn revert*:hg revert*:*rm *:tee *'

Du coup, si vous tapez une commande que vous savez délicate, précédez la d'une espace pour éviter qu'elle soit sauvée (merci acatout pour l'astuce !).

mardi 10 juin 2008

Usage des générateurs de nombres pseudo-aléatoires

Exigences vis à vis d'un générateur de nombres pseudo-aléatoires

Les générateurs de nombres pseudo-aléatoires sont utilisés principalement à deux fins :

  • Simulation : simulation physique, jeux vidéos, etc.
  • Sécurité : générer un secret pour garantir la confidentialité

Dans les deux domaines, la qualité du générateur est importante. Si un générateur est biaisé, c'est-à-dire que la distribution n'est pas équitable entre les différentes valeurs possibles, le résultat de la simulation sera invalide (ou bien simplement imprécis) et la confidentialité peut être comprise. Par contre, la simulation privilégie la vitesse du générateur. Alors que pour la sécurité on se donne les moyens pour qu'il soit difficile de deviner les nombres précédemment générés et les prochains nombres générés (quitte à ce que le générateur soit plus lent), ce qui revient à deviner quel est l'état interne du générateur étant donné qu'un algorithme est déterministe.

Générateur biaisé

Reprenons l'exemple de RANDU, un générateur biaisé (les bits de poids faible sont peu aléatoires). Si on utilise 1 + rand() % 6 pour simuler un lancé de dé, on va obtenir une suite du genre :

  1, 3, 1, 5, 3, 3, 1, 5, ...

Les faces 2, 4 et 6 ne sont jamais tirées !

Inverser un générateur congruentiel linéraire

Il est possible de deviner l'état interne d'un générateur congruentiel linéraire (LCG) en ne connaissant qu'un seul nombre généré. L'algorithme RANDU est :

  x(n+1) = (x(n) * 65539) % 2147483648

Avec x(0) : graine du générateur. On peut exécuter le générateur à l'envers en calculant :

  y(n+1) = (y(n) / 65539) % 2147483648

Sachant que diviser revient à multiplier par l'inverse, x / 65539 <=> x * (1 / 65539), on va calculer l'inverse 65539 modulo 2147483648 avec le théorème des restes chinois. En pratique, on utilise l'identité de Bezout. Fonction Python qui calcule les coefficients u et v tels quel a · u + b · v = 1 :

def bezout(a, b):
  u0 = 1; u1 = 0
  v0 = 0; v1 = 1
  while 1:
    q = a // b
    r = a % b
    u0, u1 = u1, u0 - q*u1
    v0, v1 = v1, v0 - q*v1
    if r != 0:
      a = b
      b = r
    else:
      break
  return (u0, v0)

On calcule alors bezout(65539, 2147483648) = (477211307, -14564), ce qui donne :

  65539 · 477211307 - 2147483648 · 14564 = 1

et

  (477211307 * 65539) % 2147483648 = 1

Finalement, y(n+1) = (y(n) * 477211307) % 2147483648.

Exemple :

 x(0) = 42
 x(1) = 2752638
 x(2) = 16515450
 x(3) = 74318958

On utilisant x(3), on va pouvoir générer les nombres précédents :

 y(0) = 74318958
 y(1) = 16515450
 y(2) = 2752638
 y(3) = 42

On a donc réussi à retrouver les nombres précédents jusqu'à la graine (42). Même si le générateur ne délivre que quelques bits de son état interne (ex: rand() = x(n) & 0xffff), on peut retrouver l'état interne en utilisant une recherche exhaustive (si on dispose de quelques nombres successifs).

Solutions

Pour rééquilibrer la distribution d'un générateur, on peut l'améliorer en utilisant différrentes techniques :

Lire la RFC 1750 pour les sources et les détails sur ces techniques.

Pour empêcher qu'un pirate arrive à deviner l'état interne du générateur, on peut rajouter une fonction de hachage sur la sortie du générateur (ex: MD5, SHA-1, ...). Il est toujours possible d'inverser la fonction de hachage, mais c'est beaucoup plus difficile !

lundi 9 juin 2008

Développement de la bibliothèque Hasard

Suite au bug OpenSSL de Debian, je me suis à nouveau intéressé de près aux générateurs de nombres pseudo-aléatoires (PRNG). J'ai commencé à écrire la bibliothèque Hasard qui contient plusieurs algorithmes pour générer des nombres et des fonctions de haut niveau : int(min, max), bool(), bytes(size), etc.

Outils ENT et Dieharder

J'ai utilisé le programme ENT pour tester la qualité des algorithmes. ENT utilise :

ENT n'accepte en entrée que des fichiers contenant des octets (pseudo-)aléatoires. On ne peut donc pas tester la qualité d'un générateur de nombre flottants par exemple. Exemple de sortie (algorithme RANDU avec l'opérateur pow2(8)) :

Entropy = 6.000000 bits per byte.

Optimum compression would reduce the size
of this 262144 byte file by 25 percent.

Chi square distribution for 262144 samples is 786432.00, and randomly
would exceed this value 0.01 percent of the times.

Arithmetic mean value of data bytes is 126.0000 (127.5 = random).
Monte Carlo value for Pi is 2.999862669 (error 4.51 percent).
Serial correlation coefficient is 0.322338 (totally uncorrelated = 0.0).

Il existe également le programme Dieharder qui accepte en entrée des nombres de 32 bits non signés dans un fichier binaire ou un fichier texte. Il utilise des tests bien plus rigoureux, mais comme je ne sais pas les interpréter, je ne vais pas commenter.

Représentation visuelle

C'est pas très rigolo tout ça, alors voyons un peu des dessins et schémas qui permettent de distinguer le bon chasseur du mauvais chasseur. Image générée à partir des 8 bits de poids faible de l'algorithme RANDU :

Chaque pixel utilise une valeur du générateur comme couleur. On voit clairement que l'algorithme n'est pas du tout aléatoire ! Pour reproduire l'image :

$ cd tests
$ ./gen_files.py --rng=randu --op=pow2 --bits=8 randu.dat
$ ./draw_pil.py --width=300 --height=300 randu.dat

Une autre façon de représenter des nombres est d'utiliser un axe 2D avec x=random() et y=random() :

On voit qu'il existe très peu de combinaisons (x, y) : j'en dénombre 16. Pour reproduire cette image :

$ ./gnuplot.py randu.dat --point=2

La page web graphics présente d'autres images.

Script de tests de la bibliothèque Hasard

Le script gen_files.py génère un fichier au format texte plat qui contient les nombres générés par l'algorithme RANDU pour l'opérateur pow2(8) (génère un nombre dans l'intervalle [0; 255]). Lire file_format.rst pour voir le format de ce fichier. Le script file_info.py calcule l'entropie des nombres générés, la valeur maximale et la valeur minimale.

$ ./file_info.py randu.dat
Engine: randu
Seed: linux_urandom
Range: 0..255
Operation: pow2
Count: 262144
Minimum: 1
Maximum: 251
Entropy: quality=75.00%, value=6.0000/8.0000

On voit que seul 6 bits sur 8 sont réellement aléatoires (2 bits sont invariants) et que l'intervalle annoncé est incorrect : 0..255 versus 1..251.

J'aime bien l'algorithme RANDU car il est vraiment mauvais et il permet donc de tester l'outillage de test :-)

Pour la suite

Ma bibliothèque est encore en chantier. J'ai beaucoup travaillé sur l'outillage pour tester la sortie des algorithmes en comparant avec d'autres bibliothèques comme Python, PHP ou la libc. La version 0.2 n'inclut par encore ce travail, ça sera le cas pour la prochaine version 0.3 qui n'est pas encore publiée. En attendant, vous pouvez utiliser le dépôt Mercurial.

Je ne sais pas trop ce qu'Hasard va donner au final, mais en tout cas ça avance :-)

jeudi 8 mai 2008

Pycon FR : les Journées Python Francophones édition 2008 (JPF08)

Comme l'année passée, je participe aux Journées Python Francophones organisées par l'AFPy à Paris (à la Cité des Sciences et de l'Industrie pour être exact). Contrairement aux conférences telle que Blackhat où l'entrée coûte plusieurs milliers d'euros, Pycon FR est entièrement gratuit !

Pour les gens qui ne peuvent pas se rendre à Paris ou qui sont déjà pris ce week-end là, aucun soucis ! Les conférences seront diffusées en direct sur Internet (ils ont pensé à tout). Elles seront très certainement disponibles en téléchargement un peu plus tard.

Au niveau du programme, je vous laisse le consulter vous même. Je donne une conférence sur l'interprète PyPy et une autre sur Python 3000. Il faudrait d'ailleurs que je commence à les préparer... Pour l'anecdote, j'ai deux collègues INL qui donnent des conférences (seb et misc) :-)

Pycon FR est aussi l'occasion de rencontrer des programmeurs Python et de discuter autour d'un café ou d'une bière. Alors, viendez !

mercredi 9 avril 2008

Traitement d'image

Maintenant que j'ai écrit combien je suis indigné de la retouche photo, je vais vous présenter quelques outils de traitement d'image impressionnants :-)

Morphing de visage en 3D (1999)

Exemple de modification du visage de Tom Hanks à partir d'une seule photo (1) :

Scale2x (2001)

  • Auteur : Andrea Mazzoleni
  • Utilisation : Agrandir 2 ou 4x la résolution (en pixels) d'anciens jeux de faible résolution (typiquement 320x200 pixels en 16 ou 256 couleurs)
  • Site internet : Scale2x
  • Démonstration : Scale2x, Scale4x

Exemple de l'algorithme Scale2x :

Interactive Digital Photomontage (2004)

  • Auteurs : Aseem Agarwala, Mira Dontcheva, Maneesh Agrawala, Steven Drucker, Alex Colburn, Brian Curless, David Salesin, Michael Cohen
  • Site Internet : Interactive Digital Photomontage
  • Utilisations :
    • Créer une photo de famille où tout le monde souri à partir de plusieurs photos
    • Supprimer des personnes et objets pour créer une photo de paysage ou monument « propre »
    • Augmenter la profondeur de vue d'une photo macro (pris à quelques centimètres d'une plante ou animal)
    • Créer un panorama
    • Corriger l'éclairage d'un objet
  • Publication : Interactive Digital Photomontage (mai 2004)

Exemple de montage tronqué et simplifié (j'ai apposé moi même les marques vertes et rouges pour mieux comprendre) pour créer une photo de famille où tout le monde est heureux :

GREYCstoration (2006)

Exemple tronqué de la suppression de la cage d'un perroquet :

Seam Carving for Content-Aware Image Resizing (2007)

Exemple de réduction de la hauteur d'une photo d'un port (j'ai réduit l'ensemble avec un redimensionnement cubique pour que ça tienne dans le blog) :

Je n'ai présenté que quelques outils que je connais. Il en existe sûrement d'autres encore plus puissant ! Bientôt Blade Runner sera la réalité...

On nous cache tout, on nous dit rien !

On nous cache tout, on nous dit rien
Plus on apprend plus on ne sait rien
On nous informe vraiment sur rien

... chantait Dutronc en 1966. Et bien, il avait plutôt raison et ça ne fait qu'empirer. Pour commencer, voici deux exemples frappants :

À gauche (Curves Cereal: The Lid Said Flesh Tone) la couleur de peau change au niveau du nombril, alors qu'à droite (Parenting: All The Fun Is In The Top Half) un bébé n'a pas de bas ventre ! Ces photos sont extraites de l'excellent blog Photoshop disasters qui liste les pires photos retouchées par le logiciel Adobe Photoshop. Retoucher une photo (modifier la réalité) n'est jamais fait au hasard. Parfois, c'est pour retirer quelques détails disgracieux du visage ou du corps, dans le but de rendre beau. Rappelez vous l'histoire du magazine Paris Match qui a gommé les bourrelets du président Sarkozy (article du journal Libération, août 2007) :

Sans parler de retouche, la publicité a tendance à faire de très belles photos, parfois bien différentes de la réalité. Exemple avec le site Pundo 3000 qui compare la photo sur l'emballage (est-ce qu'il y a une mention non contractuelle écrit en tout petit ?) et le produit une fois déballé :

Je vous conseille également le page Fast Food: Ads vs. Reality. La retouche sert également à des fins politiques ! L'UMP a par exemple fabriqué de fausses preuves pour contrer les verts qui proposent de taxer les automobilistes utilisant le périphérique de Paris (L'UMP d'Ile-de-France a besoin d'une formation à Photoshop, janvier 2008) :

La retouche photo est beaucoup plus vieille que Photoshop (qui lui date de 1980). Le livre Le commissariat des archives d'Alain Jaubert (ISBN: 9782736000479) contient des photos retouchées de Lénine, Staline, Mao Zedung, Mussolini, et d'autres... À l'occasion, je scannerai peut-être quelques exemples.

lundi 10 mars 2008

Un nouvel antispam pour ce blog !

Dans le plus pur respect du syndrôme NIH, j'ai écrit mon outil de détection de spam pour les commentaires Dotclear : antispam. Je sens que rien que le nom vous fait déjà trépigner d'impatience.

Système de notation

Je me suis inspiré de mon travail sur la notation dans le projet Fusil pour noter les commentaires, ce qui n'a rien de révolutionnaire en soit (SpamAssassin le fait déjà). J'ai écrit des règles empiriques selon mes observations sur les spams. L'idée est de rechercher les caractéristiques typiques des spams puis de les transformer en règles.

Voici les règles utilisées actuellement :

  • Adresse de courriel : liste blanche/noire pour les domaines, voir conf/email_domains.txt (liste noire par défaut)
  • Mots clés : recherche de mots clés à partir d'une liste blanche/noire, voir conf/words.txt (liste noire par défaut)
  • Ratio des lettres latines majuscules et du nombre total de lettres latines : s'il y a plus de 35% de majuscules, le message gagne 5 points
  • Longueur du texte : si le texte hors liens externes contient moins de 30 lettres latines, le message gagne 2 points
  • Ratio d'url par domaine : s'il y a plus de 3 liens vers le même domaine (en moyenne), le message gagne 5 points
  • Pour chaque url, une liste blanche/noire (plutôt liste blanche) permet d'attribuer un score selon le domaine. Si l'url ne correspond à aucun domaine, elle obtient une note de +1 point

Finalement, j'utilise peu de règles pour éviter les faux-positifs (message légitime détecté comme spam). Ce n'est pas nécessaire car je n'ai pas encore vu passer de faux-positif.

Résultat sur les commentaires de ce blog

En utilisant un score initial de -3, les commentaires légitimes ont une note négative entre -3 et -2. Pour les spams, j'ai observé trois types selon la note moyenne :

  • (A) note de 0,5 à 2 : un ou deux liens, message court, texte crédible en anglais
  • (B) note de 15 à 25 : une dizaine de liens vers le même serveur avec quelques mots anglais aléatoires
  • (C) note de 150 à 200 : grosse collection de liens et liste presque exhaustive des mots clés que j'ai mis en liste noire (ex: une vingtaine de variantes de « buy cheap viagra » dans le même message)

Les spams de type (B) et (C) sont triviaux à détecter. Les plus pénibles étant les spams de type (A).

Exemple de spam pénible

Commentaire reçu aujourd'hui, j'ai remplacé les urls par xxx :

Author: brazilian <thongwaxingbrazilian@mail.com>
Website: http://xxxxxxxxx.nl/35424
IP: 218.16.224.243

- she reached for her clit. madam, i ve got arthritis,
<a href=  http://xxxxxxx.com/phpbb/barthololauries.html >waxing thong brazilian</a> and.

Le message contenait aussi deux caractères Unicode invalides (U+0092 et U+0093). Analyse avec la configuration actuelle d'antispam pour ce blog :

Match URL (+1.0): http://...
Match URL (+1.0): http://...
Match email domain (+1.0): mail.com
-stdin- score: +0.00

Le message n'est pas détecté comme spam. J'ai donc ajouté les mots clit, brazilian, thong et waxing en liste noire pour gonfler la note jusqu'à +7.

Fiabilité de l'antispam

Après une semaine de développement sur antispam, je suis plutôt content du résultat. Bien que cet outil demande beaucoup de configuration manuelle, il supprime déjà environ 90% du spam de ce blog. Sachez que je reçois à peu près 100 spams par jour sur ce blog.

L'ancien moteur de spam était fiable à 100% : il bloquait simplement tout message contenant un lien externe. J'essaye de le rendre un peu plus laxiste pour autoriser les liens externes.

Amélirations possibles

Idée pour améliorer antispam :

  • Réutiliser du code (au moins des idées) des antispams existants (ex: Spam Karma)
  • Utiliser un filtre bayésien
  • Utiliser des listes noires (URL / IP / email) dynamiques
  • Filtrage horaire et/ou selon le jour de la semaine (je pense qu'il y a peu de commentaires légitimes entre 2h et 7h)
  • Utiliser des listes blanches ou d'autres règles pour diminuer la note

Contactez moi directement si vous voulez tester antispam sur votre forum ou votre blog. L'intégration étant pénible à automatiser. Antispam est écrit en Python et distribué sous licence GNU GPL.

Comment réaliser un fuzzer ?

Après de dizaines de projets d'articles avortés (mort-nés), j'ai enfin réussi à en finir un ! C'est l'article « Comment réaliser un fuzzer ? » qui est publié dans le magazine de sécurité informatique MISC numéro 36 (mars/avril 2008). J'explique quels sont les points critiques lorsqu'on écrit un fuzzer : génération des données, surveiller la cible, auto-configuration du fuzzer, etc. Image de la première des six pages de l'article :

L'article parle indirectement de mon travail sur le projet Fusil. Un deuxième article plus pratique et dédié à Fusil devrait suivre dans le prochain MISC (reste à l'écrire...).

Je regrette d'avoir oublié la section remerciements à la fin de l'article. Alors je profite de ce blog pour remercier Sebastien Tricaud, Feth Arezki, Stéphane Marchesin et ceux que j'ai oublié pour leurs relectures attentives et leurs conseils avisés. Merci aussi à Anthony Carré pour m'avoir encouragé à écrire pour des magazines papiers :-)

Au passage, si vous êtes amateur de sécurité informatique mais que vous ne connaissez pas encore MISC, je vous en conseille la lecture. Le prix élevé de 8€ est à diviser par deux car c'est un bimensuel : ce qui donne 4€/mois. D'ailleurs, il faut deux bons mois pour digérer les articles souvent complexes ;-)

dimanche 9 mars 2008

Spam dans les forums, blogs, etc.

Le spam désigne un « message non sollicité ». Avant limité à la messagerie électronique, le spam inonde aujourd'hui Internet en utilisant n'importe quel moyen de publier du texte avec des liens externes. Les plus touchés sont les forums (ex: phpbb) et les blogs (ex: dotclear). Plus généralement, plus la cible est populaire, plus elle a de chances d'être spammée. Dès lors, n'importe quel formulaire public devient est cible potentielle.

Filtrage par test de turing

Pour limiter le spam, l'inscription aux forums est devenue pénible : besoin de confirmer l'inscription par courriel par exemple. De même, déposer un commentaire sur un blog demande souvent des talents en décodage de hiéroglyphe (captchas). Le spam doit vraiment être lucratif car qu'importe le niveau de complexité de la protection, elle est déjouée un jour ou l'autre. La meilleure parade aux captchas étant de demander à des humains de les décoder à votre place. Cette faille déjoue l'ensemble des tests de turing !

Filtrage de l'enveloppe

On pourrait alors penser à filtrer l' « enveloppe » : les informations obtenues sur l'expéditeur du message. Le nom de l'expéditeur est généré aléatoirement et pourtant crédible, on ne peut pas en faire grand chose. Son adresse de courriel est souvent crée pour l'occasion sur un serveur offrant des adresses gratuites (ex: gmail). L'adresse IP semble une bonne piste pour bloquer un spammeur. Sauf que les spammeurs ont aussi trouvé une parade : ils louent des serveurs à moindre coût pour émettre anonymement du spam. Ces serveurs peuvent faire parti d'un botnet : ordinateurs verrolés à l'insu d'internautes légitimes. Bloquer une IP empêcherait un internaute légitime de poster un commentaire. De toute manière, les spammeurs changent régulièrement de serveurs (et donc d'adresse).

Filtrage du contenu

Si l'enveloppe n'est pas une information fiable, on peut se concentrer sur le contenu du message. Bien que chaque spam soit différent, on peut tout de même reconnaître certaines caractéristiques générales :

  • un spam comporte au moins un lien externe (parfois une dizaine ou plus)
  • on retrouve les même mots tels que « porn », « download » ou encore « viagra »

Une fois de plus, ces caractéristiques ne sont pas fiables à 100%. Certains spammeurs contournent le blocage par mots-clés en modifiant légèrement le terme : « viagra » devient « v1agra » par exemple. Concernant les liens externes, on commence à trouver des liens pointant sur google.com (ex: sur groups.google.com et pages.google.com) : bloquer un domaine est donc plutôt hasardeux. Bien que les spams ne comportant aucun lien externe soient rares, bloquer tout message comportant un lien externe est très contraignant pour l'internate légitime.

Filtrage par l'obscurité

Pour déjouer les plans des robots, certains se protègent en modifiant les formulaires de leur application. Une bidouille est d'ajouter un champ au formulaire. Ce champ contient un valeur spéciale ou est laissée vide : si le bot le modifie, le message est considéré comme un spam. Ce champ peut être caché (type HTML hidden ou caché par la mise en forme CSS) ou visible, auquel cas une mention avertira l'internaute de ne pas y toucher. Malheureusement, de telles pratiques relèvent de la sécurité par l'obscurité et ne peut être utilisé à grande échelle. Une fois l'astuce connue, des robots vont la déjouer facilement.

Filtrage par pot de miel

Il existe des services mettant en place des pots de miel : forums, blogs et autres dédiés à la récolte de spam. Cette collecte permet de créer une liste noire d'URL et/ou d'IP, exemples : surbl.org et projecthoneypot.org. La technique du pot de miel ne sert qu'à limiter la diffusion d'un spam.

Aucun espoir ?

C'est en écrivant mon propre antispam pour ce blog que j'ai réalisé l'ampleur du problème. Bien qu'aucune protection citée n'est fiable à 100%, cumuler plusieurs solutions permet de bloquer l'essentiel du spam, allégeant considérablement la charge du modérateur.

Malheureusement, plus un moyen de protection est efficace, plus il est utilisé, plus les spammeurs vont se concentrer dessus pour le déjouer. La sécurité par l'obscurité semble donc conseillée voir nécessaire. Des services comme Akismet reposent justement sur ce principe. Pourtant, je m'y oppose car c'est contraire à l'esprit de partage du logiciel libre !

mardi 4 mars 2008

Scanneur de ports PortBunny

Comme je n'ai pas pu aller au 24th Chaos Communication Congress (fin décembre 2007), je me suis rabattu sur les vidéos publiées quelques temps après. J'ai beaucoup apprécié les vidéos « (2279) Deconstructing Xbox 360 security » et « (2131) Port scanning improved ». Je voudrais parler plus particulièrement de PortBunny, un nouveau scanneur de port qui a pour logo un lapin rose. Le diaporama de la présentation est disponible en ligne.

Lire la suite

Historique de la faille vmsplice()

Le chercheur en sécurité Wojciech Purczynski, employé par COSEINC et membre de l'association iSEC Security Research, a trouvé divers bugs dans l'appel système vmsplice() du noyau Linux. Cette fonction, introduite avec Linux 2.6.17, sert à envoyer des données de l'espace utilisateur vers l'espace noyau pour alimenter un pipe. Lire mon précédent billet sur l'évolution des entrées/sorties dans Linux pour les détails. Les développeurs noyau sont prévenus dès le 1er février. Cet article relate la publication, l'exploitation, puis la correction de ces failles.

Lire la suite

lundi 3 mars 2008

Évolution des appels systèmes d'entrée/sortie Linux

En juin 1998, Larry McVoy propose une nouvelle API pour les entrées/sorties dans le noyau Linux : The splice I/O model. Il propose une interface d'entrée/sortie vectorielle (scatter/gather), asynchrone et sans copie (zero copy). Le but est de maximiser les performances en évitant de recopier inutilement des zones mémoires. Les travaux pour concrétiser ses idées prendront presque une dizaine d'années.

Lire la suite