mirror of
https://github.com/valitydev/atomic-threat-coverage.git
synced 2024-11-06 09:35:21 +00:00
Merge branch 'develop' into 'master'
Develop See merge request krakow2600/atomic-threat-coverage!94
This commit is contained in:
commit
a774201a63
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@ description: >
|
||||
loggingpolicy:
|
||||
- LP_0004_windows_audit_logon
|
||||
references:
|
||||
- https://github.com/MicrosoftDocs/windows-itpro-docs/blob/95b9d7c01805839c067e352d1d16702604b15f11/windows/security/threat-protection/auditing/event-4688.md
|
||||
- https://github.com/MicrosoftDocs/windows-itpro-docs/blob/95b9d7c01805839c067e352d1d16702604b15f11/windows/security/threat-protection/auditing/event-4624.md
|
||||
category: OS Logs
|
||||
platform: Windows
|
||||
type: Windows Log
|
||||
|
@ -111,7 +111,7 @@ If no local configuration is found on the argument path, a warning will be shown
|
||||
"""Open the yaml file and load it to the variable.
|
||||
Return created list"""
|
||||
with open(path) as f:
|
||||
yaml_fields = yaml.load_all(f.read())
|
||||
yaml_fields = yaml.load_all(f.read(), Loader=yaml.FullLoader)
|
||||
|
||||
buff_results = [x for x in yaml_fields]
|
||||
if len(buff_results) > 1:
|
||||
@ -149,6 +149,16 @@ class ATCutils:
|
||||
|
||||
return rule_text
|
||||
|
||||
@staticmethod
|
||||
def get_normalized_field(field):
|
||||
# return everything before field modifier (pipe)
|
||||
regex = '^(.*?)\|'
|
||||
try:
|
||||
return re.search(regex, field).group(1)
|
||||
except:
|
||||
return field
|
||||
|
||||
|
||||
@staticmethod
|
||||
def read_yaml_file(path):
|
||||
"""Open the yaml file and load it to the variable.
|
||||
@ -162,7 +172,7 @@ class ATCutils:
|
||||
return ATCConfig(path).config
|
||||
|
||||
with open(path) as f:
|
||||
yaml_fields = yaml.load_all(f.read())
|
||||
yaml_fields = yaml.load_all(f.read(), Loader=yaml.FullLoader)
|
||||
|
||||
buff_results = [x for x in yaml_fields]
|
||||
if len(buff_results) > 1:
|
||||
@ -240,7 +250,7 @@ class ATCutils:
|
||||
url = apipath + "content"
|
||||
space_page_url = url + '?spaceKey=' + space + '&title=' \
|
||||
+ title + '&expand=space'
|
||||
# print(space_page_url)
|
||||
|
||||
response = requests.request(
|
||||
"GET",
|
||||
space_page_url,
|
||||
@ -255,8 +265,6 @@ class ATCutils:
|
||||
else:
|
||||
response = response.json()
|
||||
|
||||
# print(response)
|
||||
|
||||
# Check if response contains proper information and return it if so
|
||||
if response.get('results'):
|
||||
if isinstance(response['results'], list):
|
||||
@ -470,13 +478,16 @@ class ATCutils:
|
||||
list) and _field != 'EventID':
|
||||
for val2 in detection_dict[_field]:
|
||||
if isinstance(val2, str) or isinstance(val2, int):
|
||||
dictionary_of_fields.append(_field)
|
||||
normalized_key = ATCutils.get_normalized_field(_field)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
break
|
||||
else:
|
||||
for val3 in val2:
|
||||
dictionary_of_fields.append(val3)
|
||||
normalized_key = ATCutils.get_normalized_field(val3)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
else:
|
||||
dictionary_of_fields.append(val)
|
||||
normalized_key = ATCutils.get_normalized_field(val)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
|
||||
return dictionary_of_fields
|
||||
|
||||
@ -501,15 +512,18 @@ class ATCutils:
|
||||
list) and _field != 'EventID':
|
||||
for val2 in detection_dict[_field]:
|
||||
if isinstance(val2, str) or isinstance(val2, int):
|
||||
dictionary_of_fields.append(_field)
|
||||
normalized_key = ATCutils.get_normalized_field(_field)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
break
|
||||
elif isinstance(val2, str):
|
||||
continue
|
||||
else:
|
||||
for val3 in val2:
|
||||
dictionary_of_fields.append(val3)
|
||||
normalized_key = ATCutils.get_normalized_field(val3)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
else:
|
||||
dictionary_of_fields.append(_field)
|
||||
normalized_key = ATCutils.get_normalized_field(_field)
|
||||
dictionary_of_fields.append(normalized_key)
|
||||
|
||||
return dictionary_of_fields
|
||||
|
||||
@ -559,6 +573,7 @@ class ATCutils:
|
||||
continue
|
||||
|
||||
if isinstance(_field, str):
|
||||
_field = ATCutils.get_normalized_field(_field)
|
||||
if _field == 'CommandLine' or \
|
||||
_field == 'ProcessCommandLine' or \
|
||||
_field == 'ProcesssCommandLine' or \
|
||||
@ -567,6 +582,7 @@ class ATCutils:
|
||||
|
||||
if isinstance(_field, dict):
|
||||
for item in _field:
|
||||
item = ATCutils.get_normalized_field(item)
|
||||
if item == 'CommandLine' or \
|
||||
item == 'ProcessCommandLine' or \
|
||||
item == 'ProcesssCommandLine' or \
|
||||
@ -578,18 +594,18 @@ class ATCutils:
|
||||
@staticmethod
|
||||
def check_for_event_ids_presence(detection_rule_obj):
|
||||
"""check if this is event id based detection rule"""
|
||||
|
||||
for _field in detection_rule_obj['detection']:
|
||||
if _field in ["condition", "timeframe"]:
|
||||
continue
|
||||
for __field in detection_rule_obj['detection'][_field]:
|
||||
if isinstance(__field, str) or isinstance(__field, int):
|
||||
if __field == 'EventID':
|
||||
return True
|
||||
elif isinstance(__field, dict):
|
||||
for item in __field:
|
||||
if item == 'EventID':
|
||||
if detection_rule_obj.get('detection'):
|
||||
for _field in detection_rule_obj['detection']:
|
||||
if _field in ["condition", "timeframe"]:
|
||||
continue
|
||||
for __field in detection_rule_obj['detection'][_field]:
|
||||
if isinstance(__field, str) or isinstance(__field, int):
|
||||
if __field == 'EventID':
|
||||
return True
|
||||
elif isinstance(__field, dict):
|
||||
for item in __field:
|
||||
if item == 'EventID':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@ -660,6 +676,7 @@ class ATCutils:
|
||||
if not detectionrule.get('action'):
|
||||
|
||||
logsource = ATCutils.get_logsource_of_the_document(detectionrule)
|
||||
|
||||
event_id_based_dr = ATCutils.check_for_event_ids_presence(detectionrule)
|
||||
|
||||
# if this is event id based detection rule we calculate PER SELECTION
|
||||
@ -732,6 +749,7 @@ class ATCutils:
|
||||
# check if first document has logsource
|
||||
logsource = ATCutils.get_logsource_of_the_document(detectionrule)
|
||||
if logsource:
|
||||
|
||||
event_id_based_dr = ATCutils.check_for_event_ids_presence(detectionrule)
|
||||
|
||||
if event_id_based_dr:
|
||||
@ -780,6 +798,7 @@ class ATCutils:
|
||||
for addition in detectionrule['additions']:
|
||||
|
||||
logsource = ATCutils.get_logsource_of_the_document(addition)
|
||||
|
||||
event_id_based_dr = ATCutils.check_for_event_ids_presence(addition)
|
||||
|
||||
if event_id_based_dr:
|
||||
@ -801,23 +820,25 @@ class ATCutils:
|
||||
else:
|
||||
full_list_of_fields = []
|
||||
|
||||
# just in case there are multiple selections in first document
|
||||
for _field in addition['detection']:
|
||||
|
||||
if str(_field) in ["condition", "timeframe"]:
|
||||
continue
|
||||
|
||||
try:
|
||||
detection_fields = ATCutils\
|
||||
.search_for_fields2(addition['detection'][_field])
|
||||
except Exception as e:
|
||||
detection_fields = ATCutils\
|
||||
.search_for_fields(addition['detection'])
|
||||
|
||||
if detection_fields:
|
||||
for field in detection_fields:
|
||||
if field not in full_list_of_fields:
|
||||
full_list_of_fields.append(field)
|
||||
# sometimes docs don't have detection section
|
||||
if addition.get('detection'):
|
||||
# just in case there are multiple selections in first document
|
||||
for _field in addition['detection']:
|
||||
|
||||
if str(_field) in ["condition", "timeframe"]:
|
||||
continue
|
||||
|
||||
try:
|
||||
detection_fields = ATCutils\
|
||||
.search_for_fields2(addition['detection'][_field])
|
||||
except Exception as e:
|
||||
detection_fields = ATCutils\
|
||||
.search_for_fields(addition['detection'])
|
||||
|
||||
if detection_fields:
|
||||
for field in detection_fields:
|
||||
if field not in full_list_of_fields:
|
||||
full_list_of_fields.append(field)
|
||||
|
||||
final_list += ATCutils.calculate_dn_for_non_eventid_based_dr(
|
||||
dn_list, full_list_of_fields, logsource)
|
||||
|
@ -1,5 +1,7 @@
|
||||
import sys
|
||||
import re
|
||||
import yaml
|
||||
import pprint
|
||||
import getopt
|
||||
import json
|
||||
import os
|
||||
@ -36,6 +38,29 @@ def main(**kwargs):
|
||||
techniques = []
|
||||
list_of_customers = []
|
||||
|
||||
# raw Sigma rule without fields that are present separately
|
||||
dr_raw = alert.copy()
|
||||
|
||||
fields_to_remove_from_raw_dr = [
|
||||
'title',
|
||||
'id',
|
||||
'status',
|
||||
'date',
|
||||
'modified',
|
||||
'description',
|
||||
'references',
|
||||
'author',
|
||||
'tags',
|
||||
'logsource',
|
||||
'falsepositives',
|
||||
'level'
|
||||
]
|
||||
|
||||
for field in fields_to_remove_from_raw_dr:
|
||||
dr_raw.pop(field, None)
|
||||
|
||||
dr_raw = str(yaml.dump((dr_raw), default_flow_style=False))
|
||||
|
||||
for customer in cu_list:
|
||||
if 'detectionrule' in customer:
|
||||
if alert['title'] in customer['detectionrule'] and customer['customer_name'] not in list_of_customers:
|
||||
@ -59,7 +84,6 @@ def main(**kwargs):
|
||||
pass
|
||||
|
||||
enrichments = [er for er in enrichments_list if er['title'] in alert.get('enrichment', [{'title':'-'}])]
|
||||
#print(enrichments)
|
||||
if len(enrichments) < 1:
|
||||
enrichments = [{'title': 'not defined'}]
|
||||
dn_titles = ATCutils.main_dn_calculatoin_func(path)
|
||||
@ -102,6 +126,24 @@ def main(**kwargs):
|
||||
#date_created = datetime.datetime.now().isoformat()
|
||||
date_created = '2019-03-01T22:50:37.587060'
|
||||
|
||||
# we use date of creation to have timelines of progress
|
||||
if 'modified' in alert:
|
||||
|
||||
try:
|
||||
date_modified = datetime.datetime.strptime(alert['modified'], '%Y/%m/%d').isoformat()
|
||||
except:
|
||||
pass
|
||||
|
||||
if not date_modified:
|
||||
try:
|
||||
# in case somebody mixed up month and date, like in "Detection of SafetyKatz"
|
||||
date_modified = datetime.datetime.strptime(alert['modified'], '%Y/%d/%m').isoformat()
|
||||
except:
|
||||
date_modified = None
|
||||
else:
|
||||
# temporary solution to avoid errors. all internal DRs must have date of creation
|
||||
#date_created = datetime.datetime.now().isoformat()
|
||||
date_modified = None
|
||||
|
||||
# we create index document based on DR title, which is unique (supposed to be).
|
||||
# this way we will update existing documents in case of changes,
|
||||
@ -146,6 +188,11 @@ def main(**kwargs):
|
||||
else:
|
||||
dr_author = 'not defined'
|
||||
|
||||
if 'id' in alert:
|
||||
dr_id = alert['id']
|
||||
else:
|
||||
dr_id = 'not defined'
|
||||
|
||||
if 'internal_responsible' in alert:
|
||||
dr_internal_responsible = alert['internal_responsible']
|
||||
else:
|
||||
@ -196,10 +243,13 @@ def main(**kwargs):
|
||||
|
||||
_index.update({
|
||||
"date_created": date_created,
|
||||
"date_modified": date_modified,
|
||||
"customer": list_of_customers,
|
||||
"tactic": list_of_tactics,
|
||||
"dr_id": dr_id,
|
||||
"technique": list_of_techniques,
|
||||
"detection_rule": dr_title,
|
||||
"raw_detection_rule": dr_raw,
|
||||
"detection_rule_title": dr_title,
|
||||
"detection_rule_author": dr_author,
|
||||
"detection_rule_internal_responsible": dr_internal_responsible,
|
||||
"detection_rule_development_status": dr_status,
|
||||
|
Loading…
Reference in New Issue
Block a user