Some new features of IPS mode in Suricata 1.1beta2

The IDS/IPS suricata has a native support for Netfilter queue. This brings IPS functionnalities to users running Suricata on Linux.

Suricata 1.1beta2 introduces a lot of new features related to the NFQ mode.

New stream inline mode

One of the main improvement of Suricata IPS mode is related with the new stream engine dedicated to inline. Victor Julien has a great blog post about it.

Multiqueue support

Suricata can now be started on multiple queue by using a comma separated list of queue identifier on the command line. The following syntax:

suricata -q 0 -q 1 -c /etc/suricata.yaml

will start a suricata listening to Netfilter queue 0 and 1.

The option has been added to improve performance of Suricata in NFQ mode. One of the observed limitation is the number of packets per second that can be sent to a single queue. By being able to specify multiple queues, this is possible to increase performances. The best impact is on multicore systems where it adds scalability.

This feature can be used with the queue‐balance option the NFQUEUE target which was added in Linux 2.6.31. When using −−queue−balance x:x+n instead of −−queue−num, packets are then balanced across the given queues and packets belonging to the same connection are put into the same nfqueue.

NFQ mode setting

Presentation

One of the difficulty of IPS usage is to build an adapted firewall ruleset. Following my blog post on this issue, I’ve decided to implement most of the existing mode in Suricata.
When running in NFQ inline mode, it is possible now to use a simulated non-terminal NFQUEUE verdict by using the ‘repeat’ mode.
This permit to send all needed packet to suricata via this a rule:

iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE

And below, you can have your standard filtering ruleset.

Configuration and other details

To activate this mode, you need to set mode to ‘repeat’ in the nfq section.

nfq:
  mode: repeat
  repeat_mark: 1
  repeat_mask: 1

This option uses the NF_REPEAT verdict instead of using a standard NF_ACCEPT verdict. The effect is that the packet is sent back at the start of the table where the queuing decision has been taken. As Suricata has put on the packet the mark $repeat_mark with respect to the mask $repeat_mask, when the packet reaches again the iptables NFQUEUE rules it does not match anymore because of the mark and the ruleset floowing this rule is used.

The ‘mode’ option in nfq section can have two other values:

  • accept (which is default simple mode)
  • route (which is little bit tricky)

The idea behind the route option is that a program using NFQ can issues a verdict that has for effect to send the packet to an another queue. This is thus possible to chain softwares using NFQ.
To activate this option, you have to use the following syntax:

nfq:
  mode: route
  route_queue: 2

There is not much usage of this option. One mad mind could think at chaining suricata and snort in IPS mode 😉

The nfq_set_mark keyword

Effect and usage of nfq_set_mark

A new keyword nfq_set_mark has been added to the rules option.
This is an enhancement of the NFQ mode. If a packet matches a rule using nfq_set_mark in NFQ mode, it is marked with the mark/mask specified in the option during the verdict.

The usage is really simple. In any rules, you can add the nfq_set_mark keyword to specify the mark to put on a packet and what is the the

pass tcp any any -> any 80 (msg:"TCP port 80"; sid:91000004; nfq_set_mark:0x80/0x80; rev:1;)

That’s great but what can I do with that ?

If you are not familiar with the advanced network capabilities, you may wondering how it can be used. Nefilter mark can be used to modify the handling of a packet by the network stack, ie routing, quality of service, Netfilter. Thus, the concept is the following, you can use Suricata to detect a suspect packet and decide to change the way it is handled by the network stack.
Thanks to the CONNMARK target, you can modify the way all packets of the connection are handled.

Among the possibilities:

  • Degrade QoS for a connection when a suspect packet has been seen
  • Trigger Netfilter logging of all subsequent packets of the connection (logging could be done in pcap for instance)
  • Change routing to send the trafic to a dedicated equipment

Massive and semantic patching with Coccinelle

I’m currently working on suricata and one of the feature I’m working on change the way the main structure Packet is accessed.

One of the consequences is that almost all unit tests need to be rewritten because the use Packet p construction which has to be replace by an dynamically allocated Packet *. Given the number of tests in suricata, this task is very dangerous:

  • It is error prone
  • Too long to be done correctly

I thus decide to give a try to coccinelle which is a "program matching and transformation engine which provides the language SmPL (Semantic Patch Language) for specifying desired matches and transformations in C code". Well, from user point of view it is a mega over-boosted sed for C.

