Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Wazuh Responder Not Working #844

Closed
camaro23 opened this issue Sep 3, 2020 · 21 comments · Fixed by #845
Closed

[Bug] Wazuh Responder Not Working #844

camaro23 opened this issue Sep 3, 2020 · 21 comments · Fixed by #845
Labels
category:bug Issue is related to a bug
Milestone

Comments

@camaro23
Copy link

camaro23 commented Sep 3, 2020

Hey Team,

I am attempting to implement the Wazuh Responder, but am having some issues and am unable to pinpoint the exact issue. I have configured the correct url and username/password to the wazuh manager API but when attempting to run the responder, it fails.

image

Anyone have any advice or way I could enable more verbose log output?

Thanks!

@camaro23 camaro23 added the category:bug Issue is related to a bug label Sep 3, 2020
@weslambert
Copy link
Contributor

Could you be more specific with regard to the issues you are having? Also, please ensure you have configured TheHive/Cortex as specified in the requirements:
https://github.com/TheHive-Project/CortexDocs/blob/master/analyzer_requirements.md#wazuh

@camaro23
Copy link
Author

camaro23 commented Sep 4, 2020

Hey Wes,

Thanks for getting back to me. I see now that Cortex is responding with "Agent ID is Missing":

image

What is the best way to pass the agent id so that wazuh.py can read it? Looking at the python script I see:

self.wazuh_agent_id = self.get_param('data.case.customFields.wazuh_agent_id.string', None, "Agent ID Missing!")

Is that an Observable I should also bring in? Im a little lost on how the Wazuh Responder knows what agent id to send the active response to.

Thanks!

@weslambert
Copy link
Contributor

From the docs:

The following custom fields should be created and populated in related records:

wazuh_agent_id: The ID of the Wazuh agent that witnessed activity to generate the alert
wazuh_alert_id: The Wazuh alert ID generated by the Wazuh manager
wazuh_rule_id: The rule ID associated with the Wazuh alert

These need to be populated so that the Wazuh manager knows to which agent, alert, and rule this pertains.

@camaro23
Copy link
Author

camaro23 commented Sep 4, 2020

Hey Wes,

Pardon the ignorance but I am still lost as to how I can set these custom fields. Within TheHIVE would this just be the description?

image

@weslambert
Copy link
Contributor

These need to actually be populated in the event/alert/case, so that the responder can pull the value from the field and act upon it.

@weslambert
Copy link
Contributor

Would you mind sharing the source of your Wazuh data so that it may be easier to determine how to format this data/these events accordingly?

@camaro23
Copy link
Author

camaro23 commented Sep 4, 2020

Hey Wes,

Here is the json output of an example alert

{
"_index": "wazuh-alerts-3.x-dev-2020.09.04",
"_type": "_doc",
"_id": "U0ZTV3QBuVQmIbi7MjjX",
"_version": 1,
"_score": null,
"_source": {
"predecoder": {
"hostname": "test513",
"program_name": "sshd",
"timestamp": "Sep 4 04:15:08"
},
"agent": {
"ip": "1.1.1.1",
"name": "test513",
"id": "2078"
},
"suricata_src_ip": "",
"srcip": "1.1.1.1",
"data": {
"srcip": "1.1.1.1",
"dstuser": "graphuser98"
},
"md5_hash": "",
"manager": {
"name": "test01"
},
"http_hostname": "",
"rule": {
"mail": false,
"level": 3,
"pci_dss": [
"10.2.5"
],
"hipaa": [
"164.312.b"
],
"tsc": [
"CC6.8",
"CC7.2",
"CC7.3"
],
"description": "sshd: authentication success.",
"groups": [
"syslog",
"sshd",
"authentication_success"
],
"nist_800_53": [
"AU.14",
"AC.7"
],
"gdpr": [
"IV_32.2"
],
"firedtimes": 1236,
"mitre": {
"technique": [
"Valid Accounts",
"Remote Services"
],
"id": [
"T1078",
"T1021"
],
"tactic": [
"Defense Evasion",
"Initial Access",
"Persistence",
"Privilege Escalation",
"Lateral Movement"
]
},
"id": "5715",
"gpg13": [
"7.1",
"7.2"
]
},
"suricata_dest_ip": "",
"decoder": {
"parent": "sshd",
"name": "sshd"
},
"full_log": "Sep 4 04:15:08 test sshd[12235]: Accepted keyboard-interactive/pam for graphuser98 from 1.1.1.1 port 61592 ssh2",
"sha256_hash": "",
"input": {
"type": "log"
},
"modsec_request": "",
"windows_username": "",
"modsecurity_source_ip": "",
"added_user": "graphuser98",
"location": "/var/log/secure",
"id": "1599192926.177448049",
"timestamp": "2020-09-04T04:15:26.688+0000",
"username": ""
},
"fields": {
"data.vulnerability.published": [],
"data.aws.resource.instanceDetails.launchTime": [],
"data.aws.createdAt": [],
"data.aws.end": [],
"data.aws.service.eventLastSeen": [],
"syscheck.mtime_after": [],
"syscheck.mtime_before": [],
"data.aws.updatedAt": [],
"data.aws.service.eventFirstSeen": [],
"data.timestamp": [],
"data.vulnerability.updated": [],
"data.aws.start": [],
"timestamp": [
"2020-09-04T04:15:26.688Z"
]
},
"sort": [
1599192926688
]
}

