Compare commits

...

39 Commits

Author SHA1 Message Date
Alexandre Dulaunoy 28dcfb6f39
Merge pull request #82 from arcsector/master
Bringing up-to-date with recent PyMISP and Optional Deduplication
2022-06-14 09:44:27 +02:00
George Haraksin 2aa3522cae excepting Exception instead of BaseException 2022-06-14 00:02:15 -07:00
George Haraksin 43a27c83b1 even better logging 2022-06-14 00:01:09 -07:00
George Haraksin 8ec9fc18c5 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-06-16 01:13:11 -07:00
haraksin 67d08c443f try/except on pymisp loading stix failing 2020-06-16 01:12:23 -07:00
George Haraksin f25304c815 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-06-15 19:26:25 -07:00
haraksin e020452a3d invalid syntaxi in except clause 2020-06-15 19:26:07 -07:00
George Haraksin aa7e345e68 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-06-15 19:24:39 -07:00
haraksin 0aaed66540 Checking for MISP existence 2020-06-15 19:24:18 -07:00
George Haraksin 4fd353fbec Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-06-15 19:01:31 -07:00
haraksin 67f9c52def adding try/except for pymisp error 2020-06-15 19:00:47 -07:00
George Haraksin 27e667b2f0 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-06-15 18:53:46 -07:00
George Haraksin 03aa19467e fixing merge conflicts 2020-06-15 18:49:45 -07:00
haraksin e4ab93e954 fixing logging changes 2020-06-15 18:12:24 -07:00
haraksin 6056501ff4 Adding checking if connection to MISP is valid 2020-06-15 18:08:33 -07:00
George Haraksin a850a0051f Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:53:20 -07:00
haraksin 461452f420 Adding log about MISP publish skip 2020-05-14 16:43:01 -07:00
George Haraksin 59fb6f27e8 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:38:47 -07:00
haraksin 5cc5f99c45 Making sure collections returned from manager instance are only the ones we want 2020-05-14 16:38:28 -07:00
George Haraksin 4db2a43e6d Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:33:43 -07:00
haraksin 4d9f63522b Using UUID instead of ID for publish event log 2020-05-14 16:33:15 -07:00
George Haraksin 0303688af3 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:27:12 -07:00
haraksin 310d8145d5 Making sure config can't be switched to unknown if it's false 2020-05-14 16:26:51 -07:00
George Haraksin 0326daf2b1 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:19:16 -07:00
haraksin 9b8ed9ddf9 Adding better logging 2020-05-14 16:18:53 -07:00
George Haraksin ad1834acb2 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 16:15:43 -07:00
haraksin 4a41e963df getting collection names for name lookup 2020-05-14 16:15:23 -07:00
George Haraksin 1a083c7378 Merge branch 'master' of https://github.com/arcsector/MISP-Taxii-Server 2020-05-14 15:55:50 -07:00
haraksin 934bcf1b6a Adding collections and publish args and features. 2020-05-13 19:21:52 -07:00
George Haraksin c28ab6f3af fixing merge conflicts 2020-05-13 15:30:46 -07:00
haraksin 00e70113ad Add src/ to gitignore 2020-05-13 15:29:20 -07:00
George Haraksin f3c583f0f4 adding src/ to gitignure 2020-05-13 15:28:11 -07:00
haraksin 8a20458898 removing gitignore changes 2020-05-13 13:59:56 -07:00
haraksin 823822bbf1 Making dedup optional 2020-05-13 13:49:34 -07:00
haraksin c55f9994c6 Adding deduplication as an optional item 2020-05-13 13:41:12 -07:00
haraksin 277dfcdb97 Dealing with key issue in search
Line 70
2020-05-06 21:05:36 -07:00
haraksin b50a60485f adding Loader to push_published_to_taxii
adding local-server default yaml and remote-servers default yaml
2020-05-06 17:28:04 -07:00
arcsector 53309e3477
Include Loader in hooks.py 2020-05-06 17:00:04 -07:00
arcsector c86e4940af
Including pyaml's Loader to suppress warnings
See these docs for info: https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation
2020-05-06 16:58:21 -07:00
7 changed files with 177 additions and 36 deletions

2
.gitignore vendored
View File

@ -6,3 +6,5 @@ config.yaml
__pycache__
build
dist
src
vscode/

View File

@ -29,6 +29,11 @@ zmq:
misp:
url: "http://localhost"
api: KEY
dedup: true
collections:
- my_collection
- my_collection2
publish: false
taxii:
auth:

View File

@ -0,0 +1,12 @@
host: localhost
port: 9000
discovery_path: /services/discovery
inbox_path: /services/inbox
use_https: False
taxii_version: '1.1'
headers:
auth:
username: test
password: test
collections:
- collection

View File