One of the transformation I had to do was to find all memset() done on a Packet structure and replace it by a memset on the correct length followed by the setting of a pointer. In term of code with "..." meaning some code, I had to found all codes like
[C]func(...)
{
Packet p;
...
memset(&p, 0, ...);
}[/C]
and replace it by
[C]func(...)
{
Packet p;
...
memset(&p, 0, SIZE_OF_PACKET);
p->pkt = (uint8_t *)(p + 1);
}[/C]
To do so, I wrote the following semantic patch which defined the objects and the transformation I want to apply:
[diff]@rule0@
identifier p;
identifier func;
typedef uint8_t;
typedef Packet;
@@
func(...) {
<... Packet p; ... - memset(&p, 0, ...); + memset(&p, 0, SIZE_OF_PACKET); + p.pkt = (uint8_t *)(p + 1); ...>
}
[/diff]
If this semantic patch is saved in the file memset.cocci, you just have to run

spatch -sp_file packet.cocci -in_place detect.c

to modify the file.
The result of the command is that detect.c has been modified. Here's an extract of the resulting diff:
[diff]
@@ -9043,6 +9100,7 @@ static int SigTest...m_type() {
Packet p2;
memset(&p2, 0, SIZE_OF_PACKET);
+ p2.pkt = (uint8_t *)(p2 + 1);
DecodeEthernet(&th_v, &dtv, &p2, rawpkt2, sizeof(rawpkt2), NULL);
[/diff]
As you can see, spatch does not care that the variable is name p2. This is a Packet structure which is defined inside a function and which is memset() afterwards. It does the transformation knowing C and thus you need to think C when writing the semantic patch.

Now let's go for some explanations. The semantic patch start with the declaration of the parameters:
[diff]@rule0@ // name of the rule
identifier p; // this will be replace by the name of a variable
identifier func; // func will be the name of something
typedef uint8_t; // this is a C type we will use
typedef Packet; // same remark
@@
[/diff]
The main point is that, as coccinelle is using variable you must give in the information about what is a variable for you (usage of identifier) but you also need to specify what word are specific to the code (usage of typedef in the example).
The rest is straightforward if we omit an astuce I will detail:
[diff]func(...) { // the modification occurs in any function
<... // there is some code (...) who can occur more than once (<) Packet p; // a variable is a Packet, we named it p ... // some code - memset(&p, 0, ...); // a memset is done on p, we remove it (-) + memset(&p, 0, SIZE_OF_PACKET); // and replace it + p.pkt = (uint8_t *)(p + 1); // by this two lines (+) ...> // the part of the code occuring more than once end here
}
[/diff]

My complete semantic patch for the suricata modification is around 55 lines and the resulting patch on suricata has the following git stat:

30 files changed, 3868 insertions(+), 2745 deletions(-)

and a size of 407Ko. This gives an idea of the power of coccinelle.

Here's a light example of what coccinelle is able to do. If you want to read further just go on coccinelle website or read my "Coccinelle for the newbie" page.

I like to thanks Holger Eitzenberger for talking me about the existence of Coccinelle and I give out a great thanks at Julia Lawall for her expertise and her patience. She helps me a lot during my discovery of Coccinelle.

Splitting and shrinking a git repository

I have recently faced the challenge to rewrite a git repository. It has two problems:

  • First problem was small: an user has commited with a badly setup git and E-mail as well as username were not correctly set.
  • Second problem seems more tricky: I was needing to split the git repository in two different one. To be precise on that issue, from the two directories at root (src and deps) have to become the root of their own repository.

I then dig into the doc and it leads me directly to ‘filter-branch’ which was the solution of my two problems. The names of the command is almost self-explanatory: it is used to rewrite branches.

Splitting the git repository

A rapid reading of ‘git help filter-branch’ convince me to give a try to the ‘subdirectory-filter’ subcommand:

--subdirectory-filter

Only look at the history which touches the given subdirectory. The result will contain that directory (and only that) as its project root. Implies
--remap-to-ancestor

Thus to split the directory, I have simply to copy my repository via a clone call and run the filter command:

git clone project project-src
cd project-src
git filter-branch --subdirectory-filter src

Doing once again for the deps directory and I had my two new repositories ready to go.

At once during this cleaning task, I wanted to avoid to loose my directory structure. I mean I want to keep the ‘src’ directory in the ‘src’ repository. Thanks to the examples at the end of ‘git help filter-branch’, I’ve found this trickier command:

git filter-branch --prune-empty --index-filter \\
 'git rm -r --cached --ignore-unmatch deps' HEAD

This literally do the following : for each commit (--index-filter), suppress (rm) recursively (-r) all items of the ‘deps’ directory. If a commit is empty then suppress it from history (--prune-empty).

Shrinking the resulting repository

‘deps’ directory was known to take a lot of disk space and I thus done a check to see the size of the ‘src’ directory. My old friend ‘du’ sadly told me that the split repository has the same size as the whole one ! There is something tricky here. After googling a little bi I’ve found out (mainly by reading Luke Palmer post) that git never destroy immediately a commit. It is always present has an object in the .git/objects directory. To ask for an effective suppression, you’ve got to tell git that some objects are expired and can now be destroyed. The following command will destroy all objects unreachable since more than one day:

git gc --aggressive --prune=1day

Unreachable objects means objects that exist but that aren’t readable from any of the reference nodes. This last definition is taken from ‘git help fsck’. The ‘fsck’ command can be used to check the validity
and connectivity of objects in the database. For example to display unreachable object, you can run:

git fsck --unreachable

Fixing commiter name

My problem on badly authored commits was still remaining. From the documentation, --env-filter subcommand was the one I need to use. The idea of the command is that it will iterate on every commit of the branch giving you some environnement variables:

GIT_COMMITTER_NAME=Eric Leblond
GIT_AUTHOR_EMAIL=eleblond@example.com
GIT_COMMIT=fbf7d74174bf4097fe5b0ec559426232c5f7b540
GIT_DIR=/home/regit/git/oisf/.git
GIT_AUTHOR_DATE=1280686086 +0200
GIT_AUTHOR_NAME=Eric Leblond
GIT_COMMITTER_EMAIL=eleblond@example.com
GIT_INDEX_FILE=/home/regit/git/oisf/.git-rewrite/t/../index
GIT_COMMITTER_DATE=1280686086 +0200
GIT_WORK_TREE=.

If you modify one of them and export the result, the commit will be modifed accordingly. For example, my problem was that commit
from ‘jdoe’ are in fact from ‘John Doe’ which mail is ‘john.doe@example.com’. I thus run the following command:

git filter-branch -f --env-filter '
if [ "${GIT_AUTHOR_NAME}" = "jdoe" ]; then
GIT_AUTHOR_EMAIL=john.doe@example.com;
GIT_AUTHOR_NAME="John Doe";
fi
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL
'

Git show here once again it has been made by semi-god hackers that have developped it to solve their own source management problems.

Debian, le retour de la faille SSL

La distribution Debian GNU/Linux est habituée au problème de hasard pas si aléatoire que ça. Cela s’était illustré avec la faille openssl et cela vient d’être confirmé par le debian logo en ascii art du boot.

J’en tiens pour preuve le screenshot suivant :

Debian et le retour du SSL

Hé oui, on a clairement sur l’avant-dernière ligne -)SSL,,

