@cryptotaxi247 / CoPilot / commits / 75faafa3

Wazuh exclusion (#212)

* Refactor wazuh_rule_exclude endpoint to accept RuleExcludeRequest * modify png file * chore: Update branch name in Docker workflow from network-connectors to main * updated wazuhManagerRuleExclude api FE * chore: Update Docker workflow to include wazuh-exclusion branch * chore: Update Docker workflow to use 'main' branch instead of 'wazuh-exclusion' * chore: Update Docker workflow to use 'main' branch instead of 'wazuh-exclusion' * crowdstrike * chore: Update Docker workflow to use 'main' branch instead of 'wazuh-exclusion' * chore: Update customer integrations table for customer {customer_code} * precommit fixes --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>

taylor_socfortress committed May 13, 2024 at 13:07 UTC 75faafa310a8dcb650c89e759e786fcabadb3ec0
7 files changed +113 -101
backend/app/connectors/wazuh_manager/routes/rules.py
+4 -4
@@ -16,12 +16,14 @@ from app.connectors.wazuh_manager.schema.rules import RuleDisable
16 from app.connectors.wazuh_manager.schema.rules import RuleDisableResponse
17 from app.connectors.wazuh_manager.schema.rules import RuleEnable
18 from app.connectors.wazuh_manager.schema.rules import RuleEnableResponse
19 +from app.connectors.wazuh_manager.schema.rules import RuleExcludeRequest
20 from app.connectors.wazuh_manager.schema.rules import RuleExcludeResponse
21
22 # from app.connectors.wazuh_manager.schema.rules import RuleExclude
23 # from app.connectors.wazuh_manager.schema.rules import RuleExcludeResponse
24 from app.connectors.wazuh_manager.services.rules import disable_rule
25 from app.connectors.wazuh_manager.services.rules import enable_rule
26 +from app.connectors.wazuh_manager.services.rules import post_to_copilot_ai_module
27
28 # from app.connectors.wazuh_manager.services.rules import exclude_rule
29 from app.db.db_session import get_db
@@ -155,12 +157,10 @@ async def enable_wazuh_rule(
157 raise HTTPException(status_code=404, detail="Was not able to enable rule")
158
159
158 -# ! TODO: Implement this endpoint - Maybe use OpenAI?
160 @wazuh_manager_rules_router.post(
161 "/rule/exclude",
162 response_model=RuleExcludeResponse,
163 description="Retrieve recommended exclusion for a Wazuh Rule",
164 )
164 -async def exclude_wazuh_rule() -> RuleExcludeResponse:
165 - raise HTTPException(status_code=501, detail="Feature not yet ready")
166 - return RuleExcludeResponse(success=False, message="Feature not yet ready")
165 +async def exclude_wazuh_rule(request: RuleExcludeRequest) -> RuleExcludeResponse:
166 + return await post_to_copilot_ai_module(data=request)
backend/app/connectors/wazuh_manager/schema/rules.py
+85 -6
@@ -1,8 +1,10 @@
1 from typing import List
2 from typing import Optional
3
4 +from fastapi import HTTPException
5 from pydantic import BaseModel
6 from pydantic import Field
7 +from pydantic import validator
8
9
10 class RuleDisable(BaseModel):
@@ -43,12 +45,89 @@ class AllDisabledRuleResponse(BaseModel):
45 message: str
46
47
46 -class RuleExclude(BaseModel):
47 - input_value: str = Field(
48 - ...,
49 - description="The proposed value of the field trying to be exclude that would result in an exclusiong",
50 - example="C:\\Windows\\ServiceState\\EventLog\\Data\\lastalive1.dat",
51 - )
48 +payload = {
49 + "data_win_system_eventRecordID": "521098",
50 + "data_win_eventdata_user": "WIN-HFOU106TD7K\\Administrator",
51 + "agent_id": "111",
52 + "agent_name": "WIN-HFO106TD7K",
53 + "gl2_remote_ip": "10.255.255.13",
54 + "data_win_system_eventID": "22",
55 + "agent_labels_customer": "00002",
56 + "source": "10.255.255.13",
57 + "gl2_source_input": "660320f176ca320e8393f030",
58 + "rule_level": 3,
59 + "data_win_system_task": "22",
60 + "timestamp_utc": "2024-04-17T15:06:54.742Z",
61 + "syslog_type": "wazuh",
62 + "data_win_system_threadID": "2888",
63 + "rule_description": "Sysmon - Event 22: DNS Request by C:\\Windows\\system32\\PING.EXE",
64 + "gl2_source_node": "3b68efa4-3319-4885-a38f-c944f0fcf191",
65 + "id": "1713366415.56188571",
66 + "rule_mitre_tactic": "Command and Control",
67 + "process_image": "C:\\Windows\\system32\\PING.EXE",
68 + "data_win_eventdata_utcTime": "2024-04-17 15:06:28.457",
69 + "streams": ["661555f676ca320e837b14cc", "660320f176ca320e8393f057"],
70 + "rule_mitre_id": "T1071",
71 + "gl2_message_id": "01HVP9HG8YE31EQH1878V50H89",
72 + "data_win_system_computer": "WIN-HFOU106TD7K",
73 + "agent_ip": "192.168.200.3",
74 + "data_win_eventdata_image": "C:\\Windows\\system32\\PING.EXE",
75 + "threat_intel_value": "evil.socfortress.co",
76 + "data_win_eventdata_queryName": "evil.socfortress.co",
77 + "rule_groups": "windows, sysmon, sysmon_event_22",
78 + "data_win_system_keywords": "0x8000000000000000",
79 + "data_win_system_level": "4",
80 + "process_id": "6072",
81 + "data_win_eventdata_queryStatus": "0",
82 + "data_win_system_severityValue": "INFORMATION",
83 + "dns_response_code": "0",
84 + "dns_query": "evil.socfortress.co",
85 + "data_win_eventdata_processGuid": "{691ff406-e58c-661f-b401-000000002300}",
86 + "rule_mitre_technique": "Application Layer Protocol",
87 + "rule_firedtimes": 2,
88 + "data_win_system_systemTime": "2024-04-17T15:06:54.742696000Z",
89 + "decoder_name": "windows_eventchannel",
90 + "data_win_system_processID": "2180",
91 + "data_win_system_channel": "Microsoft-Windows-Sysmon/Operational",
92 + "syslog_level": "ALERT",
93 + "threat_intel_comment": "This is a test IoC",
94 + "data_win_system_providerName": "Microsoft-Windows-Sysmon",
95 + "data_win_eventdata_processId": "6072",
96 + "data_win_system_version": "5",
97 + "data_win_system_providerGuid": "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
98 + "timestamp": "2024-04-17 15:06:57.694",
99 + "threat_intel_ioc_source": "test",
100 + "rule_group1": "windows",
101 + "data_win_system_opcode": "0",
102 +}
103 +
104 +
105 +class RuleExcludeRequest(BaseModel):
106 + integration: str = Field(..., example="wazuh-rule-exclusion")
107 + prompt: dict = Field(..., example=payload)
108 +
109 + @validator("integration")
110 + def check_integration(cls, v):
111 + if v != "wazuh-rule-exclusion":
112 + raise HTTPException(
113 + status_code=400,
114 + detail="Invalid integration. Only 'wazuh-rule-exclusion' is supported.",
115 + )
116 + return v
117 +
118 + @validator("prompt")
119 + def check_rule_group1(cls, v):
120 + if "rule_group1" not in v:
121 + raise HTTPException(
122 + status_code=400,
123 + detail="Missing 'rule_group1' in prompt.",
124 + )
125 + if v["rule_group1"] != "windows":
126 + raise HTTPException(
127 + status_code=400,
128 + detail="Invalid 'rule_group1'. Only 'windows' is supported.",
129 + )
130 + return v
131
132
133 class RuleExcludeResponse(BaseModel):
backend/app/connectors/wazuh_manager/services/rules.py
+15 -88
@@ -1,11 +1,11 @@
1 -import re
2 -from enum import Enum
1 from typing import Any
2 from typing import Dict
3 from typing import List
4 from typing import Tuple
5 from typing import Union
6
7 +import httpx
8 +
9 # import pcre2
10 import xmltodict
11 from fastapi import HTTPException
@@ -15,7 +15,7 @@ from app.connectors.wazuh_manager.schema.rules import RuleDisable
15 from app.connectors.wazuh_manager.schema.rules import RuleDisableResponse
16 from app.connectors.wazuh_manager.schema.rules import RuleEnable
17 from app.connectors.wazuh_manager.schema.rules import RuleEnableResponse
18 -from app.connectors.wazuh_manager.schema.rules import RuleExclude
18 +from app.connectors.wazuh_manager.schema.rules import RuleExcludeRequest
19 from app.connectors.wazuh_manager.schema.rules import RuleExcludeResponse
20 from app.connectors.wazuh_manager.utils.universal import restart_service
21 from app.connectors.wazuh_manager.utils.universal import send_get_request
@@ -243,92 +243,19 @@ async def enable_rule(rule: RuleEnable, previous_level: str) -> RuleEnableRespon
243
244
245 ################# ! EXCLUDE RULE ! #################
246 -
247 -
248 -def make_pcre2_compatible(input_string: str) -> str:
246 +async def post_to_copilot_ai_module(data: RuleExcludeRequest) -> RuleExcludeResponse:
247 """
250 - Convert the input string to a PCRE2 compatible regex pattern.
251 -
252 - Parameters:
253 - - input_string (str): The input string to convert.
254 -
255 - Returns:
256 - - str: The PCRE2 compatible regex pattern.
257 - """
258 - # PCRE2 uses \\ to escape a backslash
259 - return input_string.replace("\\", "\\\\")
260 -
261 -
262 -class RegexSpecialCharacters(Enum):
263 - DOT = (".", "\.")
264 - CARET = ("^", "\^")
265 - DOLLAR = ("$", "\$")
266 - STAR = ("*", "\*")
267 - PLUS = ("+", "\+")
268 - QUESTION = ("?", "\?")
269 - CURLY_OPEN = ("{", "\{")
270 - CURLY_CLOSE = ("}", "\}")
271 - SQUARE_OPEN = ("[", "\[")
272 - SQUARE_CLOSE = ("]", "\]")
273 - SINGLE_BACKSLASH = ("\\", "\\\\")
274 - DOUBLE_BACKSLASH = ("\\\\", "\\\\\\\\")
275 - PIPE = ("|", "\|")
276 - PAREN_OPEN = ("(", "\(")
277 - PAREN_CLOSE = (")", "\)")
278 - COLON = (":", "\:")
279 - DASH = ("-", "\-")
280 -
281 -
282 -# Create a dictionary for easy lookup
283 -REGEX_REPLACE_DICT = {char.value[0]: char.value[1] for char in RegexSpecialCharacters}
284 -
285 -
286 -async def replace_special_chars(rule: RuleExclude):
287 - for char, replacement in REGEX_REPLACE_DICT.items():
288 - # Use Python's raw string notation for regular expressions
289 - pattern = re.compile(re.escape(char))
290 - input_string = pattern.sub(replacement, rule.input_value)
291 - logger.info(f"Input String: {input_string}")
292 - return input_string
293 -
294 -
295 -async def exclude_rule(rule: RuleExclude) -> RuleExcludeResponse:
296 - """
297 - Exclude a rule based on the provided input value and rule value.
248 + Send a POST request to the copilot-ai-module Docker container.
249
250 Args:
300 - rule (RuleExclude): The rule to be excluded, containing the input value and rule value.
301 -
302 - Returns:
303 - RuleExcludeResponse: The response indicating the success or failure of excluding the rule, along with a recommended exclusion.
304 -
305 - Raises:
306 - Exception: If an error occurs while excluding the rule.
251 + data (CollectHuntress): The data to send to the copilot-ai-module Docker container.
252 """
308 - # Function to replace special characters
309 - # repr of the input string
310 - input_string = repr(rule.input_value)
311 - logger.info(f"Input String: {input_string}")
312 - excluded_string = await replace_special_chars(rule)
313 - logger.info(f"Excluded String: {excluded_string}")
314 - return None
315 - # try:
316 - # # Convert rule_value to a PCRE2 compatible regex pattern
317 - # pcre2_pattern = make_pcre2_compatible(rule.rule_value)
318 -
319 - # compiled_pattern = pcre2.compile(pcre2_pattern)
320 - # print(f"Compiled Pattern: {compiled_pattern}") # Debugging line
321 -
322 - # print(f"Input Value: {rule.input_value}") # Debugging line
323 -
324 - # match_data = compiled_pattern.match(rule.input_value)
325 -
326 - # if match_data:
327 - # return RuleExcludeResponse(success=True, message="Successfully excluded rule", recommended_exclusion=rule.input_value)
328 - # else:
329 - # return RuleExcludeResponse(success=False, message="Failed to exclude rule", recommended_exclusion="")
330 -
331 - # except Exception as e:
332 - # print(f"Exception: {e}") # Debugging line
333 - # logger.error(f"Failed to exclude rule: {e}")
334 - # return RuleExcludeResponse(success=False, message=f"Failed to exclude rule: {e}", recommended_exclusion="")
253 + logger.info(f"Sending POST request to http://copilot-ai-module/wazuh-rule-exclusion with data: {data.dict()}")
254 + raise HTTPException(status_code=501, detail="Not Implemented Yet")
255 + async with httpx.AsyncClient() as client:
256 + data = await client.post(
257 + "http://127.0.0.1:5001/wazuh-rule-exclusion",
258 + json=data.dict(),
259 + timeout=120,
260 + )
261 + return RuleExcludeResponse(**data.json())
backend/app/integrations/crowdstrike/routes/provision.py
+2
@@ -17,6 +17,7 @@ from app.integrations.routes import find_customer_integration
17 from app.integrations.routes import get_customer_integrations_by_customer_code
18 from app.integrations.schema import CustomerIntegrations
19 from app.integrations.schema import CustomerIntegrationsResponse
20 +from app.middleware.license import is_feature_enabled
21
22 integration_crowdstrike_router = APIRouter()
23
@@ -98,6 +99,7 @@ async def provision_crowdstrike_route(
99 Returns:
100 ProvisionCrowdstrikeResponse: The response object containing the result of the provisioning.
101 """
102 + await is_feature_enabled(feature_name="CROWDSTRIKE", session=session)
103 customer_integration_response = await get_customer_integration_response(
104 provision_crowdstrike_request.customer_code,
105 session,
backend/app/integrations/crowdstrike/services/provision.py
+2 -1
@@ -37,7 +37,7 @@ from app.customers.routes.customers import get_customer_meta
37 from app.integrations.crowdstrike.schema.provision import CrowdstrikeCustomerDetails
38 from app.integrations.crowdstrike.schema.provision import ProvisionCrowdstrikeAuthKeys
39 from app.integrations.crowdstrike.schema.provision import ProvisionCrowdstrikeResponse
40 -from app.integrations.schema import CustomerIntegrations
40 +from app.integrations.models.customer_integration_settings import CustomerIntegrations
41 from app.network_connectors.models.network_connectors import (
42 CustomerNetworkConnectorsMeta,
43 )
@@ -535,6 +535,7 @@ async def update_customer_integration_table(
535 customer_code (str): The customer code.
536 session (AsyncSession): The async session object for making HTTP requests.
537 """
538 + logger.info(f"Updating customer integrations table for customer {customer_code}")
539 await session.execute(
540 update(CustomerIntegrations)
541 .where(
backend/app/integrations/markdown/crowdstrike.md
+1 -1
@@ -104,4 +104,4 @@ docker compose -f /opt/CoPilot/data/data/CUSTOMER_NAME/CUSTOMER_NAME_docker-comp
104 ```
105
106 You should now see the container running:
107 -![Crowdstrike Running Container](/images/crowdstrike/docker_ps.png)
107 +![Crowdstrike Running Container](/images/crowdstrike/docker_ps.PNG)
frontend/src/api/alerts.ts
+4 -1
@@ -102,6 +102,9 @@ export default {
102 )
103 },
104 wazuhManagerRuleExclude(source: AlertSourceContent) {
105 - return HttpClient.post<FlaskBaseResponse & WazuhRuleExclude>(`/wazuh_manager/rule/exclude`, source)
105 + return HttpClient.post<FlaskBaseResponse & WazuhRuleExclude>(`/wazuh_manager/rule/exclude`, {
106 + integration: "wazuh-rule-exclusion",
107 + prompt: source
108 + })
109 }
110 }