Would I just add a pipeline parameter that would set wazuh_agent_id:, wazuh_rule_id:, wazuh_alert_id: and pass that to thehive via elastalert?

Here is an example elastalert config i have to send alerts to thehive:

es_host: 1.1.1.1
es_port: 9200
name: DEV Web Attack
type: frequency
index: wazuh-alerts-3.x-dev-*
num_events: 1
timeframe:
hours: 1
filter:

  • terms:
    rule.id: ["101302", "101300", "101301"]
    realert:
    minutes: 0
    alert: hivealerter
    hive_connection:
    hive_host: https://1.1.1.1
    hive_port: 443
    hive_apikey: 1.1.1.1

hive_alert_config:
type: 'external'
source: 'elastalert'
description: '{rule[name]}'
severity: 2
tags: ['{match[manager][name]}', '{rule[name]}', '{match[agent][name]}', '{match[syscheck][path]}']
tlp: 3
status: 'New'
follow: True

hive_observable_data_mapping:
- hash: "{match[md5_hash]}"
- hash: "{match[sha256_hash]}"

@weslambert
Copy link
Contributor

Yes, they will need to be added to the case, and specified as custom fields in TheHive (so that they can handled/interpreted correctly). This responder takes a little prep work up front, but after the initial setup of things, you should be okay.

@camaro23
Copy link
Author

camaro23 commented Sep 4, 2020

Hey Wes,

I created the new custom fields and added them to a case template:

image

image

image

However, I am still getting the failure on cortex end:

image

I also see the input details in Cortex:

image

Anything I am missing?

Thanks

@weslambert
Copy link
Contributor

I think that is bug with the way the error message is reported -- it's supposed to be telling you about the wazuh_alert_id being null. I suppose after that is fixed, it will tell you about the rule ID, because that is null as well.

@weslambert
Copy link
Contributor

Updated the error message(s) here: #845

@dadokkio
Copy link
Contributor

@camaro23 were you able to test the fix?

@jeromeleonard jeromeleonard linked a pull request Oct 14, 2020 that will close this issue
@jeromeleonard jeromeleonard added the status:waiting-for-reply Waiting for reply from user label Oct 14, 2020
@dadokkio dadokkio added this to the 3.0.0 milestone Jan 8, 2021
@RAIJIN-afk
Copy link

RAIJIN-afk commented May 28, 2021

Hello,

I found the solution to the bug, however, this led to another issue.

First, here is the modified code to fix the bug. I'm new to GitHub, so @weslambert or anyone concerned, I would humbly ask you to review and fix, thank you.

{ "errorMessage": "Agent ID Missing", "input": "{\"data\":{\"_id\":\"~164040800\",\"id\":\"~164040800\",\"createdBy\":\"REMOVED\",\"updatedBy\":null,\"createdAt\":1622187741922,\"updatedAt\":null,\"_type\":\"case\",\"caseId\":5,\"title\":\"wazuh-alerts-*_SSH Failed Login\",\"description\":\"sshd: Attempt to login using a non-existent user\",\"severity\":2,\"startDate\":1622187741861,\"endDate\":null,\"impactStatus\":null,\"resolutionStatus\":null,\"tags\":[\"alerting\",\"agent_ip:192.168.85.23\",\"sshd\",\"May 28 09:39:43 192 sshd[51270]: Failed password for invalid user akhdjasd from 192.168.85.49 port 60863 ssh2\",\"sourceip: 192.168.85.49\",\"SSH Failed Login\"],\"flag\":false,\"tlp\":3,\"pap\":2,\"status\":\"Open\",\"summary\":null,\"owner\":\"[email protected]\",\"customFields\":{},\"stats\":{},\"permissions\":[]},\"dataType\":\"thehive:case\",\"tlp\":3,\"pap\":2,\"message\":\"\",\"parameters\":{},\"config\":{\"proxy_https\":null,\"cacerts\":null,\"max_pap\":2,\"wazuh_user\":\"foo\",\"jobTimeout\":30,\"check_tlp\":false,\"wazuh_password\":\"REMOVED\",\"proxy_http\":null,\"max_tlp\":2,\"wazuh_manager\":\"https://192.168.85.82\",\"check_pap\":false}}", "success": false }
The code above this my output from the Cortex Alert, informing me that the error received was that the Agent ID was missing. I noticed that Wazuh.py was fetching the data at the wrong places.