Deux hypothèses :

  • Un manque de chance lors de la génération du log par le système image vers ASCII
  • Une jolie autodérision

En route vers le 2.6.30 et encore merci Denis

Oui, bon, vous savez sans doute que le noyau Linux 2.6.30 est en cours de réalisation. Mais saviez-vous que grâce à l’excellent Denis Bodor toute une série de patchs a été incorporée au noyau ?

Lors de la rédaction du Hors Série Netfilter de GLMF, j’ai, avec tous les autres rédacteurs (Gwenael, Haypo, Pollux et Toady), voulu faire découvrir les dernières avancées de Netfilter. Et, forcément, lorsque l’on est sur le fil du rasoir et que l’on pousse les choses à fond pour être le plus précis possible, il arrive que l’on découvre des problèmes ou des choses pas aussi pratiques que on le désirerait.

J’ai donc réalisé une série de patchs pour améliorer l’expérience des lecteurs de ce splendide Hors Série Netfilter :

GLMF Hors série n°41

Merci donc à Denis pour nous avoir fait confiance pour ces articles et merci à Patrick McHardy d’avoir accepté mes patchs.

Contribution au libre, 2009 commence fort.

Du côté de mes contributions au logiciel libre, l’année 2009 commence assez fort. Il semble que j’ai réussi à déclencher une petite révolution.

Le système de test de NuFW avait mis en évidence un crash rare, non reproductible facilement dans nuauth, le serveur d’authentification de NuFW. Les sorties de gdb ou valgrind révélaient un problème absurde dans la bibliothèque cyrus-sasl. NuFW l’utilise pour réaliser la phase d’authentification des utilisateurs. Le crash apparaissait lors d’un appel à sasl_dispose() qui est la fonction à appeler lorsque l’on a terminé la phase d’authentification. Après maintes vérifications et plusieurs dizaines d’heures de debug, j’étais convaincu que nuauth, le serveur d’authentification de NuFW, utilisait la bibliothèque de manière correcte et que le code environnant était correct.

