Skip to content

Commit 4815249

Browse files
committed
update Defender checks
1 parent ae6b659 commit 4815249

1 file changed

Lines changed: 68 additions & 36 deletions

File tree

nxc/modules/wcc.py

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,12 @@ def init_checks(self):
197197
ConfigCheck('Powershell Execution Policy == "Restricted"', 'Checks if the Powershell execution policy is set to "Restricted"', checker_args=[[self, ("HKLM\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.Powershell", "ExecutionPolicy", "Restricted\x00"), ("HKCU\\SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds\\Microsoft.Powershell", "ExecutionPolicy", "Restricted\x00")]], checker_kwargs=[{"options": {"KOIfMissing": False, "lastWins": True}}]),
198198
ConfigCheck("Defender service running", "Checks if defender service is enabled", checkers=[self.check_defender_service]),
199199
ConfigCheck("Defender Tamper Protection enabled", "Check if Defender Tamper Protection is enabled", checker_args=[[self, ("HKLM\\Software\\Microsoft\\Windows Defender\\Features", "TamperProtection", 5)]]),
200-
ConfigCheck("Defender RealTime Monitoring enabled", "Check if Defender RealTime Monitoring is enabled", checker_args=[[self, ("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableRealtimeMonitoring", 0), ("HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableRealtimeMonitoring", 0)]], checker_kwargs=[{"options": {"KOIfMissing": False, "lastWins": True}}]),
201-
ConfigCheck("Defender IOAV Protection enabled", "Check if Defender IOAV Protection is enabled", checker_args=[[self, ("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableIOAVProtection", 0), ("HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableIOAVProtection", 0)]], checker_kwargs=[{"options": {"KOIfMissing": False, "lastWins": True}}]),
202-
ConfigCheck("Defender Behaviour Monitoring enabled", "Check if Defender Behaviour Monitoring is enabled", checker_args=[[self, ("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableBehaviourMonitoring", 0), ("HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableBehaviourMonitoring", 0)]], checker_kwargs=[{"options": {"KOIfMissing": False, "lastWins": True}}]),
203-
ConfigCheck("Defender Script Scanning enabled", "Check if Defender Script Scanning is enabled", checker_args=[[self, ("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableScriptScanning", 0), ("HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableScriptScanning", 0)]], checker_kwargs=[{"options": {"KOIfMissing": False, "lastWins": True}}]),
204-
ConfigCheck("Defender path exlusion path", "Checks Defender path exlusion", checkers=[self.check_defender_exclusion_path]),
205-
ConfigCheck("Defender extension exlusion", "Checks Defender extension exlusion", checkers=[self.check_defender_exclusion_extension])
206-
200+
ConfigCheck("Defender RealTime Monitoring enabled", "Check if Defender RealTime Monitoring is enabled", checkers=[self.check_single_registry_with_policy], checker_args=[("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableRealtimeMonitoring", 0, True)]),
201+
ConfigCheck("Defender IOAV Protection enabled", "Check if Defender IOAV Protection is enabled", checkers=[self.check_single_registry_with_policy], checker_args=[("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableIOAVProtection", 0, True)]),
202+
ConfigCheck("Defender Behaviour Monitoring enabled", "Check if Defender Behaviour Monitoring is enabled", checkers=[self.check_single_registry_with_policy], checker_args=[("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableBehaviourMonitoring", 0, True)]),
203+
ConfigCheck("Defender Script Scanning enabled", "Check if Defender Script Scanning is enabled", checkers=[self.check_single_registry_with_policy], checker_args=[("HKLM\\Software\\Microsoft\\Windows Defender\\Real-Time Protection", "HKLM\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection", "DisableScriptScanning", 0, True)]),
204+
ConfigCheck("Defender path exlusion path", "Checks Defender path exlusion", checkers=[self.check_defender_exclusion], checker_args=[("HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Paths", "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Paths")]),
205+
ConfigCheck("Defender extension exlusion", "Checks Defender extension exlusion", checkers=[self.check_defender_exclusion], checker_args=[("HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Extensions", "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Extensions")])
207206
]
208207

209208
# Add check to conf_checks table if missing
@@ -256,7 +255,7 @@ def check_config(self):
256255
if host_id is not None:
257256
self.connection.db.add_check_result(host_id, check.check_id, check.ok, ", ".join(check.reasons).replace("\x00", ""))
258257

