tis-wazuh-plugin-import-from-wazuh

26-1
Plugin for importing wazuh breaches in wapt data audit
1070 downloads
Download
See build result See VirusTotal scan
tis-wazuh-plugin-import-from-wazuh icon

tis-wazuh-plugin-import-from-wazuh

This package allows CVEs detected by Wazuh to be reported in the audit data of the affected machines in WAPT.

The audit is performed automatically every hour.

The result is saved in the audit data under the key wazuh.

Two types of results are possible:

  • ✅ OK → The data transfer from Wazuh to WAPT is working correctly.
  • ❌ ERROR → A package configuration error is preventing proper operation.

To benefit from the latest updates, it is recommended to:

  • Clone the package from Tranquil IT's WAPT repository.

How the package works:

  • Deploy the package on the Wazuh server
  • Go to /opt/wapt/private
  • Modify the files "elastic_wazuh_api.ini" and "wapt_api.ini" with your information
  • Run the package audit to verify everything is working correctly

elastic_wazuh_api.ini :

[elastic] username = account to connect to elastic_search
password = account password
instance_name = name of the elastic_search instance (Wazuh instance or cluster name)
verify_cert = False/True
url = https://127.0.0.1:9200 - URL to connect to elastic_search
wazuh_url = https://srvwazuh.mydomain.lan - Wazuh server URL

wapt_api.ini :

[wapt] username = waptapi - WAPT account to read and store audit data
password = password - Account password
url = https://mywapt.mydomain.lan - WAPT server URL

  • package : tis-wazuh-plugin-import-from-wazuh
  • name : Plugin Import Wazuh
  • version : 26-1
  • categories :
  • maintainer : Simon Fonteneau ,Tranquil IT
  • editor :
  • licence :
  • locale :
  • target_os : all
  • impacted_process :
  • architecture : all
  • signature_date : 2025-06-08 14:02
  • size : 8.99 Ko
package           : tis-wazuh-plugin-import-from-wazuh
version           : 26-1
architecture      : all
section           : base
priority          : optional
name              : Plugin Import Wazuh
categories        : 
maintainer        : Simon Fonteneau ,Tranquil IT
description       : Plugin for importing wazuh breaches in wapt data audit
depends           : 
conflicts         : 
maturity          : PROD
locale            : 
target_os         : all
min_wapt_version  : 
sources           : 
installed_size    : 
impacted_process  : 
description_fr    : 
description_pl    : 
description_de    : 
description_es    : 
description_pt    : 
description_it    : 
description_nl    : 
description_ru    : 
audit_schedule    : 1h
editor            : 
keywords          : 
licence           : 
homepage          : 
package_uuid      : 7671a839-3f96-41d5-a012-4fcad2f6474d
valid_from        : 
valid_until       : 
forced_install_on : 
changelog         : 
min_os_version    : 
max_os_version    : 
icon_sha256sum    : ab03226aa75b0f33fcb7fe327fa164535e5410d0b5cbe02fdd5e124a017f9cb9
signer            : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date    : 2025-06-08T14:02:31.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature         : oR6I7zDUtjJV0+2c/0RUpGzHEPPMv34i9EHRyxyF5s1etbtEV2a1Z8Bsx2rzPckJ4Bg6nxjAzd3mknMbbZCiPsZ6oP5LkTZp5myWO+6Z6MD41QjHPvZ22Itod2R+wyOfONgEubU2PpbNJNYb6Mjr1BS9CKESN3ZnILaOtos6ME/g5LZIfO6vJKEckEuvatqZfH3GbY9oTisJtYUG83pPMT6UY6MXHL427Rbw/FtL59q0f3+R34l0EXgI0gFFyXbc39CTS0xLekpUAfmQuBZWYCvcZrtPDU2wBwcE8+uXR1Fipu5CpkBmJW0fbdLx+MquXQk74J9zFg2vYJj2kBYE9Q==
# -*- coding: utf-8 -*-
from setuphelpers import *
from configparser import ConfigParser
from waptutils import get_verify_cert
from common import get_requests_client_cert_session
import platform
import waptlicences
import json
import concurrent.futures
import requests
from requests.auth import HTTPBasicAuth
import datetime

