Files
blue-team-tools/documentation/tools/sigma-logsource-checker.py
T
Frank Breedijk 1a223650fc Merge PR #4667 from @MrSeccubus - Fix error in extension check in sigma-logsource-checker.py
chore: add additional checks to the `sigma-logsource-checker.py` so that it only cares about yaml files
---------

Co-authored-by: nasbench <8741929+nasbench@users.noreply.github.com>
2024-01-10 17:14:31 +01:00

512 lines
30 KiB
Python

# Author: Nasreddine Bencherchali (@nas_bench) / Nextron Systems
__version__ = "0.1.0"
from time import sleep
import yaml
import os
import argparse
from colorama import init
from colorama import Fore
import collections
import xml.etree.ElementTree as ET
from collections import defaultdict
SECURITY_EVENT_ID_MAPPING = {
# Account Logon
"{0CCE923F-69AE-11D9-BED3-505054503030}": {"EventIDs": [4774, 4775, 4776, 4777], "Name": "Audit Credential Validation"},
"{0CCE9242-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4768, 4771, 4772], "Name": "Audit Kerberos Authentication Service"},
"{0CCE9240-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4769, 4770, 4773], "Name": "Audit Kerberos Service Ticket Operations"},
"{0CCE9241-69AE-11D9-BED3-505054503030}" : { "EventIDs": [], "Name": "Audit Other Account Logon Events"},
# Account Management
"{0CCE9239-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792], "Name": "Audit Application Group Management"},
"{0CCE9236-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4741, 4742, 4743], "Name": "Audit Computer Account Management"},
"{0CCE9238-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4749, 4750, 4751, 4752, 4753], "Name": "Audit Distribution Group Management"},
"{0CCE923A-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4782, 4793], "Name": "Audit Other Account Management Events"},
"{0CCE9237-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4731, 4732, 4733, 4734, 4735, 4764, 4799, 4727, 4737, 4728, 4729, 4730, 4754, 4755, 4756, 4757, 4758], "Name": "Audit Security Group Management"},
"{0CCE9235-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4720, 4722, 4723, 4724, 4725, 4726, 4738, 4740, 4765, 4766, 4767, 4780, 4781, 4794, 4798, 5376, 5377], "Name": "Audit User Account Management"},
# Detailed Tracking
"{0CCE922D-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4692, 4693, 4694, 4695], "Name": "Audit DPAPI Activity"},
"{0CCE9248-69AE-11D9-BED3-505054503030}" : { "EventIDs": [6416, 6419, 6420, 6421, 6422, 6423, 6424], "Name": "Audit PNP Activity"},
"{0CCE922B-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4688, 4696], "Name": "Audit Process Creation"},
"{0CCE922C-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4689], "Name": "Audit Process Termination"},
"{0CCE922E-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5712], "Name": "Audit RPC Events"},
"{0CCE924A-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4703], "Name": "Audit Token Right Adjusted"},
# DS Access
"{0CCE923E-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4928, 4929, 4930, 4931, 4934, 4935, 4936, 4937], "Name": "Audit Detailed Directory Service Replication"},
"{0CCE923B-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4661, 4662], "Name": "Audit Directory Service Access"},
"{0CCE923C-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5136, 5137, 5138, 5139, 5141], "Name": "Audit Directory Service Changes"},
"{0CCE923D-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4932, 4933], "Name": "Audit Directory Service Replication"},
# Logon/Logoff
"{0CCE9217-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4625], "Name": "Audit Account Lockout"},
"{0CCE9247-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4626], "Name": "Audit User/Device Claims"},
"{0CCE9249-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4627], "Name": "Audit Group Membership"},
"{0CCE921A-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4978, 4979, 4980, 4981, 4982, 4983, 4984], "Name": "Audit IPsec Extended Mode"},
"{0CCE9218-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4646, 4650, 4651, 4652, 4653, 4655, 4976, 5049, 5453], "Name": "Audit IPsec Main Mode"},
"{0CCE9219-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4977, 5451, 5452], "Name": "Audit IPsec Quick Mode"},
"{0CCE9216-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4634, 4647], "Name": "Audit Logoff"},
"{0CCE9215-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4624, 4625, 4648, 4675], "Name": "Audit Logon"},
"{0CCE9243-69AE-11D9-BED3-505054503030}" : { "EventIDs": [6272, 6273, 6274, 6275, 6276, 6277, 6278, 6279, 6280], "Name": "Audit Network Policy Server"},
"{0CCE921C-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4649, 4778, 4779, 4800, 4801, 4802, 4803, 5378, 5632, 5633], "Name": "Audit Other Logon/Logoff Events"},
"{0CCE921B-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4964, 4672], "Name": "Audit Special Logon"},
# Object Access
"{0CCE9222-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4665, 4666, 4667, 4668], "Name": "Audit Application Generated"},
"{0CCE9221-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898], "Name": "Audit Certification Services"},
"{0CCE9244-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5145], "Name": "Audit Detailed File Share"},
"{0CCE9224-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5140, 5142, 5143, 5144, 5168], "Name": "Audit File Share"},
"{0CCE921D-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4656, 4658, 4660, 4663, 4664, 4670, 4985, 5051], "Name": "Audit File System"},
"{0CCE9226-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5031, 5150, 5151, 5154, 5155, 5156, 5157, 5158, 5159], "Name": "Audit Filtering Platform Connection"},
"{0CCE9225-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5152, 5153], "Name": "Audit Filtering Platform Packet Drop"},
"{0CCE9223-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4658, 4690], "Name": "Audit Handle Manipulation"},
"{0CCE921F-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4656, 4658, 4660, 4663], "Name": "Audit Kernel Object"},
"{0CCE9227-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4671, 4691, 4698, 4699, 4700, 4701, 4702, 5148 ,5149, 5888, 5889, 5890], "Name": "Audit Other Object Access Events"},
"{0CCE921E-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4656, 4657, 4658, 4660, 4663, 4670, 5039], "Name": "Audit Registry"},
"{0CCE9245-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4656, 4658, 4663], "Name": "Audit Removable Storage"},
"{0CCE9220-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4661], "Name": "Audit SAM"},
"{0CCE9246-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4818], "Name": "Audit Central Access Policy Staging"},
# Policy Change
"{0CCE922F-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4715, 4719, 4817, 4902, 4906, 4907, 4908, 4912, 4904, 4905], "Name": "Audit Audit Policy Change"},
"{0CCE9230-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4670, 4706, 4707, 4716, 4713, 4717, 4718, 4739, 4864, 4865, 4866, 4867], "Name": "Audit Authentication Policy Change"},
"{0CCE9231-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4703, 4704, 4705, 4670, 4911, 4913], "Name": "Audit Authorization Policy Change"},
"{0CCE9233-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4709, 4710, 4711, 4712, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5440, 5441, 5442, 5443, 5444, 5446, 5448, 5449, 5450, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5471, 5472, 5473, 5474, 5477], "Name": "Audit Filtering Platform Policy Change"},
"{0CCE9232-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4956, 4957, 4958], "Name": "Audit MPSSVC Rule-Level Policy Change"},
"{0CCE9234-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4714, 4819, 4826, 4909, 4910, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5447, 6144, 6145], "Name": "Audit Other Policy Change Events"},
# Privilege Use
"{0CCE9229-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4673, 4674, 4985], "Name": "Audit Non Sensitive Privilege Use"},
"{0CCE922A-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4985], "Name": "Audit Other Privilege Use Events"},
"{0CCE9228-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4673, 4674, 4985], "Name": "Audit Sensitive Privilege Use"},
# System
"{0CCE9213-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4960, 4961, 4962, 4963, 4965, 5478, 5479, 5480, 5483, 5484, 5485], "Name": "Audit IPsec Driver"},
"{0CCE9214-69AE-11D9-BED3-505054503030}" : { "EventIDs": [5024, 5025, 5027, 5028, 5029, 5030, 5032, 5033, 5034, 5035, 5037, 5058, 5059, 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409], "Name": "Audit Other System Events"},
"{0CCE9210-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4608, 4616, 4621], "Name": "Audit Security State Change"},
"{0CCE9211-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4610, 4611, 4614, 4622, 4697], "Name": "Audit Security System Extension"},
"{0CCE9212-69AE-11D9-BED3-505054503030}" : { "EventIDs": [4612, 4615, 4618, 4816, 5038, 5056, 5062, 5057, 5060, 5061, 6281, 6410], "Name": "Audit System Integrity"}
}
OTHER_EVENT_ID_MAPPING = {
'PowerShell Core': [
{'Turn on Module Logging': 'Disabled'},
{'Turn on PowerShell Script Block Logging': 'Disabled'},
{'Turn on PowerShell Transcription': 'Disabled'}
],
'System/Audit Process Creation': [
{'Include command line in process creation events': 'Disabled'}
],
'Windows Components/Windows PowerShell': [
{'Turn on Module Logging': 'Disabled'},
{'Turn on PowerShell Script Block Logging': 'Disabled'},
{'Turn on PowerShell Transcription': 'Disabled'}]
}
WINDOWS_SYSMON_PROCESS_CREATION_FIELDS = ["RuleName", "UtcTime", "ProcessGuid", "ProcessId", "Image", "FileVersion", "Description", "Product", "Company", "OriginalFileName", "CommandLine", "CurrentDirectory", "User", "LogonGuid", "LogonId", "TerminalSessionId", "IntegrityLevel", "Hashes", "ParentProcessGuid", "ParentProcessId", "ParentImage", "ParentCommandLine", "ParentUser"]
# A reduced set of unique fields that only available to Sysmon/1 - Used for testing
WINDOWS_SYSMON_SPECIAL_PROCESS_CREATION_FIELDS = ["RuleName", "UtcTime", "ProcessGuid", "FileVersion", "Description", "Product", "Company", "OriginalFileName", "CurrentDirectory", "User", "LogonGuid", "LogonId", "TerminalSessionId", "IntegrityLevel", "Hashes", "ParentProcessGuid", "ParentProcessId", "ParentCommandLine", "ParentUser"]
WINDOWS_SECURITY_PROCESS_CREATION_FIELDS = ["SubjectUserSid", "SubjectUserName", "SubjectDomainName", "SubjectLogonId", "NewProcessId", "NewProcessName", "TokenElevationType", "ProcessId", "CommandLine", "TargetUserSid", "TargetUserName", "TargetDomainName", "TargetLogonId", "ParentProcessName", "MandatoryLabel"]
# A reduced set of unique fields that only available to Security/4688 - Used for testing
WINDOWS_SECURITY_SPECIAL_PROCESS_CREATION_FIELDS = ["SubjectUserSid", "SubjectUserName", "SubjectDomainName", "SubjectLogonId", "NewProcessId", "NewProcessName", "TokenElevationType", "ProcessId", "TargetUserSid", "TargetUserName", "TargetDomainName", "TargetLogonId", "ParentProcessName", "MandatoryLabel"]
def yield_next_rule_file_path(path_to_rules: str) -> str:
for root, _, files in os.walk(path_to_rules):
for file in files:
if file.endswith(".yml"):
yield os.path.join(root, file)
def get_rule_part(file_path: str, part_name: str):
yaml_dicts = get_rule_yaml(file_path)
for yaml_part in yaml_dicts:
if part_name in yaml_part.keys():
return yaml_part[part_name]
return None
def get_rule_yaml(file_path: str) -> dict:
data = []
with open(file_path, encoding='utf-8') as f:
yaml_parts = yaml.safe_load_all(f)
for part in yaml_parts:
data.append(part)
return data
def extract_events_ids(detection):
eids_list = []
for key, value in detection.items():
if type(value) == dict:
for key_, value_ in value.items():
if key_ == "EventID":
if type(value_) == int:
eids_list.append(value_)
elif type(value_) == list:
for i in value_:
eids_list.append(i)
else:
pass
return eids_list
def test_invalid_logsource_attributes(path_to_rules):
"""
Returns list of rules that leverage unknown logsource
"""
faulty_rules = []
valid_logsource = [
'category',
'product',
'service',
'definition',
]
for file in yield_next_rule_file_path(path_to_rules):
logsource = get_rule_part(file_path=file, part_name="logsource")
if not logsource:
print("Rule {} has no 'logsource'.".format(file))
faulty_rules.append(file)
continue
valid = True
for key in logsource:
if key.lower() not in valid_logsource:
print("Rule {} has a logsource with an invalid field ({})".format(file, key))
valid = False
elif not isinstance(logsource[key], str):
print("Rule {} has a logsource with an invalid field type ({})".format(file, key))
valid = False
if not valid:
faulty_rules.append(file)
return faulty_rules
def extract_fields(detection):
list_of_fields = []
for key, value in detection.items():
if type(value) == list:
for element in value:
if type(element) == dict:
for key_, value_ in element.items():
field = key_.split("|")[0]
if field not in list_of_fields:
list_of_fields.append(field)
if type(value) == dict:
for key_, value_ in value.items():
field = key_.split("|")[0]
if field not in list_of_fields:
list_of_fields.append(field)
return list_of_fields
def get_logsource_dict(path_to_rules, broken_rules):
"""
Return a list of dicts of all unique log sources
"""
logsource_dict_list_tmp = []
# Add as many specific service log sources we have defined
windows_service_security_dict = defaultdict(list)
windows_service_powershell_dict = defaultdict(list)
windows_category_process_creation_dict = defaultdict(list)
windows_category_ps_module_dict = defaultdict(list)
windows_category_ps_script_dict = defaultdict(list)
for file_ in yield_next_rule_file_path(path_to_rules):
if file_ not in broken_rules:
logsource = get_rule_part(file_path=file_, part_name="logsource")
detection = get_rule_part(file_path=file_, part_name="detection")
logsource.pop("definition", None)
if (("product" in logsource.keys()) and (len(logsource) == 1)):
# We skip rules that do not specify exact services for V0.1 // Mainly the generic MIMIKATZ rule
continue
else:
if "product" in logsource:
# For V0.1 we check for windows logs only
if logsource["product"].lower() == "windows":
if "category" in logsource:
if logsource['category'] == "process_creation":
# {"rule_file_name" : [fields used]}
fields = extract_fields(detection)
windows_category_process_creation_dict[file_] = fields
elif logsource['category'] == "ps_script":
fields = extract_fields(detection)
windows_category_ps_script_dict[file_] = fields
elif logsource['category'] == "ps_module":
# {"rule_file_name" : [fields used]}
fields = extract_fields(detection)
windows_category_ps_module_dict[file_] = fields
elif "service" in logsource:
if logsource["service"].lower() == "security":
eid_list = extract_events_ids(detection)
windows_service_security_dict[file_] = eid_list
elif logsource["service"].lower() == "powershell":
eid_list = extract_events_ids(detection)
windows_service_powershell_dict[file_] = eid_list
return windows_service_security_dict, windows_service_powershell_dict, windows_category_process_creation_dict, windows_category_ps_module_dict, windows_category_ps_script_dict
def enrich_logsource_dict(logsource_dict_list):
for logsource in logsource_dict_list:
if "product" in logsource.keys:
if logsource["product"] == "windows":
if "service" in logsource.keys:
pass
elif "category" in logsource.keys:
pass
def parse_gpresult(gpresult):
"""
Parses GPResult command XML output
"""
enabled_sec_policies = []
enabled_other_logs = defaultdict(list)
tree = ET.parse(gpresult)
root = tree.getroot()
for child in root:
if "ComputerResults" in child.tag:
computerResultsNode = child
break
extensionDataList = []
for i in computerResultsNode:
if "ExtensionData" in i.tag:
extensionDataList.append(i)
for i in extensionDataList:
ext_type = i[0].attrib[next(iter(i[0].attrib))]
if "AuditSettings" in ext_type:
auditSettings = i[0]
for audit in auditSettings:
SubcategoryGuid = ""
SettingValue = ""
for element in audit:
if "SubcategoryGuid" in element.tag:
SubcategoryGuid = element
elif "SettingValue" in element.tag:
SettingValue = element
# If the audit settings is enabled for "Success" or both "Success and Failure". Then it's okay (for V0.1)
if SettingValue.text == "1" or SettingValue.text == "3":
enabled_sec_policies.append(SubcategoryGuid.text.upper())
elif "Registry" in ext_type:
registrySettings = i[0]
for policy in registrySettings:
if "}Policy" in policy.tag:
policyName = ""
policyState = ""
policyCategory = ""
for element in policy:
if "Name" in element.tag:
policyName = element
elif "State" in element.tag:
policyState = element
elif "Category" in element.tag:
policyCategory = element
# {"Category": {"Name": "State"}}
tmp = {policyName.text : policyState.text}
enabled_other_logs[policyCategory.text].append(tmp)
return enabled_sec_policies, enabled_other_logs
if __name__ == "__main__":
print(f"""
_____ _
/ ___/(_)___ _____ ___ ____ _
\__ \/ / __ `/ __ `__ \/ __ `/
___/ / / /_/ / / / / / / /_/ /
/____/_/\__, /_/ /_/ /_/\__,_/ ________ __
/ / /____/ ____ __________ __ _______________ / ____/ /_ ___ _____/ /_____ _____
/ / / __ \/ __ `/ ___/ __ \/ / / / ___/ ___/ _ \ / / / __ \/ _ \/ ___/ //_/ _ \/ ___/
/ /___/ /_/ / /_/ (__ ) /_/ / /_/ / / / /__/ __/ / /___/ / / / __/ /__/ ,< / __/ /
/_____/\____/\__, /____/\____/\__,_/_/ \___/\___/ \____/_/ /_/\___/\___/_/|_|\___/_/
/____/ by Nasreddine Bencherchali (Nextron Systems), v{__version__}
""")
parser = argparse.ArgumentParser(description='SIGMA Logsource Checker')
parser.add_argument('-d', help='Path to input directory (SIGMA rules folder; recursive)', metavar='sigma-rules-folder', required=True)
parser.add_argument('-gp', help='XML output of the command "gpresult.exe /x [path]"', metavar='gpresult')
#parser.add_argument('-sysmon', help='Sysmon configuration', metavar='sysmon-config') # TODO: add Sysmon config parser
parser.add_argument('-v', help='Get audit and logging details for every rule', action="store_true")
#parser.add_argument('-vv', help='Get audit and logging details for every rule', metavar='Very Verbose')
args = parser.parse_args()
if os.path.isdir(args.d):
path_to_rules = args.d
else:
print("The path provided isn't a directory: %s" % args.d)
exit(1)
if args.gp:
gpresult = args.gp
print("Parsing gpresults file (XML) %s ...\n" % args.gp)
subcategory_id, enabled_other_logs = parse_gpresult(gpresult)
else:
subcategory_id = []
enabled_other_logs = OTHER_EVENT_ID_MAPPING
print("Discovering used log sources ...\n")
faulty_rules = test_invalid_logsource_attributes(path_to_rules)
windows_service_security_dict, windows_service_powershell_dict, windows_category_process_creation_dict, windows_category_ps_module_dict, windows_category_ps_script_dict = get_logsource_dict(path_to_rules, faulty_rules)
if args.v:
print("Generating detailed logging requirements information for every rule...\n")
sleep(1)
if windows_category_process_creation_dict:
print(f"\nChecking rules with logsource - 'product: windows / category: process_creation'...")
# We check special fields. If they exist then we suggest the policy to be enabled
for filename, fields in windows_category_process_creation_dict.items():
special_fields_sysmon = []
special_fields_security = []
for field in fields:
if field in WINDOWS_SYSMON_SPECIAL_PROCESS_CREATION_FIELDS:
special_fields_sysmon.append(field)
elif field in WINDOWS_SECURITY_SPECIAL_PROCESS_CREATION_FIELDS:
special_fields_security.append(field)
if special_fields_sysmon:
print("-> Rule '{}' uses fields: {} which Requires Microsoft-Windows-Sysmon EID 1 to be enabled".format(os.path.basename(filename), special_fields_sysmon))
elif special_fields_security:
if "{0CCE922B-69AE-11D9-BED3-505054503030}" not in subcategory_id:
print("-> Rule '{}' uses fields: {} which Requires Microsoft Windows Security Auditing EID 4688 to be enabled".format(os.path.basename(filename), special_fields_security))
else:
if "{0CCE922B-69AE-11D9-BED3-505054503030}" not in subcategory_id:
print("-> Rule '{}' uses fields: {} which Requires 'Microsoft Windows Security Auditing EID 4688' or 'Microsoft-Windows-Sysmon EID 1' to be enabled".format(os.path.basename(filename), fields))
if windows_category_ps_module_dict:
print(f"\nChecking rules with logsource - 'product: windows / category: ps_module'...")
pwsh5_ps_module_enabled = False
pwsh5 = "Windows Components/Windows PowerShell"
#pwsh7 = "PowerShell Core" # TODO: Add PWSH7 Checks
if pwsh5 in enabled_other_logs:
if enabled_other_logs[pwsh5][0]['Turn on Module Logging'] == "Enabled":
pwsh5_ps_module_enabled = True
for filename, fields in windows_category_ps_module_dict.items():
if not pwsh5_ps_module_enabled:
print("-> Rule '{}' uses fields: {} which Requires Microsoft-Windows-PowerShell EID 4103 to be enabled".format(os.path.basename(filename), fields))
if windows_category_ps_script_dict:
print(f"\nChecking rules with logsource - 'product: windows / category: ps_script'...")
pwsh5_ps_script_enabled = False
pwsh5 = "Windows Components/Windows PowerShell"
#pwsh7 = "PowerShell Core" # TODO: Add PWSH7 Checks
if pwsh5 in enabled_other_logs:
if enabled_other_logs[pwsh5][1]['Turn on PowerShell Script Block Logging'] == "Enabled":
pwsh5_ps_script_enabled = True
for filename, fields in windows_category_ps_script_dict.items():
if not pwsh5_ps_script_enabled:
print("-> Rule '{}' uses fields: {} which Requires Microsoft-Windows-PowerShell EID 4104 to be enabled".format(os.path.basename(filename), fields))
if windows_service_security_dict:
print(f"\nChecking rules using logsource - 'product: windows / service: security'...")
for filename, eids in windows_service_security_dict.items():
specific_eids = set()
specific_subcategory = set()
for eid in eids:
for key, value in SECURITY_EVENT_ID_MAPPING.items():
if value['EventIDs']:
if ((eid in value['EventIDs']) and (key not in subcategory_id)):
specific_eids.add(eid)
specific_subcategory.add((key, value['Name']))
specific_eids = list(specific_eids)
specific_subcategory = list(specific_subcategory)
if len(specific_subcategory) > 1:
print("-> Rule '{}' uses EventIDs: {} which Requires:".format(os.path.basename(filename), specific_eids))
for i in specific_subcategory:
print(" - '{}' / {} to be enabled".format(i[1], i[0]))
else:
if len(specific_subcategory) != 0:
print("-> Rule '{}' uses EventIDs: {} which Requires: '{}' / {} to be enabled".format(os.path.basename(filename), specific_eids, specific_subcategory[0][1], specific_subcategory[0][0]))
else:
print("Generating generic logging requirements information for the rule set...")
sleep(1)
# If no verbose mode was triggered we generate a generic audit policy suggestion for all rules
# Process Creation Rules
if windows_category_process_creation_dict:
enable_sysmon = False
enable_4688 = False
print(f"\nChecking rules with logsource - 'product: windows / category: process_creation'...")
# We check special fields. If they exist then we suggest the policy to be enabled
all_process_creation_fields = []
for filename, fields in windows_category_process_creation_dict.items():
all_process_creation_fields += fields
all_process_creation_fields = list(set(all_process_creation_fields))
for field in WINDOWS_SYSMON_SPECIAL_PROCESS_CREATION_FIELDS:
if field in all_process_creation_fields:
enable_sysmon = True
print("-> Rules use Sysmon EID 1 only fields. A Sysmon configuration monitoring Process Creation is required")
break
if not enable_sysmon:
for field in WINDOWS_SECURITY_SPECIAL_PROCESS_CREATION_FIELDS:
if field in all_process_creation_fields:
if "{0CCE922B-69AE-11D9-BED3-505054503030}" not in subcategory_id:
enable_4688 = True
print("-> Rules use Microsoft-Windows-Security-Auditing EID 4688 only fields. Audit policy sub-category {0CCE922B-69AE-11D9-BED3-505054503030} / 'Process Creation' must be enabled")
break
else:
print("Audit policy sub-category {0CCE922B-69AE-11D9-BED3-505054503030} / 'Process Creation' is already enabled")
break
if not enable_4688:
print("-> Audit policy sub-category {0CCE922B-69AE-11D9-BED3-505054503030} / 'Process Creation' must be enabled")
if windows_category_ps_module_dict:
print(f"\nChecking rules with logsource - 'product: windows / category: ps_module'...")
pwsh5 = "Windows Components/Windows PowerShell"
#pwsh7 = "PowerShell Core" # TODO: Add PWSH7 Checks
if pwsh5 in enabled_other_logs:
if enabled_other_logs[pwsh5][0]['Turn on Module Logging'] != "Enabled":
print("-> Rules use Microsoft-Windows-PowerShell EID 4103. Audit policy 'Module Logging' must be enabled")
else:
print("-> PowerShell 'Module Logging' is Enabled")
if windows_category_ps_script_dict:
print(f"\nChecking rules with logsource - 'product: windows / category: ps_script'...")
pwsh5 = "Windows Components/Windows PowerShell"
#pwsh7 = "PowerShell Core" # TODO: Add PWSH7 Checks
if pwsh5 in enabled_other_logs:
if enabled_other_logs[pwsh5][1]['Turn on PowerShell Script Block Logging'] != "Enabled":
print("-> Rules use Microsoft-Windows-PowerShell EID 4104. Audit policy PowerShell 'Script Block Logging' must be enabled")
else:
print("-> PowerShell 'Script Block Logging' is Enabled")
if windows_service_security_dict:
print(f"\nChecking rules using logsource - 'product: windows / service: security'...")
all_security_eids = []
for filename, eids in windows_service_security_dict.items():
all_security_eids += eids
all_security_eids = list(set(all_security_eids))
for eid in all_security_eids:
for key, value in SECURITY_EVENT_ID_MAPPING.items():
if value['EventIDs']:
if ((eid in value['EventIDs']) and (key not in subcategory_id)):
print("-> Rules use events generated from audit policy sub-category '{}'. The audit policy '{}' must be enabled".format(key, value['Name']))
subcategory_id.append(key)
print("\nFor more information on how to setup logging, you can visit: https://github.com/SigmaHQ/sigma/tree/master/rules-documentation/logsource-guides")