AI WITH WAZUH

223 views
Skip to first unread message

heelp

unread,
Sep 25, 2024, 7:13:49 AM9/25/24
to Wazuh | Mailing List
hello 

Can you help me with this? I’m trying to integrate the Gemini API with Wazuh to get an AI-generated description for alerts with a rule level of 15, but I’m not sure where the problem lies.

/var/ossec/etc/ossec.conf

<integration>
  <name>gemini.py</name>
  <rule_id>92213</rule_id>
  <level>15</level>
  <group>sysmon, sysmon_eid11_detections, windows</group>
  <event_location>/var/log/syslog</event_location>
  <alert_format>json</alert_format>
</integration>

script python 

/var/ossec/integrations/gemini.py

    import json
    import os
    import requests
    import time

    def send_to_gemini_api(full_log):
       
        headers = {
            'Content-Type': 'application/json'
        }
       
        modified_full_log = f"In one paragraph, tell me about the impact and how to mitigate {full_log}"

        payload = {
            'contents': [
                {
                    'parts': [
                        {
                            'text': modified_full_log  
                        }
                    ]
                }
            ]
        }

        try:
            response = requests.post(api_url, headers=headers, json=payload)
            response.raise_for_status()  
            return response.json()  
        except requests.exceptions.RequestException as e:
            return None

    def read_and_process_logs(log_file, rate_limit=1):
       
        if not os.path.exists(log_file):
            return

        with open(log_file, 'r') as f:
            for line in f:
                try:
                    log_entry = json.loads(line)  
                   
                    if ('rule' in log_entry and
                        'level' in log_entry['rule'] and
                        'full_log' in log_entry and
                        log_entry['rule']['level'] >= 15):
                       
                        full_log = log_entry['full_log']
                       
                        response = send_to_gemini_api(full_log)
                        if response and "candidates" in response and len(response["candidates"]) > 0:
                            if "content" in response["candidates"][0]:
                                # You can handle the response here as needed for export
                                content_text = response["candidates"][0]["content"]["parts"][0]["text"]
                                # Add logic to export content_text as needed
                           
                        time.sleep(rate_limit)  
                except json.JSONDecodeError:
                    continue

    log_file = r'/var/log/syslog'  
    rate_limit = 1  
    read_and_process_logs(log_file, rate_limit)

rules : 


<group name="gemini,">

    <rule id="92213" level="0">
        <decoded_as>json</decoded_as>
        <field name="integration">gemini</field>
        <description>gemini integration messages.</description>
        <options>no_full_log</options>
    </rule>

    <rule id="92213" level="3">
        <if_sid>92213</if_sid>
        <field name="gemini.error">904</field>
        <description>gemini: Error: Public API request rate limit reached</description>
        <options>no_full_log</options>
    </rule>

    <rule id="92213" level="7">
        <if_sid>92213</if_sid>
        <field name="gimini.result">906</field>
        <description>gemini: result - $(content_text)</description>
        <options>no_full_log</options>
    </rule>

</group>

Federico Gustavo Galland

unread,
Sep 25, 2024, 7:49:29 AM9/25/24
to Wazuh | Mailing List
Hi there,

The integrator module will pass the trigger alert contents, the API key and hook url as arguments to your integration script. Your code doesn't seem to handle this, so it's not going to be able to read your alerts.
Also, in order for an alert to be triggered based off the API's response, you need to feed the output back into wazuh (usually by means of the wazuh socket under /var/ossec/queue/sockets/queue).

If you are working on integrating Wazuh with external APIs, the following link is a must read:

You can check out one of our official integrations in order to get a grasp on how to talk to the Wazuh socket:

Also, you can base your new script off our existing chatgpt integration:

Let me know if this was helpful.

Regards,
Fede

SaadEddine ELOTMANI

unread,
Sep 25, 2024, 10:32:18 AM9/25/24
to Wazuh | Mailing List
#!/var/ossec/framework/python/bin/python3
# Copyright (C) 2015-2023, Wazuh Inc.
# Gemini Integration

import json
import sys
import time
import os
from socket import socket, AF_UNIX, SOCK_DGRAM