259-
def check_registry(self, *specs, options=None):
258+
def check_registry(self, *specs, options=None, stop_on_error=False):
260259
"""
261260
Perform checks that only require to compare values in the registry with expected values, according to the specs
262261
a spec may be either a 3-tuple: (key name, value name, expected value), or a 4-tuple (key name, value name, expected value, operation), where operation is a function that implements a comparison operator
@@ -274,6 +273,7 @@ def check_registry(self, *specs, options=None):
274273
try:
275274
if len(spec) == 3:
276275
(key, value_name, expected_value) = spec
276+
op = operator.eq
277277
elif len(spec) == 4:
278278
(key, value_name, expected_value, op) = spec
279279
else:
@@ -321,6 +321,9 @@ def check_registry(self, *specs, options=None):
321321
else:
322322
ok = False
323323
reasons.append(f"Error while retrieving value of {key}\\{value_name}: {value}")
324+
if stop_on_error:
325+
ok = None
326+
return ok, reasons
324327
continue
325328

326329
if op(value, expected_value):
@@ -337,6 +340,37 @@ def check_registry(self, *specs, options=None):
337340

338341
return ok, reasons
339342

343+
344+
def check_single_registry_with_policy(self, *spec, options=None):
345+
"""
346+
Perform checks that only require to compare values in the registry with expected values, according to the spec
347+
The spec may be either a 5-tuple: (key name, policy key name, value name, expected value, default result), or a 6-tuple (key name, policy key name, value name, expected value, default result, operation), where operation is a function that implements a comparison operator
348+
"""
349+
try:
350+
if len(spec) == 5:
351+
(key, policy_key, value_name, expected_value, default_result) = spec
352+
op = operator.eq
353+
elif len(spec) == 6:
354+
(key, policy_key, value_name, expected_value, default_result, op) = spec
355+
else:
356+
ok = False
357+
reasons = ["Check could not be performed (invalid specification provided)"]
358+
return ok, reasons
359+
except Exception as e:
360+
ok, reasons = self.module.log.error(f"Check could not be performed. Details: specs={specs}, dce={self.dce}, error: {e}")
361+
return ok, reasons
362+
363+
ok, reasons_p = self.check_registry((policy_key, value_name, expected_value, op), stop_on_error=True)
364+
reasons = [f"Policy: [{', '.join(reasons_p)}]"]
365+
if ok is not None:
366+
return ok, reasons
367+
ok, reasons_k = self.check_registry((key, value_name, expected_value, op), stop_on_error=True)
368+
reasons.append(f"Specific: [{', '.join(reasons_k)}]")
369+
if ok is not None:
370+
return ok, reasons
371+
372+
return default_result, reasons
373+
340374
def check_laps(self):
341375
reasons = []
342376
success = False
@@ -492,41 +526,39 @@ def check_applocker(self):
492526

493527
return success, reasons
494528

495-
def check_defender_exclusion_path(self):
496-
key_name = "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Paths"
497-
values = self.reg_query_value(self.dce, self.connection, key_name, valueName=None, all=True)
498-
success = True
499-
reasons = []
500-
for value_type, value_name, value_data in values:
501-
reasons.append(value_name)
502-
key_name = "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Paths"
529+
def get_exclusions(self, key_name):
530+
exclusions = []
503531
try:
504532
values = self.reg_query_value(self.dce, self.connection, key_name, valueName=None, all=True)
505533
for value_type, value_name, value_data in values:
506-
reasons.append(value_name)
534+
exclusions.append(value_name)
507535
except Exception:
508-
self.context.log.debug("No defender path exclusion policies")
509-
510-
if len(reasons) > 0:
511-
success = False
536+
self.context.log.debug("No defender exclusion policies")
512537

513-
return success, reasons
538+
return len(exclusions), exclusions
539+
540+
def check_defender_exclusion(self, *spec, options=None):
541+
try:
542+
if len(spec) == 2:
543+
(policy_key_name, key_name) = spec
544+
else:
545+
ok = False
546+
reasons = ["Check could not be performed (invalid specification provided)"]
547+
return ok, reasons
548+
except Exception as e:
549+
ok, reasons = self.module.log.error(f"Check could not be performed. Details: specs={specs}, dce={self.dce}, error: {e}")
550+
return ok, reasons
514551

515-
def check_defender_exclusion_extension(self):
516-
key_name = "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Extensions"
517-
values = self.reg_query_value(self.dce, self.connection, key_name, valueName=None, all=True)
518-
success = True
519552
reasons = []
520-
for value_type, value_name, value_data in values:
521-
reasons.append(value_name)
522-
key_name = "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Exclusions\\Extensions"
523-
try:
524-
values = self.reg_query_value(self.dce, self.connection, key_name, valueName=None, all=True)
525-
for value_type, value_name, value_data in values:
526-
reasons.append(value_name)
527-
except Exception:
528-
self.context.log.debug("No defender extension exclusion policies")
529-
if len(reasons) > 0:
553+
success = True
554+
555+
count, exclusions_p = self.get_exclusions(policy_key_name)
556+
reasons = [f"Policy: [{', '.join(exclusions_p)}]"]
557+
count_k, exclusions_k = self.get_exclusions(key_name)
558+
reasons.append(f"Specific: [{', '.join(exclusions_k)}]")
559+
count += count_k
560+
561+
if count > 0:
530562
success = False
531563

532564
return success, reasons

0 commit comments

Comments
 (0)