Skip to content

Commit

Permalink
Merge branch 'develop' into threat_q-connector
Browse files Browse the repository at this point in the history
  • Loading branch information
delliott90 authored May 12, 2023
2 parents 2c0db6a + 6141486 commit 8b80cab
Show file tree
Hide file tree
Showing 114 changed files with 8,410 additions and 1,363 deletions.
19 changes: 9 additions & 10 deletions adapter-guide/connectors/azure_sentinel_supported_stix.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
##### Updated on 02/27/23
##### Updated on 05/02/23
## Microsoft Graph Security
### Supported STIX Operators
*Comparison AND/OR operators are inside the observation while observation AND/OR operators are between observations (square brackets).*
Expand Down Expand Up @@ -45,7 +45,7 @@
| **process**:pid | processes.processId, processes.parentProcessId, registryKeyStates.processId |
| **process**:created | processes.createdDateTime |
| **process**:parent_ref.pid | processes.parentProcessId |
| **process**:binary_ref.path | processes.path |
| **process**:binary_ref.parent_directory_ref.path | processes.path |
| **domain-name**:value | hostStates.fqdn, hostStates.netBiosName, networkConnections.destinationDomain, userStates.domainName |
| **user-account**:user_id | userStates.accountName, processes.accountName, userStates.aadUserId |
| **user-account**:account_login | userStates.logonId |
Expand All @@ -54,11 +54,11 @@
| **software**:name | vendorInformation.provider |
| **software**:vendor | vendorInformation.vendor |
| **software**:version | vendorInformation.providerVersion |
| **url**:name | networkConnections.destinationUrl |
| **url**:value | networkConnections.destinationUrl |
| **windows-registry-key**:key | registryKeyStates.key |
| **windows-registry-key**:extensions.windows-registry-value-type.valueData | registryKeyStates.valueData |
| **windows-registry-key**:extensions.windows-registry-value-type.name | registryKeyStates.valueName |
| **windows-registry-key**:extensions.windows-registry-value-type.valueType | registryKeyStates.valueType |
| **windows-registry-key**:values[*].data | registryKeyStates.valueData |
| **windows-registry-key**:values[*].name | registryKeyStates.valueName |
| **windows-registry-key**:values[*].data_type | registryKeyStates.valueType |
| **x-msazure-sentinel**:tenant_id | azureTenantId |
| **x-msazure-sentinel**:subscription_id | azureSubscriptionId |
| **x-msazure-sentinel-alert**:activityGroupName | activityGroupName |
Expand Down Expand Up @@ -148,10 +148,6 @@
| domain-name | value | destinationDomain |
| domain-name | value | domainName |
| <br> | | |
| extensions | windows-registry-value-type.valueData | registryKeyStates |
| extensions | windows-registry-value-type.name | registryKeyStates |
| extensions | windows-registry-value-type.valuetype | registryKeyStates |
| <br> | | |
| file | hashes.SHA-256 | sha256 |
| file | hashes.SHA-1 | sha1 |
| file | hashes.MD5 | md5 |
Expand Down Expand Up @@ -201,6 +197,9 @@
| user-account | account_login | logonId |
| <br> | | |
| windows-registry-key | key | registryKeyStates |
| windows-registry-key | values.data | registryKeyStates |
| windows-registry-key | values.name | registryKeyStates |
| windows-registry-key | values.data_type | registryKeyStates |
| <br> | | |
| x-ibm-finding | dst_application_ref | destinationServiceName |
| x-ibm-finding | createddatetime | createdDateTime |
Expand Down
171 changes: 171 additions & 0 deletions map_validator/validate_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import argparse
import json
import logging


# create logging formatter
logFormatter = logging.Formatter(fmt='%(levelname)s: %(message)s')

# create logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# create console handler
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)

# Add console handler to logger
logger.addHandler(consoleHandler)


def _log(level, mapping, msg):
if mapping:
logger.log(level, '%s in mapping %s', msg, mapping)
else:
logger.log(level, '%s', msg)


def log_warning(mapping, msg):
_log(logging.WARNING, mapping, msg)


def log_error(mapping, msg):
_log(logging.ERROR, mapping, msg)


def get_mapping(to_stix_map):
for _, mappings in to_stix_map.items():
if isinstance(mappings, list):
for mapping in mappings:
if isinstance(mapping, dict):
yield mapping
else:
log_error(mappings, 'Nothing found')
break
elif isinstance(mappings, dict): # and not all(type(v) in (str, bool) for v in mappings.values()):
if 'key' in mappings and isinstance(mappings['key'], str): # and 'object' in mappings:
yield mappings
else:
# Step down into nested mapping
yield from get_mapping(mappings)


# From stix_shifter_utils/stix_translation/src/json_to_stix/json_to_stix_translator.py
# TODO: use pydantic to validate structure?
KNOWN_KEYS = {
'cybox', # bool; is this a SCO property (or observed-data SDO prop)?
'ds_key', # ???
'group', # bool; combine this value into a list
'group_ref', # ???
'key', # str; path-like name of property target
'object', # str; named object to add property to
'references', # str|list[str]; named objects to reference
'transformer', # str; function to apply on value
'unwrap', # bool; ???
'value', # any; constant (literal) value for property
}


REQD_PROPS = {
'first_observed',
'last_observed',
}

RECD_PROPS = {
'number_observed',
}


def ip_types(*args):
return all(arg in ('ipv4-addr', 'ipv6-addr') for arg in args)


def main():
parser = argparse.ArgumentParser('Generate a bundle of STIX observed-data')
parser.add_argument('-l', '--level', metavar='LEVEL', default='warning', type=str)
parser.add_argument('filename')
args = parser.parse_args()