try:
    import requests
except Exception as e:
    print("No module 'requests' found. Install: pip install requests")
    sys.exit(1)

# Global vars
debug_enabled = False
pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

json_alert = {}
now = time.strftime("%a %b %d %H:%M:%S %Z %Y")
# Set paths
log_file = '{0}/var/log/syslog'.format(pwd)
socket_addr = '{0}/queue/sockets/queue'.format(pwd)

def main(args):
    debug("# Starting")
    # Read args
    alert_file_location = args[1]
    apikey = args[2]
    hook_url = args[3]

    debug("# API Key")
    debug(apikey)
    debug("# File location")
    debug(alert_file_location)

    # Load alert. Parse JSON object.
    with open(alert_file_location) as alert_file:
        json_alert = json.load(alert_file)
    debug("# Processing alert")
    debug(json_alert)

    # Check for rule level 15
    if json_alert["rule"]["level"] == 15:
        debug("# Rule level 15 detected")
        # Send log to Gemini
        msg = request_gemini_info(json_alert, apikey, hook_url)
        # If positive match, send event to Wazuh Manager
        if msg:
            send_event(msg, json_alert["agent"])

def debug(msg):
    if debug_enabled:
        msg = "{0}: {1}\n".format(now, msg)
    print(msg)
    with open(log_file, "a") as f:
        f.write(str(msg))

def request_gemini_info(alert, apikey, hook_url):
    alert_output = {}
   
    # Gemini API request
    headers = {
        'Authorization': 'Bearer ' + apikey,
        'Content-Type': 'application/json',
    }

    json_data = {
        'full_log': alert['full_log'],
        'rule': {
            'id': alert['rule']['id'],
            'description': alert['rule']['description'],
            'level': alert['rule']['level']
        },
        'agent': alert['agent']
    }

    response = requests.post(hook_url, headers=headers, json=json_data)

    if response.status_code == 200:
        alert_output = response.json()
        debug("# Gemini API response received")
    else:
        alert_output["gemini"] = {}
        alert_output["integration"] = "custom-gemini"
        alert_output["gemini"]["error"] = response.status_code
        debug("# Error: The Gemini API encountered an error")
   
    return alert_output

def send_event(msg, agent=None):
    if not agent or agent["id"] == "000":
        string = '1:gemini:{0}'.format(json.dumps(msg))
    else:
        string = '1:[{0}] ({1}) {2}->gemini:{3}'.format(agent["id"], agent["name"], agent.get("ip", "any"), json.dumps(msg))

    debug(string)
    sock = socket(AF_UNIX, SOCK_DGRAM)
    sock.connect(socket_addr)
    sock.send(string.encode())
    sock.close()

if __name__ == "__main__":
    try:
        # Read arguments
        bad_arguments = False
        if len(sys.argv) >= 4:
            msg = '{0} {1} {2} {3}'.format(now, sys.argv[1], sys.argv[2], sys.argv[3])
            debug_enabled = (len(sys.argv) > 4 and sys.argv[4] == 'debug')
        else:
            msg = '{0} Wrong arguments'.format(now)
            bad_arguments = True

        # Logging the call
        with open(log_file, 'a') as f:
            f.write(str(msg) + '\n')

        if bad_arguments:
            debug("# Exiting: Bad arguments.")
            sys.exit(1)

        # Main function
        main(sys.argv)

    except Exception as e:
        debug(str(e))
        raise

SaadEddine ELOTMANI

unread,
Sep 25, 2024, 10:36:10 AM9/25/24
to Wazuh | Mailing List
in wazuh log :  000 wazuh-integratord ERROR Invalid integration: 'gemini.py'. Not currently supported.

Federico Gustavo Galland

unread,
Sep 26, 2024, 7:07:44 AM9/26/24
to Wazuh | Mailing List
Hi,

Custom integration scripts should use the prefix `custom-` in the name. In your case: `custom-gemini.py`.

Other than that, it would be nice if you tried to execute the script on the command line and verify that it works before setting it up with Wazuh.

Regards,
Fede
Reply all
Reply to author
Forward
0 new messages