Originally, the data (wazuh_agent_id etc) were being fetch from 'data.case.customFields.wazuh_agent_id.string'
Following the schema above, I modified the codes to
'data.customFields.wazuh_agent_id.string'

Here is the complete list of modified codings.

        self.wazuh_manager = self.get_param('config.wazuh_manager', None, 'https://localhost:55000')
       self.wazuh_user = self.get_param('config.wazuh_user', None, 'Username missing!')
       self.wazuh_password = self.get_param('config.wazuh_password', None, 'Password missing!')
       self.wazuh_agent_id = self.get_param('data.customFields.wazuh_agent_id.string', None, 'Agent ID Missing')
       self.wazuh_alert_id = self.get_param('data.customFields.wazuh_alert_id.string', None, " Missing!")
       self.wazuh_rule_id = self.get_param('data.customFields.wazuh_rule_id.string', None, "Rule ID Missing!")
       self.observable = self.get_param('data', None, "Data is empty")
       self.observable_type = self.get_param('dataType', None, "Data type is empty")

The last 5 parameters we modified.

Of course, as admin, I then added the 3 missing Custom Fields just like @camaro23 did.
image

The error messages were cleared. However, I am now receiving another error. A blank error. Could anyone follow up on this?
Here is the screenshot of said error:
image

Note: I added random values to the Alert and Rule ID. I haven't tested if that caused the issue.

@nadouani
Copy link
Contributor

Closing per PR #845

@nadouani nadouani removed the status:waiting-for-reply Waiting for reply from user label Jul 27, 2021
@VerityCyber
Copy link

This issue is still present. I am testing this now in a dev environment. The only thing I can think of is perhaps there is some compatibility issues with the latest versions of Wazuh.

@VerityCyber
Copy link

For reference:
"customFields": {
"wazuh_rule_id": {
"string": "60122",
"order": 1
},
"wazuh_agent_id": {
"string": "001",
"order": 0
},
"wazuh_alert_id": {
"string": "1627400930.2083663",
"order": 2
}
},
"stats": {},
"permissions": []
}

Report

{
"errorMessage": "Agent ID Missing!",
"input": "{"data":{................
"success": false
}

@abhijeetasawant
Copy link

Added this comment to help users if they face "Agent ID Missing" error:
If you run responder against "CASE" you will get an error : "Agent ID Missing"
But if you run responder against "Observable - IP" - it will run successfuly.

@SrijanNandi
Copy link

Still does not work...

Even after running it on an observable IP, I still get the same error as Agent ID missing.

image

When I checked in Cortex, I see the following lines:

image

It seems that the fields in wazuh.py is not matching with the custom fields here.

Im wazuh.py it is wazuh_agent_id where as in cortex it is wazuh-agent-id.

The custom fields that I have created are:

image

Still not able to figure out the issue.

@SrijanNandi
Copy link

Finally managed to get it to a point wherein the login is successful. Using the following code:

#!/usr/bin/env python3
from cortexutils.responder import Responder
import requests
import ipaddress
import json
import urllib3
from base64 import b64encode

# Disable insecure https warnings (for self-signed SSL certificates)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class Wazuh(Responder):
   def __init__(self):
       Responder.__init__(self)
       self.wazuh_manager = self.get_param('config.wazuh_manager', None, 'https://localhost:55000')
       self.wazuh_user = self.get_param('config.wazuh_user', None, 'Username missing!')
       self.wazuh_password = self.get_param('config.wazuh_password', None, 'Password missing!')
       self.wazuh_agent_id = self.get_param('data.case.customFields.wazuh-agent-id.string', None, "Agent ID Missing!")
       self.wazuh_alert_id = self.get_param('data.case.customFields.wazuh-alert-id.string', None, "Alert ID Missing!")
       self.wazuh_rule_id = self.get_param('data.case.customFields.wazuh-rule-id.string', None, "Rule ID Missing!")
       self.observable = self.get_param('data.data', None, "Data is empty")
       self.observable_type = self.get_param('data.dataType', None, "Data type is empty")
   
   def run(self):
       Responder.run(self)
       auth = (self.wazuh_user, self.wazuh_password)
       basic_auth = f"{self.wazuh_user}:{self.wazuh_password}".encode()
       headers = {'Content-Type': 'application/json',
                 'Authorization': f'Basic {b64encode(basic_auth).decode()}'}
       
       # Check observable to ensure valid IP address
       if self.observable_type == "ip":
           try:
               ipaddress.ip_address(self.observable)
           except ValueError:
               self.error({'message': "Not a valid IPv4/IPv6 address!"})
       else: 
           self.error({'message': "Not a valid IPv4/IPv6 address!"})
       payload = '{"command":"firewall-drop", "arguments": ["-", "' +  self.observable + '", "' + self.wazuh_alert_id + '", "' + self.wazuh_rule_id + '", "' + self.wazuh_agent_id + '", "var/log/test.log"], "custom": "True"}'
      
       response = requests.get(self.wazuh_manager + '/security/user/authenticate', headers=headers, verify=False)
       token = json.loads(response.content.decode())['data']['token']
       # New authorization header with the JWT token we got
       requests_headers = {'Content-Type': 'application/json',
                          'Authorization': f'Bearer {token}'}

       response = requests.get(f"{self.wazuh_manager}/?pretty=true", headers=requests_headers, verify=False)
       #response = requests.put(f"{self.wazuh_manager}/active-response/self.wazuh_agent_id", headers=requests_headers, data=payload, verify=False)
       print(response.text)
       print(response.status_code)
       
       if response.status_code == 200:
           self.report({'message': "Added DROP rule for " + self.observable  })
       else:
           self.error(response.status_code)
   
   def operations(self, raw):
      return [self.build_operation('AddTagToCase', tag='Wazuh: Blocked IP')] 

