blog-image

HAPROXY - Paramétrage des Logs APACHE2 - OSSEC Haproxy decoder

  • dHENRY
  • 28/04/2019
  • (Durée de lecture : 8 mn)

Update : Attention cette documentation est obsolète

Cet article n’a pas pour but d’expliquer le fonctionnement du service HAPROXY mais de donner quelques idées au niveau du paramétrage d’un ensemble utilisant HAPROXY : serveurs web apache, OSSEC et la détection d’intrusion.

Quand vous installez un service HAPROXY pour répartir la charge des accès un site ou une application web (protocole HTTP/HTTPS), ou pour permettre une isolation des “serveurs Web”, HAPROXY doit être configuré en mode http (Layer7), qui correspond à la couche 7 du modèle OSI (https://fr.wikipedia.org/wiki/Mod%C3%A8le_OSI).
HAPROXY est capable d’analyser les entêtes contenues dans les requêtes TCP/IP puis de dispatcher le flux vers les ressources nécessaires (serveurs web finaux) :

topologie d’ensemble

Paramétrage des Logs - HAPROXY et les serveurs Web Apache (Debian - apache2)

HAPROXY comme son nom l’indique agit en tant que proxy. Il écoute à l’adresse et sur le port paramétré (ici xxx.xxx.xxx.xxx/TCP 443). Quand il reçoit une requête correspond à la configuration, il analyse l’entête, détecte le domaine, choisi le serveur web final, puis crée une nouvelle communication entre lui et le serveur web final. Il n’agit donc pas comme un routeur. La requête TCP/IP finale transporte bien l’adresse de l’émetteur : le serveur HAPROXY, et l’adresse du destinataire : le serveur final.
On a donc au niveau des requêtes TCP/IP :

  • la requête initial de l’utilisateur situé sur l’internet : EMETTEUR : xxx.xxx.xxx.xxx (IP utilisateur) - DESTINATAIRE : xxx.xxx.xxx.xxx (IP Internet HAPROXY)
  • puis la seconde requête créée par HAPROXY : EMETTEUR : 192.168.1.10 (IP HAPROXY réseau local) - DESTINATAIRE : 192.168.1.100 ou 192.168.1.101 (IP serveur web final).

Le serveur web final, va donc recevoir, non pas une requête provenant directement de l’internet, mais bien du serveur HAPROXY. Le log du serveur (apache2 dans mon cas), va donc indiquer à la position de l’adresse du client : “192.168.1.10”. Et j’ai perdu l’information de départ, par conséquent si j’effectue des statistiques, à partir de ces logs, tous mes visiteurs seront : “192.168.1.10” !!!

Configuration HAPROXY

HAPROXY permet, au moment de créer la communication entre lui et le serveur final, l’ajout de l’information du client original (situé sur l’internet). Cette information sera stockée dans l’entête TCP/IP, dans le paramètre “X-FORWARDED-FOR”.
Ce paramétrage est activable en ajoutant le paramètre “option forwardfor” à la configuration HAPROXY.

Après avoir modifié la configuration HAPROXY, rechargez la : systemctl reload haproxy

Configuration du serveur Apache (Debian Apache2)

Je modifie la configuration du serveur apache, afin de lui indiquer la nouvelle forme des logs à créer.
Par défaut, apache trace les évènements de connexion par rapport au paramètre LogFormat situé dans le fichier : /etc/apache2/apache2.conf
Ouvrez ce fichier et rechercher la ligne : LogFormat “%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"” combined
Notez bien la fin “combined”. Dupliquez cette ligne et remplacer le %h par : %{X-Forwarded-For}i et combined par forwardfor. Le fichier ressemble maintenant à ceci :

[..]
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" forwardfor
[..]

Enregistez et quitter.
Ouvrez maintenant le fichier de configuration de votre site ou de l’application web, distribué par votre serveur web. (/etc/apache/site-enabled/xxxx). Mon site se nomme www.mondomaine.com, j’indique dans la configuration, que le service doit tracer les connexions dans le fichier /var/log/apache2/access-www.mondomaine.com.log
Notez bien le type de signal “forwardfor” et comme habituellement “combined”.

CustomLog ${APACHE_LOG_DIR}/access-www.mondomaine.com.log forwardfor

Enregistez et quitter. Rechargez la configuration apache2 :

systemctl reload apache2

Vérifiez le log d’accès, après avoir demandé une ressource de ce site. L’adresse IP du demandeur initial correspond bien à l’adresse IP de votre poste de travail et non celle du serveur HAPROXY.

OSSEC (détection d’intrusion) et HAPROXY decoder

Concernant l’installation du service OSSEC, reportez-vous au billet : https://www.mytinydc.com/index.php/2018/11/15/ossec-hids-detecteur-dintrusions/

OSSEC ne connaît pas le format des logs HAPROXY, par conséquent, il est inutile que OSSEC observe les traces de connexions HAPROXY.
Mais ceci pose un problème majeur.
Reprenons à partir du schéma topologique ci-avant.
Si vous demandez à OSSEC de filtrer les entrées du log Apache (**Serveur-web-1 ** qui est disposé sur un serveur final). Ces logs, de part le paramétrage effectué avec “forwardfor”, indiquent bien l’adresse source de la demande, mais ce serveur (Serveur-web-1) n’est pas en contact direct avec la source, mais avec le serveur HAPROXY.
Si OSSEC applique la réponse active, il va blacklister l’adresse xxx.xxx.xxx.xxxx de l’utilisateur situé sur l’internet. La protection est alors INEFFICACE puis l’adresse IP, qui contacte le serveur final, est celle du serveur HAPROXY. Il faut donc effectuer le contrôle OSSEC sur le serveur HAPROXY, connecté directement à l’utilisateur final.
Le but d’un détecteur d’intrusion est bien de bloquer les accès, en amont des serveurs applicatifs, afin que ces derniers ne subissent pas en continu, des attaques de type “force brute”.
Dans le cadre d’une attaque par “force brute” envers des services HTTP/HTTPS, il convient que les développeurs aient prévus une réponse HTTP de type 401, conformément aux spécifications du protocole (401 Unauthorized).
Le test à faire est très simple, connectez-vous à la page de connexion de votre application, tentez une connexion avec un mauvais login ou un mauvais mot de passe, les traces Apache2 doivent mentionner dans la colonne HTTP response le code 401, si ce n’est pas le cas, demandez aux concepteurs de l’inclure dans leur prochaine mise à jour. Cette aspect est très souvent oublié lors des développements, mais absolument nécessaire pour les analyses liées à l’administration de systèmes et donc à la sécurité. Sans ce système frontal, il est impossible de détecter les tentatives d’intrusions en amont du serveur d’application et d’y remédier très rapidement.

OSSEC ne dispose pas de décodeur permettant l’analyse de ce type de fichier (/var/log/haproxy.log). Dans la pratique, le contenu de ce fichier ressemble de très près, aux traces “Apache” et “Syslog. Je vais donc écrire un décodeur pour OSSEC, qui filtre les entrées du log, en utilisant le “syslog decoder” et qui applique les filtres de “apache decoder” pour déclencher les réponses actives conséquentes.

Ajout haproxy decoder à la configuration OSSEC

Connectez-vous au serveur OSSEC (les clients ne disposent pas de ce fichier, il est distribué par le serveur), éditez le fichier /var/ossec/etc/decoder.xml puis ajoutez y le contenu suivant :

<decoder name="haproxy">
  <program_name>^haproxy</program_name>
</decoder>
<decoder name="haproxy-web-accesslog">
  <parent>haproxy</parent>
  <type>web-log</type>
  <prematch>^\S+:\S+ [\S+] \S+ \S+ \S+ \S+ <prematch>
  <regex>^(\S+):(\S+) [\S+] \S+ \S+ \S+ (\S+) .*"(\S+) (\S+)</regex>
  <order>srcip, srcuser, id, action, url </order>
</decoder>

Expressions régulières OSSEC https://ossec-docs.readthedocs.io/en/latest/syntax/regex.html

Enregistrez le fichier. Redémarrer OSSEC : systemctl restart ossec
Connectez-vous au serveur disposant du service HAPROXY et du client OSSEC, ajoutez l’instruction permettant à OSSEC de lire le fichier /var/log/haproxy.log. Editez le fichier /var/ossec/etc/ossec.conf

<localfile>
    <log_format>apache</log_format>
    <log_format>/var/log/apache2/access.log</log_format>
</localfile>
.....

Ajoutez ce block xml :

<localfile>
    <log_format>syslog</log_format>
    <log_format>/var/log/haproxy.log</log_format>
</localfile>

Enregistrer le fichier, et redémarrez OSSEC :

systemctl restart ossec

Test

Benjamin nous indique que le système OSSEC (installation serveur) dispose d’un shell permettant de tester le comportement de OSSEC par rapport à une entrée de log. L’utilisation est très simple et très utile pour écrire un decoder. La modification du fichier decoder.xml ne nécessite pas un redémarrage OSSEC pour être utilisé par cet outil. Tapez la commande : /var/ossec/bin/ossec-logtest puis coller l’entrée de log souhaité, l’outil indiquera son analyse et le traitement qu’il opère.

/var/ossec/bin/ossec-logtest
# Coller cette phrase :
Apr 28 12:12:35 machinetest haproxy[31648]: **192.168.1.183**:35567 [27/Apr/2018:09:11:34.840] 192.168.1.118:443httpssl~ nextcloud.ssl/server-1 0/0/4/216/220 **401** 1017 - - ---- 9/3/0/1/0 0/0 "GET //ocs/v2.php/apps/notifications/api/v2/notifications HTTP/1.1
# Appuyer sur Entrée


Phase 2: Completed decoding.
       decoder: 'haproxy'
       srcip: '192.168.1.183'
       srcuser: '35567'
       id: '401'
       action: 'GET'
       url: '//ocs/v2.php/apps/notifications/api/v2/notifications'
**Phase 3: Completed filtering (rules).
Rule id: '31101'
Level: '5'
Description: 'Web server 400 error code.'
Alert to be generated.

Remarquez srcuser correspond au port du client, le log haproxy ne présente pas l’entrée user de l’entête HTTP, j’ai donc pris une valeur au hasard afin d’être conforme au spécification de web-log decoder

Votre système de détection d’intrusion va pouvoir se charger des tentatives d’intrusions, par force brute, sur un serveur HAPROXY. Pour faire le test :

Sur le serveur OSSEC :

tail -f /var/ossec/logs/active-responses.log &

Sur le serveur HAPROXY : Ajoutez manuellement des traces permettant d’indiquer le statut 401, par exemple :

echo "Apr 28 12:12:35 machinetest haproxy[31648]: 192.168.1.183:35567 [27/Apr/2018:09:11:34.840] 192.168.1.118:443httpssl~ nextcloud.ssl/server-1 0/0/4/216/220 401 1017 - - ---- 9/3/0/1/0 0/0 \"GET //ocs/v2.php/apps/notifications/api/v2/notifications HTTP/1.1\"" >> /var/log/haproxy.log

Exécutez la commande précédente plusieurs fois de suite. Les traces “active-responses” vont finir par indiquer :

xxxxxxxx /var/ossec/active-response/bin/host-deny.sh add - 192.168.1.183 xxxxx
xxxxxxxx /var/ossec/active-response/bin/firewall-drop.sh add - 192.168.1.183 xxxxxxx

L’adresse IP 192.168.1.183 ne pourra plus se connecter au serveur HAPROXY

Conclusion

Ce post est un pretexte pour présenter la manière de créer un “decoder” pour OSSEC.
Pour sécuriser ce type d’attaque, OSSEC présente déjà toute les fonctionnalités devant être implémentées pour gérer ce type d’évènement.
Dans ce type de schéma, on installera Ossec en version client sur le serveur HAPROXY et relié à un serveur OSSEC. Les serveurs Web seront également connectés au serveur OSSEC.
Avec la mise en place de conditions, tout le mécanisme de protection se passera par échange entre les clients et le serveur OSSEC. Le serveur web détectera l’attaque, qui la transmettra au serveur OSSEC, qui déclenchera l’active-response directement sur le serveur HAPROXY.

Licence de ce document : Creative Commons (CC BY-NC-ND 4.0)

CETTE DOCUMENTATION EST LIVRÉE “EN L’ÉTAT”, SANS GARANTIE D’AUCUNE SORTE ET DISTRIBUÉE DANS UN BUT ÉDUCATIF EXCLUSIVEMENT. L’AUTEUR, CONTRIBUTEURS DE CETTE DOCUMENTATION OU ©MYTINYDC.COM NE SAURAIENT EN AUCUN CAS ÊTRE TENUS RESPONSABLES DES DOMMAGES DIRECTS OU INDIRECTS POUVANT RÉSULTER DE L’APPLICATION DES PROCÉDURES MISES EN ŒUVRE DANS CETTE DOCUMENTATION, OU DE LA MAUVAISE INTERPRÉTATION DE CE DOCUMENT.