2023-03-24 13:53:59 +01:00
# 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 :
2024-01-10 17:14:31 +01:00
if file . endswith ( " .yml " ) :
yield os . path . join ( root , file )
2023-03-24 13:53:59 +01:00
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 " \n Checking 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 " \n Checking 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 " \n Checking 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 " \n Checking 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 " \n Checking 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 " \n Checking 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 " \n Checking 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 " \n Checking 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 )
2023-03-24 13:56:11 +01:00
print ( " \n For more information on how to setup logging, you can visit: https://github.com/SigmaHQ/sigma/tree/master/rules-documentation/logsource-guides " )