Lorsque l’utilisation d’une bibliothèque est légitime et que l’on obtient un plantage, c’est que l’on a trouvé un bug. J’ai donc alors commencé à enquêter sur Cyrus-sasl. Cette bibliothèque est développée dans le cadre du projet cyrus (serveur de mail imap) par la Carnegie Mellon University. Elle est utilisée par un nombre conséquent de logiciels libres fameux (dont openldap, sendmail). Même si sendmail a une réputation sulfureuse de sécurité, il est connu pour sa stabilité. Et donc, en me lançant dans le debug de ce problème début septembre 2008, je savais que je m’attaquais à quelque chose de robuste car très utilisé. Le bug allait donc être complexe à trouver.

J’enchainais alors des séances de deboguage plus ou moins longues passant à certain moment plusieurs longues journées de travail (lire 14 ou 15 heures) sur ce problème. Je sortais tout de même victorieux de la confrontation et le 20 septembre 2008, j’envoyais un message à la liste de diffusion cyrus-sasl : [PATCH] Fix problem with sasl_set_mutex

NuFW utilise les bibliothèques cyrus-sasl et libldap_r et libldap_r utilise lui aussi cyrus-sasl. Elle s’en sert lors de la phase d’authentification sur la base LDAP. Comme, et libldap_r et NuFW sont multithreadés ou multithreadable, ils initient tous les deux la bibliothèque cyrus-sasl pour le support des threads. Il y a notamment un appel à sasl_set_mutex() qui définit l’implémentation de mutex à utiliser. NuFW appelle cette fonction avec ses propres paramètres et libldap_r fait de même (même lorsque l’on fait un bind simple, les connaisseurs apprécieront). Or sasl_set_mutex() ne détectait pas qu’une initilisation avait déjà été faite. On avait donc un conflit possible. Les fonctions de mutex sasl prennent des paramètres void* en entrée et travaille sur ces pointeurs. Il y donc potentiellement des casts dangereux.

Dans le cas de NuFW, le problème était beaucoup plus radical. L’initialisation de libldap_r se fait lors du chargement du module ldap de nuauth. Par conséquent, c’est la fonction ldap qui est utilisée après chargement du module. Or, nuauth peut changer de configuration et donc de modules à chaud. Il réalise notamment un déchargement des modules. Or, cela ne met pas à jour la fonction mutex de sasl qui appelle donc une fonction déchargée. Ceci conduit immanquablement au crash. Cette fonctionnalité de modification de configuration à chaud est massivement utilisé dans le système de tests de NuFW et c’est donc pour cette raison que le crash ne se produisait qu’à cet endroit.

J’aurais du déboguer plus rapidement ce problème. La piste que j’aurais du voir plus tôt était l’utilisation de fonctions stockées à des emplacements mémoires non valides. Cette information était donnée par gdb et j’aurais du lui faire d’avantage confiance.

Ma remontée de bug et mon patch ont rapidement été pris au sérieux et un patch implémentant mon idée a été commité dans les sources : Fixed sasl_set_mutex() to disallow changing mutex management functions once sasl_server_init/sasl_client_init is called

J’étais content de voir ce correctif appliqué, mais vu la criticité pour NuFW, j’aurais été satisfait de voir arriver une nouvelle version de cyrus-sasl fixant ce bug. Le problème étant déclenché par une utilisation précise de la bibliothèque, je n’étais pas en droit de remonter mon exigence. De plus, la dernière version de cyrus-sasl date du 19 mai 2006 et je me doutais donc que je n’allais pas être entendu.

Début janvier, un mail envoyé sur la liste a pointé le fait que le bug était reproductible en utilisant le stockage des mots de passe sasl dans ldap : En utilisant lui aussi la bibliothèque libldap_r cyrus-sasl se mordait la queue. Le bug était donc aussi interne à cyrus-sasl. Fort de cette conclusion, j’envoyais une réponse au message signalant le problème :

This made the bug self contained and not dependant of other applications. Given the fact that the effect of this bug is a crash of the calling program, it could be interesting to release a new version of the sasl library. (my 0.02$)

