mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Merge branch 'automatically_build_src' of github.com:splunk/security-content into automatically_build_src
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# Set to true to add reviewers to pull requests
|
||||
addReviewers: true
|
||||
|
||||
# Set to true to add assignees to pull requests
|
||||
addAssignees: true
|
||||
|
||||
# A list of reviewers to be added to pull requests (GitHub user name)
|
||||
reviewers:
|
||||
- d1vious
|
||||
- rvaldez617
|
||||
- patel-bhavin
|
||||
|
||||
# A number of reviewers added to the pull request
|
||||
# Set 0 to add all the reviewers (default: 0)
|
||||
numberOfReviewers: 0
|
||||
|
||||
# A list of assignees, overrides reviewers if set
|
||||
# assignees:
|
||||
# - assigneeA
|
||||
|
||||
# A number of assignees to add to the pull request
|
||||
# Set to 0 to add all of the assignees.
|
||||
# Uses numberOfReviewers if unset.
|
||||
# numberOfAssignees: 2
|
||||
|
||||
# A list of keywords to be skipped the process that add reviewers if pull requests include it
|
||||
# skipKeywords:
|
||||
# - wip
|
||||
+44
-21
@@ -6,6 +6,7 @@ import glob
|
||||
from os import path, environ
|
||||
import json
|
||||
import jsonschema
|
||||
import sys
|
||||
|
||||
# HIGH Level Fields
|
||||
|
||||
@@ -50,7 +51,7 @@ PROVIDING_TECHNOLOGIES = [
|
||||
"Splunk Stream", "Active Directory", "Bluecoat",
|
||||
"Carbon Black Response", "Carbon Black Protect", "CrowdStrike Falcon",
|
||||
"Microsoft Exchange", "Nessus", "Palo Alto Firewall", "Qualys",
|
||||
"Sysmon", "Tanium", "Ziften", "AWS"
|
||||
"Sysmon", "Tanium", "Ziften", "AWS", "OSquery"
|
||||
]
|
||||
|
||||
KILL_CHAIN_PHASES = [
|
||||
@@ -271,7 +272,8 @@ def validate_search_manifest(search):
|
||||
data_model)
|
||||
|
||||
if 'providing_technologies' in search['data_metadata']:
|
||||
for providing_technology in search['data_metadata']['providing_technologies']:
|
||||
for providing_technology in \
|
||||
search['data_metadata']['providing_technologies']:
|
||||
if providing_technology not in PROVIDING_TECHNOLOGIES:
|
||||
errors.append(
|
||||
'ERRORS: Unknown product in providing technologies: %s' %
|
||||
@@ -280,16 +282,19 @@ def validate_search_manifest(search):
|
||||
if search['search_type'] == 'detection':
|
||||
try:
|
||||
if search['correlation_rule']['risk']:
|
||||
for risk_object_type in search['correlation_rule']['risk']['risk_object_type']:
|
||||
for risk_object_type in \
|
||||
search['correlation_rule']['risk']['risk_object_type']:
|
||||
if risk_object_type not in RISK_OBJECCT_TYPE:
|
||||
errors.append(
|
||||
'ERRORS: Unknown risk object type, must be system, user, or other got: %s' %
|
||||
'ERRORS: Unknown risk object type, must be system, \
|
||||
user, or other got: %s' %
|
||||
risk_object_type)
|
||||
except BaseException:
|
||||
errors.append('WARNING: correlation_rule is missing risk object')
|
||||
|
||||
if 'providing_technologies' in search['data_metadata']:
|
||||
for providing_technology in search['data_metadata']['providing_technologies']:
|
||||
for providing_technology in \
|
||||
search['data_metadata']['providing_technologies']:
|
||||
if providing_technology not in PROVIDING_TECHNOLOGIES:
|
||||
errors.append(
|
||||
'ERRORS: Unknown product in providing technologies: %s' %
|
||||
@@ -299,20 +304,25 @@ def validate_search_manifest(search):
|
||||
if '| tstats' in search['search'] or 'datamodel' in search['search']:
|
||||
if 'data_models' not in search['data_metadata']:
|
||||
errors.append(
|
||||
"The search uses a data model but 'data_models' field is not set")
|
||||
"The search uses a data model but 'data_models' \
|
||||
field is not set")
|
||||
|
||||
if 'data_models' in search and not search['data_metadata']['data_models']:
|
||||
if 'data_models' in search and not \
|
||||
search['data_metadata']['data_models']:
|
||||
errors.append(
|
||||
"The search uses a data model but 'data_models' is empty")
|
||||
|
||||
if 'sourcetype' in search['search']:
|
||||
if 'data_sourcetypes' not in search['data_metadata']:
|
||||
errors.append(
|
||||
"The search specifies a sourcetype but 'data_sourcetypes' field is not set")
|
||||
"The search specifies a sourcetype but 'data_sourcetypes' \
|
||||
field is not set")
|
||||
|
||||
if 'data_sourcetypes' in search and not search['data_metadata']['data_sourcetypes']:
|
||||
if 'data_sourcetypes' in search and not \
|
||||
search['data_metadata']['data_sourcetypes']:
|
||||
errors.append(
|
||||
"The search specifies a sourcetype but 'data_sourcetypes' is empty")
|
||||
"The search specifies a sourcetype but \
|
||||
'data_sourcetypes' is empty")
|
||||
|
||||
try:
|
||||
search['search_description'].encode('ascii')
|
||||
@@ -337,7 +347,8 @@ def validate_search_manifest(search):
|
||||
except UnicodeEncodeError:
|
||||
errors.append("known_false_positives not ascii")
|
||||
|
||||
if 'correlation_rule' in search and 'notable' in search['correlation_rule']:
|
||||
if 'correlation_rule' in search and 'notable' in \
|
||||
search['correlation_rule']:
|
||||
try:
|
||||
search['correlation_rule']['notable']['rule_title'].encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
@@ -388,7 +399,8 @@ def main():
|
||||
path.expanduser(MANIFEST_DIRECTORY),
|
||||
'spec/analytic_story.json.spec')
|
||||
story_schema = json.loads(open(story_schema_file, 'rb').read())
|
||||
story_manifest_files = path.join(path.expanduser(MANIFEST_DIRECTORY), "*/stories/*.json")
|
||||
story_manifest_files = path.join(path.expanduser(MANIFEST_DIRECTORY),
|
||||
"*/stories/*.json")
|
||||
for story_manifest_file in glob.glob(story_manifest_files):
|
||||
try:
|
||||
story_manifest_data = json.loads(
|
||||
@@ -420,11 +432,13 @@ def main():
|
||||
detection_search_schema = json.loads(
|
||||
open(detection_search_schema_file, 'rb').read())
|
||||
contextual_search_schema_file = path.join(
|
||||
path.expanduser(MANIFEST_DIRECTORY), 'spec/contextual_search.json.spec')
|
||||
path.expanduser(MANIFEST_DIRECTORY),
|
||||
'spec/contextual_search.json.spec')
|
||||
contextual_search_schema = json.loads(
|
||||
open(contextual_search_schema_file, 'rb').read())
|
||||
investigative_search_schema_file = path.join(
|
||||
path.expanduser(MANIFEST_DIRECTORY), 'spec/investigative_search.json.spec')
|
||||
path.expanduser(MANIFEST_DIRECTORY),
|
||||
'spec/investigative_search.json.spec')
|
||||
investigative_search_schema = json.loads(
|
||||
open(investigative_search_schema_file, 'rb').read())
|
||||
support_search_schema_file = path.join(
|
||||
@@ -445,7 +459,8 @@ def main():
|
||||
print e
|
||||
continue
|
||||
|
||||
if 'status' in search_manifest_data and search_manifest_data['status'] == 'development':
|
||||
if 'status' in search_manifest_data and \
|
||||
search_manifest_data['status'] == 'development':
|
||||
continue
|
||||
|
||||
if 'search_type' not in search_manifest_data:
|
||||
@@ -502,7 +517,8 @@ def main():
|
||||
|
||||
if search_manifests[ds]['search_type'] != 'detection':
|
||||
errors = True
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" as a detection search" % (
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" \
|
||||
as a detection search" % (
|
||||
story_name, ds)
|
||||
|
||||
if 'investigative_searches' in story_data['searches']:
|
||||
@@ -517,7 +533,8 @@ def main():
|
||||
|
||||
if search_manifests[invs]['search_type'] != 'investigative':
|
||||
errors = True
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" as a investigative search" % (
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" \
|
||||
as a investigative search" % (
|
||||
story_name, invs)
|
||||
|
||||
if 'contextual_searches' in story_data['searches']:
|
||||
@@ -525,12 +542,14 @@ def main():
|
||||
if cs not in search_manifests:
|
||||
print "INFO: %s has a contextual search, \
|
||||
%s, not in local repo. Verify name of search provided \
|
||||
in Enterprise Security Content Updates" % (story_name, cs)
|
||||
in Enterprise Security Content Updates" \
|
||||
% (story_name, cs)
|
||||
continue
|
||||
|
||||
if search_manifests[cs]['search_type'] != 'contextual':
|
||||
errors = True
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" as a contextual search" % (
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" \
|
||||
as a contextual search" % (
|
||||
story_name, cs)
|
||||
|
||||
if 'support_searches' in story_data['searches']:
|
||||
@@ -544,12 +563,16 @@ def main():
|
||||
|
||||
if search_manifests[ss]['search_type'] != 'support':
|
||||
errors = True
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" as a support search" % (
|
||||
print "ERROR: \"%s\" mislabeled \"%s\" \
|
||||
as a support search" % (
|
||||
story_name, ss)
|
||||
|
||||
print "%d story manifests checked" % len(story_manifests)
|
||||
print "%d search manifests checked" % len(search_manifests)
|
||||
if not errors:
|
||||
|
||||
if errors:
|
||||
sys.exit("Errors found")
|
||||
else:
|
||||
print "No errors found"
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Endpoint"
|
||||
],
|
||||
"providing_technologies": [
|
||||
"osquery"
|
||||
"OSquery"
|
||||
]
|
||||
},
|
||||
"eli5": "The search looks at the Alerts data model to identify those generated from the osquery osx-attacks.conf pack, which search for the ColdRoot RAT.",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"Endpoint"
|
||||
],
|
||||
"providing_technologies": [
|
||||
"osquery"
|
||||
"OSquery"
|
||||
]
|
||||
},
|
||||
"eli5": "The search leverages Alerts generated from the osquery osx-attacks.conf pack search `Keyboard_Event_Taps` to detect when a process is monitoring the keystrokes of a machine, This is a common technique used by macOS remote access trojans to log keystrokes from a machine",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"channel": "ESCU",
|
||||
"creation_date": "2019-01-29",
|
||||
"description": "Leverage searches that allow you to detect and investigate unusual activities that relate to the ColdRoot Remote Access Trojan that affects MacOS. An example of some of these activities are changing sensative binaries in the MacOS sub-system, detecting process names and executables associated with the RAT, detecting when a keyboard tab is installed on a MacOS machine and more.",
|
||||
"id": "bd91a2bc-d20b-4f44-a982-1bea98e86390",
|
||||
"id": "ad7eb6e0-f06c-4781-b145-a42bd59c56e9",
|
||||
"maintainers": [
|
||||
{
|
||||
"company": "Splunk",
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
"Sysmon",
|
||||
"Tanium",
|
||||
"Ziften",
|
||||
"osquery"
|
||||
"OSquery"
|
||||
]
|
||||
},
|
||||
"minItems": 0,
|
||||
|
||||
+6
-3
@@ -100,9 +100,12 @@ class DomainFuzz(object):
|
||||
for d in self.domains:
|
||||
# if not self.__validate_domain(d['domain-name']):
|
||||
# p_err("debug: invalid domain %s\n" % d['domain-name'])
|
||||
if self.__validate_domain(d['domain-name']) and d['domain-name'] not in seen:
|
||||
seen.add(d['domain-name'])
|
||||
filtered.append(d)
|
||||
try:
|
||||
if self.__validate_domain(d['domain-name']) and d['domain-name'] not in seen:
|
||||
seen.add(d['domain-name'])
|
||||
filtered.append(d)
|
||||
except:
|
||||
continue
|
||||
|
||||
self.domains = filtered
|
||||
|
||||
|
||||
Reference in New Issue
Block a user