simultaneous_maximum_send=10

def audit():
    CONFWAPT = ConfigParser()
    CONFWAPT.read(makepath(WAPT.private_dir, "wapt_api.ini"))
    username_wapt = CONFWAPT.get("wapt", "username")
    password_wapt = CONFWAPT.get("wapt", "password")
    srvwapt_url = CONFWAPT.get("wapt", "url")


    t = waptlicences.waptserver_login(WAPT.config_filename,username_wapt,password_wapt)
    if not 'session' in t['session_cookies']:
        session_cookies = [u for u in t['session_cookies'] if u['Domain'] == WAPT.waptserver.server_url.split('://')[-1]][0]
    else:
        session_cookies = t['session_cookies']['session']
        session_cookies['Name'] = 'session'

    sessionwapt = get_requests_client_cert_session(WAPT.waptserver.server_url,cert=(t['client_certificate'],t['client_private_key'],t['client_private_key_password']),verify=WAPT.waptserver.verify_cert)
    sessionwapt.cookies.set(session_cookies['Name'], session_cookies['Value'], domain=session_cookies['Domain'])
    sessionwapt.verify = WAPT.waptserver.verify_cert

    CONFWAZUH = ConfigParser()
    CONFWAZUH.read(makepath(WAPT.private_dir, "elastic_wazuh_api.ini"))
    url_elastic = CONFWAZUH.get("elastic", "url")
    username_elastic = CONFWAZUH.get("elastic", "username")
    password_elastic = CONFWAZUH.get("elastic", "password")
    instance_name_elastic = CONFWAZUH.get("elastic", "instance_name")
    wazuh_url = CONFWAZUH.get("elastic", "wazuh_url")

    if CONFWAZUH.has_option("elastic", 'verify_cert'):
        verify_cert_wz = get_verify_cert(CONFWAZUH.get("elastic", 'verify_cert'))
    else:
        verify_cert_wz = True

    dict_hostname_uuid = {}

    for pc in json.loads(sessionwapt.get("%s/api/v3/hosts?&limit=1000000" % WAPT.waptserver.server_url).content)["result"]:
        dict_hostname_uuid[str(pc["computer_name"]).lower()] = pc["uuid"]

    list_error = []


    list_run = []

    for hostname, uuid in dict_hostname_uuid.items():
        list_run.append({
            "sessionwapt": sessionwapt,
            "dict_hostname_uuid": {hostname: uuid},
            "WAPT": WAPT,
            "hostname":hostname,
            "list_error":list_error,
            "url_elastic": url_elastic,
            "username_elastic" : username_elastic,
            "password_elastic" : password_elastic,
            "instance_name_elastic" : instance_name_elastic,
            "verify_cert_wz" : verify_cert_wz,
            "wazuh_url" : wazuh_url
        })

    results = []
    with concurrent.futures.ThreadPoolExecutor(simultaneous_maximum_send) as executor:
        futures = {executor.submit(import_from_wazuh, **g): g for g in list_run}

        for future in concurrent.futures.as_completed(futures):
            results.append(future.result())


    waptlicences.waptserver_logout(WAPT.config_filename)

    if list_error:
        print(" \n".join(list_error))
        return "ERROR"
    else:
        return "OK"