J’avais ainsi osé demandé une nouvelle version sur un logiciel où je n’avais pas écrit une ligne de code. À ma surprise, cela s’est conclu par ce message :  Next release of CMU SASL – call for favorite bugfixes où un membre de l’équipe de développement annonce l’arrivée probable, aux alentours du 15 février, d’une nouvelle version de la bibliothèque et demande quels sont les corrections de bugs que les utilisateurs voudraient voir figurer dans cette version.

Je commence donc l’année 2009, en réussissant à déclencher la sortie d’une nouvelle version d’une bibliothèque qui n’avait pas eu de nouvelles versions depuis près de trois ans !

Je conclus ce poste en plagiant pollux et en revoyant mes objectifs de contributions à la hausse pour l’an prochain :

En 2010, je déclenche une sortie de Debian.

Lutter contre la faille DNS avec Netfilter

La découverte récente d’une méthode permettant d’exploiter des failles dans la plupart des implémentations DNS à fait beaucoup de bruits. J’en tiens pour preuve des articles dans ZDNET (Colmatage d’une faille de grande envergure sur les serveurs DNS), Le Monde et les échos.

Si l’on étudie ce qu’écrit le CERT dans l’article Multiple DNS implementations vulnerable to cache poisoning, une méthode de contournement de la faille consiste à rendre aléatoire le port source utilisé pour les requêtes DNS.

Lors de recherches faites sur le bloquage de Skype, j’avais implémenté la traduction d’adresse avec attributions de port source aléatoire dans Netfilter et Iptables. Cette modification avait été faite pour empêcher l’établissement de connexions directes entre deux machines situés derrière des routeurs malgré la traduction d’adresse. Cette fonctionnalité est disponible dans Linux depuis le noyau 2.6.21. Elle peut-être utilisée pour lutter contre la faille DNS.

Si les serveurs DNS relais ou les clients se trouvent derrière votre pare-feu Netfilter, il suffit de rajouter la règle de NAT suivante :

iptables -I POSTROUTING -t nat -p udp --dport 53 -j SNAT --to IP --random

Netfilter va alors rendre aléatoire le port source des connexions DNS tel qu’il est vu derrière la passerelle (et donc pour le monde extérieur) luttant ainsi contre les attaques de cache poisonning.

Présentation de ulogd2 et nf3d au SSTIC 2008

J’ai présenté Ulogd2 et nf3d lors de la rump session du SSTIC 2008.
Après une brève introduction sur l’architecture de ulogd2, j’ai montré le résultat de mon travail sur la visualisation des connexions et des paquets loggués, nf3d.
Les slides sont disponibles.

Je me rend compte que je n’ai pas encore parlé de nf3d ici. Il s’agit d’un logiciel représentant sur une vue 3D les connexions Netfilter et les paquets loggués. Comme une image vaut mieux qu’un long discours :




Les cylindres représentent les connexions et les sphères les paquets loggués. L’axe des X est le temps et l’axe des Y indique la succession des connexions. Chaque paquet est représenté sur la connexion dont il est issu.

GPL contre Skype : 2-0

D’un point de vue juridique, j’aurais du plutôt titrer Welte vs. Skype Technologies SA. En effet, Harald Welte, ex leader du projet Netfilter et fondateur de GPL violations vient de gagner en appel contre Skype Technologies SA.

Harald Welte, dans le cadre de GPL violations, avait commencé à lutter contre Skype Technologies SA en février 2007 pour que la société cesse de violer la GPL en commercialisant des téléphones Wifi sous Linux sans respecter les exigences de la licence.

Faute de réponse de Skype Technologies SA à ses demandes, il avait porté plainte et l’affaire avait été jugée en Juin 2007. Le tribunal avait statué en faveur de GPL violations et Skype Technologies SA avait ensuite fait appel du jugement (GPL 1 – Skype 0).

L’affaire a donc été portée devant le “Oberlandesgericht Muenchen”, plus haute juriduction dans la région de Munich. L’intention de Skype Technologies SA était de nier la validité de la licence GPL mais les juges ne l’entendaient pas de cette manière et Skype Technologies SA a donc retiré son appel après un entretien préliminaire le 08 mai 2008 (GPL 2 – Skype 0).

Interview dans le cadre des RMLLs

Je vais donner une conférence sur NuFW et les interactions entre espace utilisateur et noyau dans Netfilter lors des rencontres mondiales du logiciel libre 2008 à Mont-de-Marsans.

Dans ce cadre, Christophe Brocas m’a gentillement interviewé par mail. L’interview est en ligne sur le site des RMLLs : Interview Éric Leblond.

À noter qu’une interview de l’excellent Pablo Neira est elle aussi disponible sur le site.