Wazuh¶
Qu’est-ce que Wazuh ?¶
Wazuh est un SIEM qui embarque des fonctionnalité d’HIDS. Ce dernier est découpé en trois fonctionalitées, l’indexer, le server et le dashboard. Chaque service peut-être décentralisé et multiplié.
Installation¶
Deux méthodes, la très rapide et la manuelle.
la très rapide implique que l’on a pas de serveur web déjà installé (ou qu’on configure le port par défaut) ; que l’on est sur un serveur supporté (ou qu’on enleve le check avec -i), et pleins d’autres petits trucs.
curl -sO https://packages.wazuh.com/4.7/wazuh-install.sh && sudo bash ./wazuh-install.sh -a
La manuelle demande un peu plus de préparation.
Installation des dépots de Wazuh¶
apt-get install gnupg apt-transport-https
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import && chmod 644 /usr/share/keyrings/wazuh.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | tee -a /etc/apt/sources.list.d/wazuh.list
apt-get update
Génération des certificats¶
Whazuh génère automatiquement ces certificats. Ces derniers utilisent du RSA 2048 et d’autres mochetés qui ne me plaisent pas. Bref, pleins de trucs que l’on va essayer de changer pour se faire nos propres certificats.
Pour ces certificats, Wazuh indique avoir besoin des KeyUsage suivants digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment. Dans mon cas, ce qui s’en rapproche le plus est celui que je mets sur les pare-feu (car les serveurs n’ont pas le KU nonRepudiation). Je vais faire les certificats en Server dans un premier temps, et si ces derniers ont vraiment besoin du KU nonRepudiation, je créerais un certificat particulier.
Ce qui nous donne en rsa :
/!\ Avec Wazuh 4.7.3, les certificats ecdsa remontent une erreur. Cette dernière semble être lié à la version utilisée de bouncycastle. J’ai ouvert une issue sur leur github, on verra pour les prochaines versions.
/!\ Vous voulez un truc fun ? Le filebeat (donc core) a besoin d’un certificat client pour pouvoir parler avec le serveur (indexer). Enjoy les pannes non prévu et chiante à débuger.
SERVER;SIEM.prj.luclis.fr;Roubaix;adminca@luclis.fr;ext.prj.luclis.fr;siem.luclis.fr;dashboard.luclis.fr;Certificat pour le Dashboard de Wazuh
SERVER;indexer.prj.luclis.fr;Roubaix;adminca@luclis.fr;ext.prj.luclis.fr;siem.luclis.fr;indexer.luclis.fr;Certificat pour l'indexer de Wazuh
CLIENT;core.prj.luclis.fr;Roubaix;adminca@luclis.fr;ext.prj.luclis.fr;siem.luclis.fr;core.luclis.fr;Certificat pour le server core de Wazuh
CLIENT;admin.prj.luclis.fr;Roubaix;adminca@luclis.fr;;;Certificat pour le server core de Wazuh
On pense bien à déplacer nos certificats. Wazuh s’isole dans son dossier une fois lancer. il va donc falloir viser les dossiers certs de wazuh.
for i in SIEM core indexer ; do
case $i in
SIEM) location="wazuh-dashboard";;
core) location="filebeat";;
indexer) location="wazuh-indexer";;
esac
mkdir -p /etc/${location}/certs #Si les services ne sont pas encore installés, on créer les dossiers
cp /srv/IGC/luclis.fr/delegated_ca/private/${i}.prj.luclis.fr.key /etc/${location}/certs/
cp /srv/IGC/luclis.fr/delegated_ca/public/${i}.prj.luclis.fr.pem /etc/${location}/certs/
cp /srv/IGC/luclis.fr/root_ca/public/ACR_LUCLIS.pem /etc/${location}/certs/
cp /srv/IGC/luclis.fr/delegated_ca/public/ACD_LUCLIS.pem /etc/${location}/certs/
chmod 400 /etc/${location}/certs/*
done
Note : Le nom de chaque serveur est donc défini ici. Ce sera indexer.prj.luclis.fr pour l’indexer, core.prj.luclis.fr pour le serveur, et siem.prj.luclis.fr pour le dashboard.
Note 2 : En regardant la configuration de wazuh, on peut se rendre compte qu’il embarque plusieurs « sous-rôles » qui demandent également des certificats. Ces sous rôles sont mutualisé en fonction du rôle principal (ex : indexer possède une page web et un transport). A voir la plus-value de créer des certificats différents pour chaque.
Installation de l’indexer¶
apt-get -y install wazuh-indexer
Une fois l’indexer de configurer, il faut personnaliser son fichier de configuration. Celui-ci se trouve sous /etc/wazuh-indexer/opensearch.yml.
Dans mon cas, je vais faire pas mal de modification vu que j’ai des cas d’usage très spécifiques.
network.host: "127.0.0.1" #Ecoute uniquement sur la localhost
node.name: "indexer.prj.luclis.fr" #Le nom du node "indexer".
cluster.initial_master_nodes:
- "indexer.prj.luclis.fr" #Le nom du node "indexer".
#- "node-2" #Garder pour historique
#- "node-3"
cluster.name: "wazuh-cluster" #Je sais pas à quoi il sert
#discovery.seed_hosts:
# - "node-1-ip" #Pas utile dans le cas d'un single node
# - "node-2-ip"
# - "node-3-ip"
node.max_local_storage_nodes: "3"
path.data: /var/lib/wazuh-indexer
path.logs: /var/log/wazuh-indexer
plugins.security.ssl.http.pemcert_filepath: certs/indexer.prj.luclis.fr.pem
plugins.security.ssl.http.pemkey_filepath: certs/indexer.prj.luclis.fr.key
plugins.security.ssl.http.pemtrustedcas_filepath: certs/ca_chain.pem
plugins.security.ssl.transport.pemcert_filepath: certs/indexer.prj.luclis.fr.pem
plugins.security.ssl.transport.pemkey_filepath: certs/indexer.prj.luclis.fr.key
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/ca_chain.pem
plugins.security.ssl.http.enabled: true
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.transport.resolve_hostname: false
plugins.security.authcz.admin_dn:
- "CN=admin.prj.luclis.fr,EMAILADDRESS=adminca@luclis.fr,OU=LUCLIS CA UNIT,O=LUCLIS,L=Roubaix,ST=FRANCE,C=FR" #Notre Subject du certificat admin
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.enable_snapshot_restore_privilege: true
plugins.security.nodes_dn:
- "CN=indexer.prj.luclis.fr,EMMAILADDRESS=adminca@luclis.fr,OU=LUCLIS CA UNIT,O=LUCLIS,L=Roubaix,ST=FRANCE,C=FR" #Notre subject du certificat indexer.prj
#- "CN=node-2,OU=Wazuh,O=Wazuh,L=California,C=US"
#- "CN=node-3,OU=Wazuh,O=Wazuh,L=California,C=US"
plugins.security.restapi.roles_enabled:
- "all_access"
- "security_rest_api_access"
plugins.security.system_indices.enabled: true
plugins.security.system_indices.indices:
[
".plugins-ml-model",
".plugins-ml-task",
".opendistro-alerting-config",
".opendistro-alerting-alert*",
".opendistro-anomaly-results*",
".opendistro-anomaly-detector*",
".opendistro-anomaly-checkpoints",
".opendistro-anomaly-detection-state",
".opendistro-reports-*",
".opensearch-notifications-*",
".opensearch-notebooks",
".opensearch-observability",
".opendistro-asynchronous-search-response*",
".replication-metadata-store",
]
### Option to allow Filebeat-oss 7.10.2 to work ###
compatibility.override_main_response_version: true
Maintenant, il suffit d’initialiser le cluster ELK. Pour cela, Wazuh doit avoir, au moins temporairement accès à vos certificats admins.
cp /srv/IGC/luclis.fr/delegated_ca/private/admin.prj.luclis.fr.key /etc/wazuh-indexer/certs/admin-key.pem
cp /srv/IGC/luclis.fr/delegated_ca/public/admin.prj.luclis.fr.pem /etc/wazuh-indexer/certs/admin.pem
chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/certs/admin*
/usr/share/wazuh-indexer/bin/indexer-security-init.sh
**************************************************************************
** This tool will be deprecated in the next major release of OpenSearch **
** https://github.com/opensearch-project/security/issues/1755 **
**************************************************************************
Security Admin v7
Will connect to 127.0.0.1:9200 ... done
Connected as "CN=admin.prj.luclis.fr,EMAILADDRESS=adminca@luclis.fr,OU=LUCLIS CA UNIT,O=LUCLIS,L=Roubaix,ST=FRANCE,C=FR"
OpenSearch Version: 2.8.0
[...]
Done with success
Et c’est fini ! On peut se lancer à l’installation du server core.
Installation du server core¶
Normalement cette partie devrait être plus rapide car l’on dispose déjà des certificats et des repos. Dans le cas où tu t’es lancé sur une installation multinode, tu sais ce que tu as à faire !
apt-get -y install wazuh-manager filebeat
systemctl daemon-reload
systemctl enable wazuh-manager
systemctl start wazuh-manager
Configuration de FileBeat¶
Pour configurer filebeat, le plus simple et de s’inspirer du fichier que fourni Wazuh et de modiifer ce qui nous importe.
curl -so /etc/filebeat/filebeat.yml https://packages.wazuh.com/4.7/tpl/wazuh/filebeat/filebeat.yml
vi /etc/filebeat/filebeat.yml
ssl.certificate_authorities:
- "/etc/filebeat/certs/ACR_LUCLIS.pem"
- "/etc/filebeat/certs/ACD_LUCLIS.pem"
ssl.certificate: "/etc/filebeat/certs/core.prj.luclis.fr.pem"
ssl.key: "/etc/filebeat/certs/core.prj.luclis.fr.key"
Comme on peut le voir dans le fichier de configuration, trois points sont importants : le mot de passe ; les certificats et le fichier wazuh-templates.
Normalement, l’histoire des certificats a déjà été réglée. Faites bien attention à ce qu’ils aient l’EKU clientAuth Sinon ces derniers ne pourront pas joindre l’indexer.
Pour le fichier template, il suffit de le télécharger. Ce dernier doit être accompagner des modules liés à Wazuh :
curl -so /etc/filebeat/wazuh-template.json https://raw.githubusercontent.com/wazuh/wazuh/v4.7.3/extensions/elasticsearch/7.x/wazuh-template.json
chmod 644 /etc/filebeat/wazuh-template.json
curl -s https://packages.wazuh.com/4.x/filebeat/wazuh-filebeat-0.3.tar.gz | tar -xz -C /usr/share/filebeat/module
Note : Je suis pas sûr que le 644 serve à quelquechose Enfin, concernant les mots de passe, on regardera pour les changer plus tard. En attendant, il faut les mettre dans un keystore.
filebeat keystore create
echo admin | filebeat keystore add username --stdin --force
echo admin | filebeat keystore add password --stdin --force
Pour info, le keystore est stocké sous /var/lib/filebeat/filebeat.keystore.
Normalement, ici tout est bon. On a plus qu’à lancer le service filebeat
systemctl daemon-reload
systemctl enable filebeat
systemctl start filebeat
Tester c’est douter ? Bah je doute de plus en plus de wazuh vu ce que je débug alors testons :
filebeat test output
elasticsearch: https://indexer.prj.luclis.fr:9200...
parse url... OK
connection...
parse host... OK
dns lookup... OK
addresses: 127.0.0.1
dial up... OK
TLS...
security: server's certificate chain verification is enabled
handshake... OK
TLS version: TLSv1.3
dial up... OK
talk to server... OK
version: 7.10.2
Si tout va bien, on peut passer à l’installation du dashboard. Sinon, j’ai eu un problème sur la ligne talk to server : mon certificat « core » ne disposait de l’EKU serveurAuth, donc il ne pouvait pas joindre l’indexer.
Installation du serveur dashboard¶
Bon, on espère ne pas trop avoir de soucis ici … On va bien voir. Comme toujours, pré-requis = certificats & repository.
apt-get -y install wazuh-dashboard
On modifie ensuite le fichier de configuration du dashboard. Comme mon port 443 est déjà pris par le nginx, je vais le faire tourner sur le port 9201, celui juste après l’opensearch. Pour ça, on modifie le fichier etc/wazuh-dashboard/opensearch_dashboards.yml
server.host: 127.0.0.1
server.port: 9201
opensearch.hosts: https://indexer.prj.luclis.fr:9200
server.ssl.key: "/etc/wazuh-dashboard/certs/SIEM.prj.luclis.fr.key"
server.ssl.certificate: "/etc/wazuh-dashboard/certs/SIEM.prj.luclis.fr.pem"
opensearch.ssl.certificateAuthorities:
[
"/etc/wazuh-dashboard/certs/ACR_LUCLIS.pem",
"/etc/wazuh-dashboard/certs/ACD_LUCLIS.pem",
]
On peut donc maintenant lancer le service dashboard.
systemctl daemon-reload
systemctl enable wazuh-dashboard
systemctl start wazuh-dashboard
Et voilà, votre SIEM devrait fonctionner ! Bon, pour ma part, il me reste à configurer le nginx pour faire reverse proxy.
Configuration¶
Configuration de Nginx comme reverse proxy¶
Bon, on commence à avoir l’habitude d’utiliser nginx en simple proxy. Ici, je veux qu’il ne tourne que sur le réseau VPN interne.
#SIEM nginx conf
server {
listen 192.168.3.193:80;
server_name siem.luclis.fr;
return 301 https://$host$request_uri;
}
server {
listen 192.168.3.193:443 ssl;
# http3 on;
server_name siem.luclis.fr;
ssl_certificate /etc/ssl/public/SIEM.luclis.fr_chain.pem;
ssl_certificate_key /etc/ssl/private/SIEM.luclis.fr.key;
# ssl_password_file /etc/ssl/private/SIEM.luclis.fr.pass;
# this is the SIEM web root directory
# (mentioned in the output of "systemctl cat SIEM")
root /var/lib/jenkins/war/;
access_log /var/log/nginx/SIEM.access.log;
error_log /var/log/nginx/SIEM.error.log;
location / {
proxy_pass https://localhost:9201
proxy_set_header Host $host;
}
}
Je copie les certificats, j’active le site sur Nginx, et je relance le serveur
cp /srv/IGC/luclis.fr/delegated_ca/private/SIEM.prj.luclis.fr.key /etc/ssl/private/
cat /srv/IGC/luclis.fr/delegated_ca/public/SIEM.prj.luclis.fr.pem /etc/ssl/public/ca_chain.pem > /etc/ssl/public/SIEM.luclis.fr_chain.pem
Configuration du ldap¶
J’ai choisi wazuh entre autre parce qu’il supporte le ldap par défaut. On va tester tout ça. On commence donc par lui créer un compte de service dédier.
samba-tool user add --random-password --login-shell=/bin/false --userou="OU=SERVICE" svc_wazuh
samba-tool group addmembers "Services Accounts" svc_wazuh
samba-tool user setpassword svc_wazuh
samba-tool group add "Wazuh Admins" --groupou
samba-tool group add "Wazuh Users" --groupou "OU=GROUPS"
samba-tool group addmembers "Wazuh Admins" adm_svc-l.filippi
samba-tool group addmembers "Wazuh Users" lucas.filippi
On peut enfin se lancer dans la modification du fichier de configuration. Celui-ci se trouve sous etc/wazuh-indexer/opensearch-security/config.yml.
authc:
ldap:
description: "Authenticate via LDAP or Active Directory"
http_enabled: true
transport_enabled: false
order: 5
http_authenticator:
type: basic
challenge: false
authentication_backend:
# LDAP authentication backend (authenticate users against a LDAP or Active Directory)
type: ldap
config:
enable_ssl: true
pemtrustedcas_filepath: /etc/wazuh-indexer/certs/ca_chain.pem
enable_start_tls: false
# send client certificate
enable_ssl_client_auth: false
# verify ldap hostname
verify_hostnames: true
hosts:
- ad.luclis.fr:636
bind_dn: "CN=svc_wazuh,OU=SERVICE,DC=LUCLIS,DC=FR"
password: "YOURPASSWORD"
userbase: "DC=LUCLIS,DC=FR"
# Filter to search for users (currently in the whole subtree beneath userbase)
# {0} is substituted with the username
usersearch: "(|(sAMAccountName={0})(email={0})"
# Use this attribute from the user as username (if not set then DN is used)
username_attribute: "sAMAccountName" #Faudra tester avec le CN
authz:
roles_from_myldap:
description: "Authorize via LDAP or Active Directory"
http_enabled: true
transport_enabled: true #A vérifier
authorization_backend:
type: ldap
config:
enable_ssl: true
pemtrustedcas_filepath: /etc/wazuh-indexer/certs/ca_chain.pem
enable_start_tls: false
# send client certificate
enable_ssl_client_auth: false
# verify ldap hostname
verify_hostnames: true
hosts:
- ad.luclis.fr:636
bind_dn: "CN=svc_wazuh,OU=SERVICE,DC=LUCLIS,DC=FR"
password: "YOURPASSWORD"
rolebase: "OU=GROUP,DC=LUCLIS,DC=FR"
# Filter to search for roles (currently in the whole subtree beneath rolebase)
# {0} is substituted with the DN of the user
# {1} is substituted with the username
# {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
rolesearch: "(member={0})"
userroleattribute: null
# Roles as an attribute of the user entry
userrolename: disabled
# The attribute in a role entry containing the name of that role, Default is "name".
# Can also be "dn" to use the full DN as rolename.
rolename: cn
resolve_nested_roles: false
userbase: "DC=LUCLIS,DC=FR"
# Filter to search for users (currently in the whole subtree beneath userbase)
# {0} is substituted with the username
usersearch: "(uid={0})"
# Skip users matching a user name, a wildcard or a regex pattern
skip_users:
- admin
- kibanaserver
On lance le script pour mettre à jour les privllèges.
export JAVA_HOME=/usr/share/wazuh-indexer/jdk/ && bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -f /etc/wazuh-indexer/opensearch-security/config.yml -icl -key /etc/wazuh-indexer/certs/admin-key.pem -cert /etc/wazuh-indexer/certs/admin.pem -cacert /etc/wazuh-indexer/certs/ca_chain.pem -h localhost -nhnv
Puis l’on modifie les rôles… Pour ça, c’est le fichier /etc/wazuh-indexer/opensearch-security/roles_mapping.yml
all_access:
reserved: true
hidden: false
backend_roles:
- "admin"
- "Wazuh Admins"
hosts: []
users: []
and_backend_roles: []
description: "Maps admin to all_access"
Et enfin, on recharge la configuration :
export JAVA_HOME=/usr/share/wazuh-indexer/jdk/ && bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -f /etc/wazuh-indexer/opensearch-security/roles_mapping.yml -icl -key /etc/wazuh-indexer/certs/admin-key.pem -cert /etc/wazuh-indexer/certs/admin.pem -cacert /etc/wazuh-indexer/certs/ca_chain.pem -h localhost -nhnv
Configuration d’un rsyslog¶
Wazuh propose d’utiliser syslog pour récupérer les informations des devices sur lesquels on ne peut pas installer son agent. Pour cela, il faut faire une modification dans le fichier de configuration de wazuh /var/ossec/etc/ossec.conf et rajouter le bloc suivant :
<remote>
<connection>syslog</connection>
<port>514</port>
<protocol>udp</protocol>
<allowed-ips>10.0.0.0/24</allowed-ips>
<local_ip>10.0.0.1</local_ip>
</remote>
Avec dans la partie allowed-ips le réseau que wazuh acceptera de loger et en local_ip l’adresse sur laquel il lancera son bind syslog.
/!\ Ces petits c… chenapans ont mis un - pour le premier et un _ pour le second ! Et passons sur le s de allowed-ips, qui est tout aussi chiant pour l’utilisateur.
Une fois la modification faite, on rédémarre le service :
systemctl restart wazuh-manager
Et l’on peut configurer le syslog sur les devices terminaux.
Sécurisation¶
Réinistialisation des mots de passes de Wazuh¶
L’équipe a été plutôt cool sur ce sujet, ils ont créer un script de réinitialisation des mots de passes. Une fois les mots de passes changer, il faut répliquer ces changement sur les autres parties de l’applications soit filebeat puis le dashboard. Filebeat a besoin du mot de passe admin. le dashboard, de celui de kibana. On va également en profiter pour réinitialiser les mots de passes des API la première fois, comme ce dernier vaut wazuh par défaut …
cd /etc/wazuh-indexer
/usr/share/wazuh-indexer/plugins/opensearch-security/tools/wazuh-passwords-tool.sh -a -A -au wazuh -ap wazuh
INFO: Wazuh API admin credentials not provided, Wazuh API passwords not changed.
INFO: The password for user admin is wcAny.XUwOVWHFy.+7tW9l8gUW1L8N3j
INFO: The password for user kibanaserver is qy6fBrNOI4fD9yR9.Oj03?pihN6Ejfpp
INFO: The password for user kibanaro is Nj*sSXSxwntrx3O7m8ehrgdHkxCc0dna
INFO: The password for user logstash is nQg1Qw0nIQFZXUJc8r8+zHVrkelch33h
INFO: The password for user readall is s0iWAei?RXObSDdibBfzSgXdhZCD9kH4
INFO: The password for user snapshotrestore is Mb2EHw8SIc1d.oz.nM?dHiPBGk7s?UZB
08/03/2024 12:03:59 WARNING: Wazuh indexer passwords changed. Remember to update the password in the Wazuh dashboard and Filebeat nodes if necessary, and restart the services.
08/03/2024 12:04:01 INFO: The password for Wazuh API user wazuh is ..bmJVOepyjA4Bq77EgRZlP.R5NPX2ro
08/03/2024 12:04:02 INFO: The password for Wazuh API user wazuh-wui is pa.Xx1.z4vfGT.fKKLI8LxXE9nWXoweG
08/03/2024 12:04:02 INFO: Updated wazuh-wui user password in wazuh dashboard. Remember to restart the service.
systemctl restart wazuh-dashboard.service wazuh-indexer wazuh-manager.service filebeat.service
Normalement, comme on est dans un environnement all-in-one, tout ça devrait suffire … Spoiler alert ? Un bug fait planter le dashboard, il faut flush tous les cookies.
Utilisation¶
Agents¶
L’installation des agents et plutôt simple. C’est principalement un unique paquet Linux auquel on rajoute des informations. Chaque AGENT_NAME doit être unique, il suffit de mettre le nom de la machine.
wget https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_4.7.3-1_amd64.deb
sudo WAZUH_MANAGER='siem.luclis.fr' WAZUH_AGENT_NAME="$HOSTNAME" dpkg -i ./wazuh-agent_4.7.3-1_amd64.deb
Attention, quand vous installer ces agents, il faut penser à ouvrir le pare-feu côté serveur (et client) !
iptables -A INPUT -p tcp -m tcp --dport 1514 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 1515 -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp --sport 1514 -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp --sport 1515 -j ACCEPT
Configuration adaptée à Nginx¶
Configuration adaptée à PiHole¶
TroubleShooting¶
Notes¶
Durant toutes les phases de l’installation de wazuh, je trouve que ce dernier n’est pas « propre ».
On est bloqué dans les certificats que l’on utilise ;
Ces derniers sont absolument pas explicite et utilisent des KU/EKU non définis …
Pour initialiser le cluster, on utilise une fonctionnalité qui sera bientôt obsolète
Le mot de passe admin admin en dur à l’install ? Sérieux ?
Et ce même token ecrit en brute dans un terminal puis stocké dans un keystore java ?
Enfin, l’installation écrit des fichiers de partout. /usr/share ; /etc/ ; /var/lib … Woaw !