def import_from_wazuh(sessionwapt=None,url_elastic=None,username_elastic=None,password_elastic=None,instance_name_elastic=None,dict_hostname_uuid=None,WAPT=None,hostname=None,list_error=None,verify_cert_wz=True,wazuh_url=None):

            waptdata = []

            try:

                # URL d'accès à l'index Elasticsearch pour les vulnérabilités
                url = f"{url_elastic}/wazuh-states-vulnerabilities-{instance_name_elastic}/_search"

                # Construction de la requête avec un filtre sur l'agent si nécessaire
                query = {
                    "_source": [
                        "agent.id",
                        "agent.name",
                        "vulnerability.id",
                        "vulnerability.severity",
                        "vulnerability.reference",
                        "vulnerability.score.base",
                        "package.name",
                        "package.version"
                    ],
                    "size": 100,
                    "sort": [
                        {
                            "_score": {
                                "order": "desc"
                            }
                        }
                    ],
                    "query": {
                        "wildcard": {
                            "agent.name": {
                                "value": hostname,
                                "case_insensitive": True
                            }
                        }
                    }
                }

                # Envoi de la requête GET à Elasticsearch
                response = requests.get(url, auth=HTTPBasicAuth(username_elastic, password_elastic), headers={'Content-Type': 'application/json'}, json=query, verify=verify_cert_wz)
                response.raise_for_status()

                data = response.json()

                vulnerabilities = data.get('hits', {}).get('hits', [])

                result = {"cve":{},"max_score_base":0,"status":"compliant" ,"list_patch": {},"wazuh_url":wazuh_url,"agent_id": {}}
                for vuln in vulnerabilities:
                    source = vuln["_source"]
                    cve_id = source.get("vulnerability", {}).get("id")
                    score_base = source.get("vulnerability", {}).get("score").get("base")
                    package_name = source.get("package", {}).get("name")
                    agent_id = source.get("agent", {}).get("id")
                    result['cve'][cve_id] = {
                        "agent_name": source.get("agent", {}).get("name"),
                        "score_base": score_base,
                        "vulnerability_id": cve_id,
                        "package_name": package_name,
                        "package_version": source.get("package", {}).get("version"),
                        "severity": source.get("vulnerability", {}).get("severity"),
                        "reference": source.get("vulnerability", {}).get("reference")
                    }
                    if package_name :
                        result['list_patch'][package_name.replace(' ','_')] = package_name
                    if agent_id :
                        result['agent_id'] = agent_id
                    result['status'] = 'vulnerable'
                    if score_base > result['max_score_base']:
                        result['max_score_base'] = score_base
                result['list_patch_list'] = list(result['list_patch'])


                ##################################################################

                waptdata.append(
                    {
                        "host_id": dict_hostname_uuid[str(hostname).lower()],
                        "value_id": int(time.monotonic() * 1000),
                        "value_date": datetime2isodate(datetime.datetime.utcnow()),
                        "value_section": "wazuh",
                        "value_key": "wazuh",
                        "value": result,
                        "expiration_date": datetime2isodate(datetime.datetime.utcnow() + datetime.timedelta(minutes=1440)),
                    }
                )
                print("Get %s from wazuh" % str(hostname).lower())
                time.sleep(0.0000001)

            except Exception as e:
                list_error.append("Error %s %s" % (str(hostname).lower(), str(e)))

            sessionwapt.post("%s/api/v3/update_hosts_audit_data" % WAPT.waptserver.server_url, data=json.dumps(waptdata))



def install():
    if not isfile(makepath(WAPT.private_dir, "elastic_wazuh_api.ini")):
        filecopyto("elastic_wazuh_api.ini", makepath(WAPT.private_dir, "elastic_wazuh_api.ini"))
    if not isfile(makepath(WAPT.private_dir, "wapt_api.ini")):
        filecopyto("wapt_api.ini", makepath(WAPT.private_dir, "wapt_api.ini"))



def list_to_dict(newkey=None, listconvert=None):
    newdict = {}
    for p in listconvert:
        newdict[p[newkey]] = p
    return newdict
fa941f3c5789cd760e2560d387a4acd8c29ce43d71e3c6e2946f305e77a99d26 : WAPT/README.md
e9aa386b6e8872abd808802c5d042cdbcdd1db1842cebc146476864e147d8086 : WAPT/README_fr.md
38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
86c4f984733c99b59b29f6ca35350feb4227cc6556de56b214f77617f1dfacc1 : WAPT/control
ab03226aa75b0f33fcb7fe327fa164535e5410d0b5cbe02fdd5e124a017f9cb9 : WAPT/icon.png
b41d8970d1fd0d06f9be052f55ee3544e9d6cdbce6d348f669e3791d77dedec7 : elastic_wazuh_api.ini
11f563b87bc554bec2c1e6f44257375b949863ddae80fb27a775379f49e4c0c5 : luti.json
f52601023fac6b0c0a3f55625c19773c3015b87f15861e33ee3c68cd6a97d432 : setup.py
cb302f842cf1695f553389a436898f9e580d7d866a6726789dca1994a55e9c3c : wapt_api.ini