@ -0,0 +1,18 @@
- name: 'default'
host: localhost
port: 9000
discovery_path:
use_https: False
taxii_version: '1.1'
headers:
auth:
username:
password:
cacert_path:
cert_file:
key_file:
key_password:
jwt_auth_url:
verify_ssl: True
collections:
- collection

View File

@ -9,43 +9,84 @@ import pymisp
import tempfile
import logging
from pyaml import yaml
from yaml import Loader
from io import StringIO
from requests.exceptions import ConnectionError
from pymisp.exceptions import PyMISPError
import warnings
warnings.filterwarnings("ignore")
log = logging.getLogger("__main__")
TOTAL_ATTRIBUTES_SENT = 0
TOTAL_ATTRIBUTES_ANALYZED = 0
logging_level = logging.INFO
log = logging.getLogger("misp_taxii_server")
log.setLevel(logging_level)
handler = logging.StreamHandler()
handler.setLevel(logging_level)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
if log.handlers:
log.handlers = []
log.addHandler(handler)
from opentaxii.signals import (
CONTENT_BLOCK_CREATED, INBOX_MESSAGE_CREATED
)
def env_config_helper(env_name):
if env_name in os.environ:
if env_name == "MISP_COLLECTIONS":
name = os.environ[env_name]
return name.split(',')
return os.environ[env_name]
else:
log.error("Missing env setting {0}. Set OPENTAXII_CONFIG or {0}.".format(env_name))
return "UNKNOWN"
def yaml_config_helper(config_name, CONFIG):
if config_name in CONFIG["misp"]:
if not CONFIG["misp"][config_name] and CONFIG["misp"][config_name] != False:
CONFIG["misp"][config_name] = "UNKNOWN"
else:
CONFIG["misp"][config_name] = "UNKNOWN"
return CONFIG
## CONFIG
if "OPENTAXII_CONFIG" in os.environ:
print("Using config from {}".format(os.environ["OPENTAXII_CONFIG"]))
CONFIG = yaml.load(open(os.environ["OPENTAXII_CONFIG"], "r"))
log.debug("Using config from {}".format(os.environ["OPENTAXII_CONFIG"]))
CONFIG = yaml.load(open(os.environ["OPENTAXII_CONFIG"], "r"), Loader=Loader)
# validate dedup and collections and publish
CONFIG = yaml_config_helper("dedup", CONFIG)
CONFIG = yaml_config_helper("collections", CONFIG)
CONFIG = yaml_config_helper("publish", CONFIG)
else:
print("Trying to use env variables...")
if "MISP_URL" in os.environ:
misp_url = os.environ["MISP_URL"]
else:
print("Unkown misp URL. Set OPENTAXII_CONFIG or MISP_URL.")
misp_url = "UNKNOWN"
if "MISP_API" in os.environ:
misp_api = os.environ["MISP_API"]
else:
print("Unknown misp API key. Set OPENTAXII_CONFIG or MISP_API.")
misp_api = "UNKNOWN"
log.debug("Trying to use env variables...")
misp_url = env_config_helper("MISP_URL")
misp_api = env_config_helper("MISP_API")
misp_dedup = env_config_helper("MISP_DEDUP")
misp_collections = env_config_helper("MISP_COLLECTIONS")
misp_publish = env_config_helper("MISP_PUBLISH")
CONFIG = {
"misp" : {
"url" : misp_url,
"api" : misp_api
"api" : misp_api,
"dedup" : misp_dedup,
"collections": misp_collections
}
}
MISP = pymisp.PyMISP(
MISP = ''
try:
MISP = pymisp.PyMISP(
CONFIG["misp"]["url"],
CONFIG["misp"]["api"],
ssl = CONFIG["misp"].get("verifySSL", True)
)
except PyMISPError:
log.error("Cannot connect to MISP; please ensure that MISP is up and running at {}. Skipping MISP upload.".format(CONFIG['misp']['url']))
def post_stix(manager, content_block, collection_ids, service_id):
'''
@ -53,34 +94,95 @@ def post_stix(manager, content_block, collection_ids, service_id):
Will convert it to a MISPEvent and push to the server
'''
# make sure collections, if specified are supposed to be sent to
if CONFIG["misp"]["collections"] != "UNKNOWN" or CONFIG["misp"]["collections"] == False:
log.debug("Using collections")
should_send_to_misp = False
collection_names = [collection.name for collection in manager.get_collections(service_id) if collection.id in collection_ids]
for collection in CONFIG["misp"]["collections"]:
if collection in collection_names or collection in collection_ids:
log.debug("Collection specified matches push collection: {}".format(collection))
should_send_to_misp = True
break
if should_send_to_misp == False:
log.debug('''No collections match misp.collections; aborting MISP extraction.''')
log.debug("Collection ids whitelisted: {}".format(CONFIG["misp"]["collections"]))
log.debug("Collection ids sent to: {}".format(collection_ids))
log.debug('''Collection names sent to: {}'''.format(collection_names))
return None
# Load the package
log.info("Posting STIX...")
log.debug("Posting STIX...")
block = content_block.content
if isinstance(block, bytes):
block = block.decode()
package = pymisp.tools.stix.load_stix(StringIO(block))
log.info("STIX loaded succesfully.")
try:
package = pymisp.tools.stix.load_stix(StringIO(block))
except Exception:
log.error('Could not load stix into MISP format; exiting.')
return 0
log.debug("STIX loaded succesfully.")
values = [x.value for x in package.attributes]
log.info("Extracted %s", values)
for attrib in values:
log.info("Checking for existence of %s", attrib)
search = MISP.search("attributes", values=str(attrib))
if search["response"]["Attribute"] != []:
# This means we have it!
log.info("%s is a duplicate, we'll ignore it.", attrib)
package.attributes.pop([x.value for x in package.attributes].index(attrib))
else:
log.info("%s is unique, we'll keep it", attrib)
log.debug("Extracted %s", values)
TOTAL_ATTRIBUTES_ANALYZED = len(values)
# if deduping is enabled, start deduping
if (
CONFIG["misp"]["dedup"] or
CONFIG["misp"]["dedup"] == "True" or
CONFIG["misp"]["dedup"] == "UNKNOWN"
):
for attrib in values:
log.debug("Checking for existence of %s", attrib)
search = ''
if MISP:
search = MISP.search("attributes", values=str(attrib))
else:
return 0
if 'response' in search:
if search["response"]["Attribute"] != []:
# This means we have it!
log.debug("%s is a duplicate, we'll ignore it.", attrib)
package.attributes.pop([x.value for x in package.attributes].index(attrib))
else:
log.debug("%s is unique, we'll keep it", attrib)
elif 'Attribute' in search:
if search["Attribute"] != []:
# This means we have it!
log.debug("%s is a duplicate, we'll ignore it.", attrib)
package.attributes.pop([x.value for x in package.attributes].index(attrib))
else:
log.debug("%s is unique, we'll keep it", attrib)
else:
log.error("Something went wrong with search, and it doesn't have an 'attribute' or a 'response' key: {}".format(search.keys()))
else:
log.debug("Skipping deduplication")
# Push the event to MISP
# TODO: There's probably a proper method to do this rather than json_full
# But I don't wanna read docs
if (len(package.attributes) > 0):
log.info("Uploading event to MISP with attributes %s", [x.value for x in package.attributes])
MISP.add_event(package)
log.debug("Uploading event to MISP with attributes %s", [x.value for x in package.attributes])
event = ''
try:
if MISP:
event = MISP.add_event(package)
TOTAL_ATTRIBUTES_SENT = len(package.attributes)
except ConnectionError:
log.error("Cannot push to MISP; please ensure that MISP is up and running at {}. Skipping MISP upload.".format(CONFIG['misp']['url']))
if (
CONFIG["misp"]["publish"] == True or
CONFIG["misp"]["publish"] == "True"
):
log.info("Publishing event to MISP with ID {}".format(event.get('uuid')))
if MISP:
MISP.publish(event)
else:
log.debug("Skipping MISP event publishing")
else:
log.info("No attributes, not bothering.")
log.debug("total_attributes_analyzed={}, total_attributes_sent={}".format(TOTAL_ATTRIBUTES_ANALYZED, TOTAL_ATTRIBUTES_SENT))
# Make TAXII call our push function whenever it gets new data
CONTENT_BLOCK_CREATED.connect(post_stix)

View File

@ -4,6 +4,7 @@ import sys
import json
import pymisp
from pyaml import yaml
from yaml import Loader
from cabby import create_client
from misp_stix_converter.converters import lint_roller
import logging
@ -20,7 +21,7 @@ log.setLevel(logging.DEBUG)
log.info("Starting...")
# Try to load in config
if "OPENTAXII_CONFIG" in os.environ:
config = yaml.load(open(os.environ["OPENTAXII_CONFIG"], "r"))
config = yaml.load(open(os.environ["OPENTAXII_CONFIG"], "r"), Loader=Loader)
else:
print("OPENTAXII CONFIG NOT EXPORTED")
sys.exit()

View File

@ -2,6 +2,7 @@
from cabby import create_client
from pyaml import yaml
from yaml import Loader
import pytz
import argparse
import os
@ -51,14 +52,14 @@ config_file = "{}/remote-servers.yml".format(
log.debug("Opening config file %s", config_file)
with open(config_file, "r") as f:
config = yaml.load(f.read())
config = yaml.load(f.read(), Loader=Loader)
log.debug("Config read %s", config)
# Read in the local server configuration
local_config = "{}/local-server.yml".format(os.path.expanduser(args.configdir))
log.debug("Reading local server config")
with open(local_config, "r") as f:
local_config = yaml.load(f.read())
local_config = yaml.load(f.read(), Loader=Loader)
# Attempt to make contact with the local server
log.info("Connecting to local server...")