if __name__ == '__main__':
  Wazuh().run()

The line that is not working is:
response = requests.put(f"{self.wazuh_manager}/active-response/self.wazuh_agent_id", headers=requests_headers, data=payload, verify=False)

@SrijanNandi
Copy link

Managed to get it working with the following code:

#!/usr/bin/env python3
from cortexutils.responder import Responder
import requests
import ipaddress
import json
import urllib3
from base64 import b64encode

# Disable insecure https warnings (for self-signed SSL certificates)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class Wazuh(Responder):
   def __init__(self):
       Responder.__init__(self)
       self.wazuh_manager = self.get_param('config.wazuh_manager', None, 'https://localhost:55000')
       self.wazuh_user = self.get_param('config.wazuh_user', None, 'Username missing!')
       self.wazuh_password = self.get_param('config.wazuh_password', None, 'Password missing!')
       self.wazuh_agent_id = self.get_param('data.case.customFields.wazuh-agent-id.string', None, "Agent ID Missing!")
       self.wazuh_alert_id = self.get_param('data.case.customFields.wazuh-alert-id.string', None, "Alert ID Missing!")
       self.wazuh_rule_id = self.get_param('data.case.customFields.wazuh-rule-id.string', None, "Rule ID Missing!")
       self.observable = self.get_param('data.data', None, "Data is empty")
       self.observable_type = self.get_param('data.dataType', None, "Data type is empty")
   
   def run(self):
       Responder.run(self)
       auth = (self.wazuh_user, self.wazuh_password)
       basic_auth = f"{self.wazuh_user}:{self.wazuh_password}".encode()
       headers = {'Content-Type': 'application/json',
                 'Authorization': f'Basic {b64encode(basic_auth).decode()}'}
       
       # Check observable to ensure valid IP address
       if self.observable_type == "ip":
           try:
               ipaddress.ip_address(self.observable)
           except ValueError:
               self.error({'message': "Not a valid IPv4/IPv6 address!"})
       else: 
           self.error({'message': "Not a valid IPv4/IPv6 address!"})
       payload = '{"command":"firewall-drop", "arguments": ["-", "' +  self.observable + '", "' + self.wazuh_alert_id + '", "' + self.wazuh_rule_id + '", "' + self.wazuh_agent_id + '", "var/log/test.log"]}'
      
       response = requests.get(self.wazuh_manager + '/security/user/authenticate', headers=headers, verify=False)
       token = json.loads(response.content.decode())['data']['token']
       # New authorization header with the JWT token we got
       requests_headers = {'Content-Type': 'application/json',
                          'Authorization': f'Bearer {token}'}

       response = requests.put(f"{self.wazuh_manager}/active-response?agents_list={self.wazuh_agent_id}", headers=requests_headers, data=payload, verify=False)
       
       if response.status_code == 200:
           self.report({'message': "Added DROP rule for " + self.observable  })
       else:
           self.error(response.status_code)
   
   def operations(self, raw):
      return [self.build_operation('AddTagToCase', tag='Wazuh: Blocked IP')] 

if __name__ == '__main__':
  Wazuh().run()

@timandlily
Copy link

timandlily commented Oct 26, 2022

I got this error with above script

{
"errorMessage": "Traceback (most recent call last): File "/opt/cortex/Cortex-Analyzers/responders/Wazuh/wazuh.py", line 59, in Wazuh().run() File "/opt/cortex/Cortex-Analyzers/responders/Wazuh/wazuh.py", line 43, in run token = json.loads(response.content.decode())['data']['token']KeyError: 'data'",
"input": null,
"success": false
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category:bug Issue is related to a bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants