Un analyseur est un fichier de configuration YAML qui décrit comment une chaîne doit être analysée. Cette chaîne peut être une ligne de journal ou un champ extrait d’un analyseur précédent.
Alors que de nombreux analyseurs s’appuient sur l’ approche GROK (alias expression régulière nommée groupes de capture), les analyseurs peuvent également utiliser des expressions pour effectuer une analyse sur des données spécifiques (c’est-à-dire json), se référer à des méthodes externes pour l’enrichissement ou même effectuer une White Liste .
L’ événement entre dans l’analyseur et peut se terminer avec succès ou non :
1.2 Stages (Etapes)
Les analyseurs sont organisés en Stages(étapes) pour permettre les pipelines et les branchements dans l’analyse. Un événement peut passer à l’étape suivante si au moins un analyseur de l’étape donnée l’a analysé avec succès tout en ayant onsuccess défini sur next_stage. Sinon, l’événement est considéré comme non analysé et quittera le pipeline (et sera ignoré):
Chaque analyseur peut ajouter, modifier ou même supprimer des données de l’événement.
L’approche actuelle est la suivante :
s00-raw: prend en charge la structure globale du journal (c’est-à-dire extraire les lignes de journal du blob ‘JSON’, analyser les informations de protocole syslog)
s01-parse: analyse la ligne de journal réelle ( ‘ssh’ , ’nginx’ etc.)
s02-enrich: effectue un post-traitement, tel que l’enrichissement ‘géoip’ ou la post-analyse des événements ‘http’ pour fournir plus de contexte
Une fois qu’un événement a quitté avec succès le pipeline d’analyse, il est prêt à être mis en correspondance avec des ‘scénarios’. Comme vous pouvez vous y attendre, chaque analyseur s’appuie sur les informations analysées au cours des étapes précédentes.
Une fois qu’un scénario déborde, l’événement résultant va être traité par un ensemble distinct d’analyseurs, appelés “postoverflows”.
Ces analyseurs sont situés dans /etc/crowdsec/postoverflows/ et contiennent généralement des listes blanches supplémentaires, un exemple courant consiste à mettre en liste blanche les décisions provenant de certains FQDN spécifiques .
Habituellement, ces parseurs doivent être réservés aux parseurs “coûteux” qui pourraient s’appuyer sur des services externes.
Voir le Hub pour explorer les analyseurs, ou voir ci-dessous quelques exemples :
Les analyseurs résident généralement dans /etc/crowdsec/parsers/<STAGE>/.
2. Création d’un Parser (Analyseur)
Cette partie suppose que vous essayez de créer un analyseur pour crowdsec dans le but de le soumettre au hub, et donc de créer les tests fonctionnels associés. La création de ces tests fonctionnels guidera notre démarche et la facilitera.
Nous allons créer un parseur pour le service imaginaire “myservice” qui produit trois types de logs via syslog:
Dec 8 06:28:43 mymachine myservice[2806]: bad password for user 'toto' from '1.2.3.4'
Dec 8 06:28:43 mymachine myservice[2806]: unknown user 'toto' from '1.2.3.4'
Dec 8 06:28:43 mymachine myservice[2806]: accepted connection for user 'toto' from '1.2.3.4'
Comme nous allons analyser ces journaux pour détecter davantage les attaques par force brute et par énumération d’utilisateurs, nous allons simplement “supprimer” le dernier type de journal
2.1 Schéma
Un schema yaml est disponible pour l’analyseur et lié à SchemaStore pour une disponibilité publique générale dans les éditeurs les plus courants. Vous pourrez voir si l’analyseur se conforme au schéma directement dans votre éditeur, et vous aurez une sorte de coloration syntaxique et des suggestions. La seule exigence pour cela est d’écrire votre analyseur en utilisant la structure de répertoires du hub pour que l’éditeur détecte que le fichier doit se conformer au schéma yaml.
2.1.1 Installation dans visual studiocode:
L’extension pour visual studiocode peut être installée directement à partir du market place ou via GitHub
Dans Visual Studio Code, il faut ouvrir la pallete de commande en utilisant la combinaison de touches Ctrl+P, et y coller la commande suivante:
ext install remcohaszing.schemastore
Cela signifie que vous devrez écrire l’analyseur dans un sous-répertoire de:
parsers/s00-raw
parsers/s01-parse
parsers/s02-enrich
postoverflows/s00-enrich
postoverflows/s01-whitelist
Ce sous-répertoire porte votre nom ou du nom de votre organisation. À titre d’exemple parsers/s01-parse/crowdsecurity/sshd-logs.yaml correspond à cette structure de répertoire. Notez que l’extension de l’analyseur doit .yaml.
2.2 Pré-requis
2.2.1 Créer un environnement de test
Vous avez besoin d’un environnement de test pour plusieurs raisons :
Création de nouveaux analyseurs ou scénarios
Tester de nouvelles fonctionnalités ou en général
Présentez un bug ou un cas particulier
Créer un répertoire pour héberger notre environnement de test.
# mkdir crowdsec && cd crowdsec
Cela peut être fait directement avec l’archive tar de la dernière release :
VER=1.5.2 # Please check https://github.com/crowdsecurity/crowdsec/releases/latest for latest versionwget https://github.com/crowdsecurity/crowdsec/releases/download/v$VER/crowdsec-release.tgz
tar xvzf crowdsec-release.tgz
cd crowdsec-v$VER./test_env.sh
On obtient la sortie suivante:
[07/27/2023:11:26:13 PM][INFO] Creating test arboresence in /root/crowdsec/crowdsec-v1.5.2/tests
[07/27/2023:11:26:13 PM][INFO] Arboresence created
[07/27/2023:11:26:13 PM][INFO] Copying needed files for tests environment
[07/27/2023:11:26:13 PM][INFO] Files copied
[07/27/2023:11:26:13 PM][INFO] Setting up configurations
WARN[27-07-2023 23:26:13] can't load CAPI credentials from './config/online_api_credentials.yaml' (missing field)
INFO[27-07-2023 23:26:13] push and pull to Central API disabled
WARN[27-07-2023 23:26:13] You are using sqlite without WAL, this can have a performance impact. If you do not store the database in a network share, set db_config.use_wal to true. Set explicitly to false to disable this warning.
WARN[27-07-2023 23:26:13] can't load CAPI credentials from './config/online_api_credentials.yaml'(missing field)INFO[27-07-2023 23:26:13] push and pull to Central API disabled
INFO[27-07-2023 23:26:13] Machine 'test' successfully added to the local API
INFO[27-07-2023 23:26:13] API credentials dumped to '/root/crowdsec/crowdsec-v1.5.2/tests/config/local_api_credentials.yaml'INFO[27-07-2023 23:26:14] Wrote new 794587 bytes index to /root/crowdsec/crowdsec-v1.5.2/tests/config/hub/.index.json
INFO[27-07-2023 23:26:14] crowdsecurity/syslog-logs : OK
INFO[27-07-2023 23:26:14] Enabled parsers : crowdsecurity/syslog-logs
INFO[27-07-2023 23:26:14] crowdsecurity/geoip-enrich : OK
INFO[27-07-2023 23:26:14] downloading data 'https://crowdsec-statics-assets.s3-eu-west-1.amazonaws.com/GeoLite2-City.mmdb' in '/root/crowdsec/crowdsec-v1.5.2/tests/data/GeoLite2-City.mmdb'INFO[27-07-2023 23:26:16] downloading data 'https://crowdsec-statics-assets.s3-eu-west-1.amazonaws.com/GeoLite2-ASN.mmdb' in '/root/crowdsec/crowdsec-v1.5.2/tests/data/GeoLite2-ASN.mmdb'INFO[27-07-2023 23:26:16] Enabled parsers : crowdsecurity/geoip-enrich
INFO[27-07-2023 23:26:16] crowdsecurity/dateparse-enrich : OK
INFO[27-07-2023 23:26:16] Enabled parsers : crowdsecurity/dateparse-enrich
INFO[27-07-2023 23:26:16] crowdsecurity/sshd-logs : OK
INFO[27-07-2023 23:26:16] Enabled parsers : crowdsecurity/sshd-logs
INFO[27-07-2023 23:26:16] crowdsecurity/ssh-bf : OK
INFO[27-07-2023 23:26:16] Enabled scenarios : crowdsecurity/ssh-bf
INFO[27-07-2023 23:26:16] crowdsecurity/ssh-slow-bf : OK
INFO[27-07-2023 23:26:16] Enabled scenarios : crowdsecurity/ssh-slow-bf
INFO[27-07-2023 23:26:16] crowdsecurity/sshd : OK
WARN[27-07-2023 23:26:16] crowdsecurity/sshd : overwrite
INFO[27-07-2023 23:26:16] /root/crowdsec/crowdsec-v1.5.2/tests/config/collections doesn't exist, create
INFO[27-07-2023 23:26:16] Enabled collections : crowdsecurity/sshd
INFO[27-07-2023 23:26:16] crowdsecurity/linux : OK
INFO[27-07-2023 23:26:16] /root/crowdsec/crowdsec-v1.5.2/tests/config/collections/sshd.yaml already exists.
INFO[27-07-2023 23:26:16] Enabled collections : crowdsecurity/linux
INFO[27-07-2023 23:26:16] Enabled crowdsecurity/linux
INFO[27-07-2023 23:26:16] Run 'sudo systemctl reload crowdsec'for the new configuration to be effective.
[07/27/2023:11:26:16 PM][INFO] Environment is ready in /root/crowdsec/crowdsec-v1.5.2/tests
L’environnement de test est disponible dans le dossier tests et fournit un environnement CrowdSec fonctionnel :
cd tests
./crowdsec -c dev.yaml
cscli doit aussi être fonctionnel :
cd tests
./cscli -c dev.yaml hub list
# ./cscli -c dev.yaml hub listINFO[27-07-2023 23:29:20] Loaded 98 collecs, 106 parsers, 183 scenarios, 7 post-overflow parsers
COLLECTIONS
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Name 📦 Status Version Local Path
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
crowdsecurity/linux ✔️ enabled 0.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/collections/linux.yaml
crowdsecurity/sshd ✔️ enabled 0.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/collections/sshd.yaml
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
PARSERS
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Name 📦 Status Version Local Path
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
crowdsecurity/dateparse-enrich ✔️ enabled 0.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/parsers/s02-enrich/dateparse-enrich.yaml
crowdsecurity/geoip-enrich ✔️ enabled 0.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/parsers/s02-enrich/geoip-enrich.yaml
crowdsecurity/sshd-logs ✔️ enabled 2.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/parsers/s01-parse/sshd-logs.yaml
crowdsecurity/syslog-logs ✔️ enabled 0.8 /root/crowdsec/crowdsec-v1.5.2/tests/config/parsers/s00-raw/syslog-logs.yaml
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
SCENARIOS
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Name 📦 Status Version Local Path
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
crowdsecurity/ssh-bf ✔️ enabled 0.1 /root/crowdsec/crowdsec-v1.5.2/tests/config/scenarios/ssh-bf.yaml
crowdsecurity/ssh-slow-bf ✔️ enabled 0.2 /root/crowdsec/crowdsec-v1.5.2/tests/config/scenarios/ssh-slow-bf.yaml
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
POSTOVERFLOWS
─────────────────────────────────────────
Name 📦 Status Version Local Path
─────────────────────────────────────────
Dans l’environnement de test, les configurations se trouvent dans le dossier config/.
Ajouter un référentiel hub à l’envireonnement
Comme indiqué dans la documentation, cette étape est nécessaire seulement si on veut développer des analyseurs et des scénarios. Ce qui est notre cas.
# cd tests # if you are already in tests no need to cd~/crowdsec/crowdsec-v1.5.2/tests # git clone https://github.com/crowdsecurity/hub.git~/crowdsec/crowdsec-v1.5.2/tests # cd hub
Nous venons de cloner le référentiel hub, nous pouvons maintenant exécuter cscli, par exemple :
~/crowdsec/crowdsec-v1.5.2/tests/hub # ../cscli -c ../dev.yaml hubtest run --all
Cette commande va exécuter tous les tests du référentiel contenu dans le hub.
Le ../ devant cscli et dev.yaml c’est tout simplement car ils se trouvent dans le dossier au-dessus de notre répertoire de travail actuel.
Une astuce utile pour vous éviter de taper toute la commande à chaque fois est de définir un alias dans votre shell :
Ensuite, vous pouvez exécuter la commande en tant que csdev
csdev hubtest run --all
Cependant, il s’agit d’un alias temporaire défini dans votre session. Si vous vous déconnecté et reconnécté, il aura disparu. Il faut donc l’ajouter à votre .bashrc ou à votre équivalent shell.
2.3 Créer notre environnement de tests
Depuis la racine du référentiel hub :
▶ cscli hubtest create myservice-logs --type syslog
Test name : myservice-logs
Test path : /home/dev/github/hub/.tests/myservice-logs
Log file : /home/dev/github/hub/.tests/myservice-logs/myservice-logs.log (please fill it with logs) Parser assertion file : /home/dev/github/hub/.tests/myservice-logs/parser.assert (please fill it with assertion) Scenario assertion file : /home/dev/github/hub/.tests/myservice-logs/scenario.assert (please fill it with assertion) Configuration File : /home/dev/github/hub/.tests/myservice-logs/config.yaml (please fill it with parsers, scenarios...)
2.4 Configurez notre environnement de tests
Ajoutons notre analyseur à la configuration de test (.tests/myservice-logs/config.yaml). Il précise que nous avons besoin de l’analyseur syslog-logs (car les journaux myservice sont expédiés via syslog), puis de notre analyseur personnalisé. La ligne surlignée peut être supprimée pour notre exemple.
Note:: comme notre analyseur personnalisé ne fait pas encore partie du hub, nous spécifions son chemin par rapport à la racine du répertoire du hub.
Donc le fichier myservice-logs.yaml devra être créé dans le répertoire /crowdsec/crowdsec-v1.5.2/tests/hub/parsers/s01-parse/crowdsecurity
2.5 Création de notre parser (Analyseur) Squelette
Pour les besoins du tutoriel, créons un analyseur très simple:
filter:1== 1debug:trueonsuccess:next_stagename:crowdsecurity/myservice-logsdescription:"Parse myservice logs"grok:#our grok pattern : capture .*pattern:^%{DATA:some_data}$#the field to which we apply the grok pattern : the log message itselfapply_on:messagestatics:- parsed:is_my_servicevalue:yes
filter : si l’expression est true, l’événement entrera dans l’analyseur, sinon, il ne le sera pas.
onsuccess: définit ce qui se passe lorsque l’événement a été analysé avec succès : allons-nous continuer ? allons-nous passer à l’étape suivante ? etc.
name: un nom
*description: Une description du parser
debug: un drapeau qui permet d’activer les informations de débogage local
grok: un modèle pour capturer certaines données dans les journaux
Il faut s’assurer de ne pas avoir oublié de saisir les lignes de log dans le fichier ~/crowdsec/crowdsec-v1.5.2/tests/hub/.tests/myservice-logs/myservice-logs.log:
Dec 8 06:28:43 mymachine myservice[2806]: bad password for user 'toto' from '1.2.3.4'
Dec 8 06:28:43 mymachine myservice[2806]: unknown user 'toto' from '1.2.3.4'
Dec 8 06:28:43 mymachine myservice[2806]: accepted connection for user 'toto' from '1.2.3.4'
On peut alors “tester” notre analyseur:
cd ../../
▶ ~/crowdsec/crowdsec-v1.5.2/tests/hub #cscli hubtest run myservice-logsINFO[28-07-2023 11:44:21] Running test'myservice-logs'WARN[28-07-2023 11:44:25] Assert file '/root/crowdsec/crowdsec-v1.5.2/tests/hub/.tests/myservice-logs/parser.assert' is empty, generating assertion:
len(results)==4len(results["s00-raw"]["crowdsecurity/syslog-logs"])==3results["s00-raw"]["crowdsecurity/syslog-logs"][0].Success ==true...
len(results["s01-parse"]["crowdsecurity/myservice-logs"])==3results["s01-parse"]["crowdsecurity/myservice-logs"][0].Success ==trueresults["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["logsource"]=="syslog"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["message"]=="bad password for user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["pid"]=="2806"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["program"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["some_data"]=="bad password for user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["timestamp"]=="Dec 8 06:28:43"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["is_my_service"]=="yes"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["machine"]=="mymachine"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["datasource_path"]=="myservice-logs.log"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["datasource_type"]=="file"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Success ==trueresults["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["is_my_service"]=="yes"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["logsource"]=="syslog"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["timestamp"]=="Dec 8 06:28:43"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["message"]=="unknown user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["pid"]=="2806"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["program"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["some_data"]=="unknown user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["datasource_path"]=="myservice-logs.log"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["datasource_type"]=="file"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["machine"]=="mymachine"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Success ==trueresults["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["timestamp"]=="Dec 8 06:28:43"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["logsource"]=="syslog"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["message"]=="accepted connection for user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["pid"]=="2806"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["some_data"]=="accepted connection for user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["is_my_service"]=="yes"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Parsed["program"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Meta["datasource_path"]=="myservice-logs.log"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Meta["datasource_type"]=="file"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Evt.Meta["machine"]=="mymachine"len(results["s02-enrich"]["crowdsecurity/dateparse-enrich"])==3...
results["s02-enrich"]["crowdsecurity/dateparse-enrich"][2].Evt.Meta["machine"]=="mymachine"results["s02-enrich"]["crowdsecurity/dateparse-enrich"][2].Evt.Enriched["MarshaledTime"]=="2023-12-08T06:28:43Z"len(results["success"][""])==0Please fill your assert file(s)fortest'myservice-logs', exiting
Que s’est-il passé ici ?
Nos journaux ont été traités par l’analyseur syslog-logs et notre analyseur personnalisé
Comme nous n’avons pas d’assertion(s) existante(s), cscli hubtest va en générer pour nous
Cela nous permet surtout de nous assurer que nos logs ont bien été traités par notre analyseur, même s’il est inutile dans son état actuel. Une inspection plus approfondie peut être vue avec cscli hubtest explain:
Nous gardons une trace du nom d’utilisateur et de la source_ip (Veuillez noter que la définition de la source_ip dans evt.Meta.source_ip et evt.Parsed.source_ip est importante [1] )
Nous configurons diverses informations statiques pour classer le type de journal [3]
Recommençons les tests :
INFO[28-07-2023 11:50:40] Running test'myservice-logs'WARN[28-07-2023 11:50:44] Assert file '/root/crowdsec/crowdsec-v1.5.2/tests/hub/.tests/myservice-logs/parser.assert' is empty, generating assertion:
len(results)==4len(results["s00-raw"]["crowdsecurity/syslog-logs"])==3results["s00-raw"]["crowdsecurity/syslog-logs"][0].Success ==trueresults["s00-raw"]["crowdsecurity/syslog-logs"][0].Evt.Parsed["message"]=="bad password for user 'toto' from '1.2.3.4'"...
results["s00-raw"]["crowdsecurity/syslog-logs"][2].Evt.Meta["machine"]=="mymachine"results["s00-raw"]["crowdsecurity/syslog-logs"][2].Evt.Meta["datasource_path"]=="myservice-logs.log"len(results["s01-parse"]["crowdsecurity/myservice-logs"])==3results["s01-parse"]["crowdsecurity/myservice-logs"][0].Success ==trueresults["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["program"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["source_ip"]=="1.2.3.4"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["logsource"]=="syslog"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["message"]=="bad password for user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["pid"]=="2806"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["timestamp"]=="Dec 8 06:28:43"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Parsed["user"]=="toto"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["service"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["source_ip"]=="1.2.3.4"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["username"]=="toto"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["datasource_path"]=="myservice-logs.log"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["datasource_type"]=="file"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["log_subtype"]=="myservice_bad_password"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["log_type"]=="myservice_failed_auth"results["s01-parse"]["crowdsecurity/myservice-logs"][0].Evt.Meta["machine"]=="mymachine"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Success ==trueresults["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["logsource"]=="syslog"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["source_ip"]=="1.2.3.4"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["message"]=="unknown user 'toto' from '1.2.3.4'"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["pid"]=="2806"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["program"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["timestamp"]=="Dec 8 06:28:43"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Parsed["user"]=="toto"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["service"]=="myservice"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["source_ip"]=="1.2.3.4"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["username"]=="toto"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["datasource_path"]=="myservice-logs.log"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["datasource_type"]=="file"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["log_subtype"]=="myservice_bad_user"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["log_type"]=="myservice_failed_auth"results["s01-parse"]["crowdsecurity/myservice-logs"][1].Evt.Meta["machine"]=="mymachine"results["s01-parse"]["crowdsecurity/myservice-logs"][2].Success ==falselen(results["s02-enrich"]["crowdsecurity/dateparse-enrich"])==2results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Success ==trueresults["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["pid"]=="2806"...
results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["timestamp"]=="2023-12-08T06:28:43Z"results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Enriched["MarshaledTime"]=="2023-12-08T06:28:43Z"len(results["success"][""])==0Please fill your assert file(s)fortest'myservice-logs', exiting
Nous pouvons voir que notre analyseur a capturé toutes les informations pertinentes, et cela devrait être suffisant pour créer des scénarios plus tard.
Encore une fois, une inspection plus approfondie avec cscli hubtest explain nous en dira plus sur ce qui s’est passé :
▶ ~/crowdsec/crowdsec-v1.5.2/tests/hub # cscli hubtest explain myservice-logsline: Dec 8 06:28:43 mymachine myservice[2806]: bad password for user 'toto' from '1.2.3.4' ├ s00-raw
| └ 🟢 crowdsecurity/syslog-logs (+12 ~9) ├ s01-parse
| └ 🟢 crowdsecurity/myservice-logs (+7 ~1) ├ s02-enrich
| └ 🟢 crowdsecurity/dateparse-enrich (+2 ~2) ├-------- parser success 🟢
├ Scenarios
line: Dec 8 06:28:43 mymachine myservice[2806]: unknown user 'toto' from '1.2.3.4' ├ s00-raw
| └ 🟢 crowdsecurity/syslog-logs (+12 ~9) ├ s01-parse
| └ 🟢 crowdsecurity/myservice-logs (+7 ~1) ├ s02-enrich
| └ 🟢 crowdsecurity/dateparse-enrich (+2 ~2) ├-------- parser success 🟢
├ Scenarios
line: Dec 8 06:28:43 mymachine myservice[2806]: accepted connection for user 'toto' from '1.2.3.4' ├ s00-raw
| └ 🟢 crowdsecurity/syslog-logs (+12 ~9) ├ s01-parse
└-------- parser failure 🔴
note: nous pouvons voir que notre ligne de journal accepted connection for user ’toto’ from ‘1.2.3.4’ n’a pas été analysée car nous n’avons pas de modèle pour cela
Une modification possible pour analyser cette ligne serait de changer le fichier parsers/s01-parse/crowdsecurity/myservice-logs.yaml en y ajoutant les lignes surlignées:
onsuccess: next_stage
filter: "evt.Parsed.program == 'myservice'"name: crowdsecurity/myservice-logs
description: "Parse myservice logs"#for clarity, we create our pattern syntax beforehandpattern_syntax:
MYSERVICE_BADPASSWORD: bad password for user '%{USERNAME:user}' from '%{IP:source_ip}'#[1] MYSERVICE_BADUSER: unknown user '%{USERNAME:user}' from '%{IP:source_ip}'#[1] MYSERVICE_GOODUSER: accepted connection for user '%{USERNAME:user}' from '%{IP:source_ip}'#[1]nodes:
#and we use them to parse our two type of logs - grok:
name: "MYSERVICE_BADPASSWORD"#[2] apply_on: message
statics:
- meta: log_type #[3] value: myservice_failed_auth
- meta: log_subtype
value: myservice_bad_password
- grok:
name: "MYSERVICE_BADUSER"#[2] apply_on: message
statics:
- meta: log_type #[3] value: myservice_failed_auth
- meta: log_subtype
value: myservice_bad_user
- grok:
name: "MYSERVICE_GOODUSER"#[2] apply_on: message
statics:
- meta: log_type #[3] value: myservice_success_auth
- meta: log_subtype
value: myservice_good_user
statics:
- meta: service #[3] value: myservice
- meta: username
expression: evt.Parsed.user
- meta: source_ip #[1] expression: "evt.Parsed.source_ip"
Nous avons maintenant un analyseur entièrement fonctionnel pour les journaux de myservice ! Nous pouvons soit le déployer sur nos systèmes de production pour faire des choses, soit mieux encore, contribuer au hub !