logger.setLevel(args.level.upper())

with open(args.filename, 'r') as fp:
to_stix_map = json.load(fp)

# Track named objects
objects = {}
reffed = {}

# Track observed-data properties
obs_props = set()

for mapping in get_mapping(to_stix_map):
#TODO: make each "check" a function?

# Check cybox flag
cybox = mapping.get('cybox', True)
if not isinstance(cybox, bool): # Note: this could be checked by pydantic
log_error(mapping, '"cybox" is not a boolean')
obj = mapping.get('object')
if not obj and cybox:
log_warning(mapping, 'no "object"')

# Validate key
key = mapping['key']
if not isinstance(key, str):
log_error(mapping, '"key" is not a string')
continue # This is "fatal" for this mapping
otype, _, rest = key.partition('.')
if not rest:
rest, otype = otype, rest
if otype and obj:
prev_otype = objects.get(obj)
if (prev_otype and
prev_otype != otype and
not ip_types(prev_otype, otype) and
'_ref.' not in rest):
log_error(mapping, f'conflicting types for {objects[obj]} {obj}')
else:
objects[obj] = otype
if not otype:
if cybox is not False:
log_error(mapping, 'No type in "key" and "cybox" is not False')
obs_props.add(rest)
if cybox is False and otype:
if '-' in otype:
log_error(mapping, f'"key" type is {otype} but "cybox" is False')
elif rest:
log_warning(mapping, f'dict {otype} as observed-data property')

# Check refs
if '_ref.' in rest:
log_error(mapping, 'invalid reference syntax')
if rest.endswith('_ref'):
# Must reference something
if 'references' not in mapping:
log_error(mapping, f'no "references" for {key}')
else:
ref_objs = mapping['references']
if not isinstance(ref_objs, list):
ref_objs = [ref_objs]
for ref_obj in ref_objs:
reffed[ref_obj] = mapping # Save and check at end of file

# Look for any unknown mapping dict keys
for key in mapping:
if key not in KNOWN_KEYS:
log_warning(mapping, f'unknown param "{key}"')

# Check for undefined reference objects
for ref_obj, mapping in reffed.items():
if ref_obj not in objects:
log_error(mapping, 'unknown "references" object')

for prop in REQD_PROPS - obs_props:
log_error({}, f'nothing mapped to {prop}')

for prop in RECD_PROPS - obs_props:
log_warning({}, f'nothing mapped to {prop}')


if __name__ == '__main__':
main()
10 changes: 10 additions & 0 deletions map_validator/validate_mappings.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Run this from the root of the repo

for to_stix_map in $(find stix_shifter_modules/ -name "*to_stix_map.json")
do
echo -e "${to_stix_map}:"
python3 map_validator/validate_mapping.py $to_stix_map || break
echo
done
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
astroid==2.12.12
autopep8==1.3.4
coverage==6.5.0
debugpy-run
flake8==3.5.0
freezegun==1.2.2
isort==4.3.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def ping_data_source(self):
async def get_search_results(self, query_expression, offset=None, length=None):
endpoint = self.endpoint_start + '/search'
data = {'query': query_expression}
result = await self.client.call_api(endpoint, 'GET', urldata=data)
result = await self.client.call_api(endpoint, 'GET', urldata=data, timeout=self.timeout)
return result

async def delete_search(self, search_id):
Expand Down
2 changes: 2 additions & 0 deletions stix_shifter_modules/alienvault_otx/.coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
omit = tests/*
Empty file.
117 changes: 117 additions & 0 deletions stix_shifter_modules/alienvault_otx/configuration/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"connection": {
"type": {
"id": "OTXQuery_Connector",
"displayName": "AlienVault OTX",
"description": "Query AlienVault OTX for IPs, domains, URLs, or file hashes"
},
"help": {
"default": "www.ibm.com",
"type": "link"
},
"options": {
"type": "fields",
"concurrent": {
"default": 4,
"min": 1,
"max": 100,
"type": "number",
"previous": "connection.maxConcurrentSearches"
},
"result_limit": {
"default": 10000,
"min": 1,
"max": 500000,
"type": "number",
"previous": "connection.resultSizeLimit",
"hidden": true
},
"time_range": {
"default": 5,
"min": 1,
"max": 10000,
"type": "number",
"previous": "connection.timerange",
"nullable": true,
"hidden": true
},
"timeout": {
"default": 30,
"min": 1,
"max": 60,
"type": "number",
"previous": "connection.timeoutLimit"
}
},
"namespace":{
"type": "text",
"default": "9d4bedaf-d351-4f50-930f-f8eb121e5bae",
"hidden": true
},
"host": {
"type": "text",
"default": "",
"hidden": true
},
"port": {
"default": 443,
"type": "number",
"min": 1,
"max": 65535,
"hidden": true
}
},
"configuration": {
"auth": {
"type": "fields",
"key": {
"type": "password"
}
},
"rateLimit": {
"type": "fields",
"rateLimit": {
"default": 10000,
"type": "number",
"hidden": true
},
"rateUnit": {
"type": "text",
"default": "Hour",
"hidden": true
}
},
"cacheDuration": {
"type": "fields",
"cacheDuration": {
"default": 10,
"type": "number",
"hidden": true
},
"unit": {
"default": "Minute",
"type": "text",
"hidden": true
}
},
"dataTypeList": {
"type": "fields",
"ip": {
"type": "checkbox",
"default": true
},
"domain": {
"type": "checkbox",
"default": true
},
"url": {
"type": "checkbox",
"default": true
},
"hash": {
"type": "checkbox",
"default": true
}
}
}
}
Loading

0 comments on commit 8b80cab

Please sign in to comment.