misp-modules 2.4.196__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- misp_modules/__init__.py +379 -0
- misp_modules/helpers/__init__.py +1 -0
- misp_modules/helpers/cache.py +84 -0
- misp_modules/lib/__init__.py +4 -0
- misp_modules/lib/_vmray/__init__.py +0 -0
- misp_modules/lib/_vmray/parser.py +1417 -0
- misp_modules/lib/_vmray/rest_api.py +148 -0
- misp_modules/lib/cof2misp/LICENSE-2.0.txt +202 -0
- misp_modules/lib/cof2misp/__init__.py +0 -0
- misp_modules/lib/cof2misp/cof.py +165 -0
- misp_modules/lib/joe_mapping.py +114 -0
- misp_modules/lib/joe_parser.py +573 -0
- misp_modules/lib/lastline_api.py +841 -0
- misp_modules/lib/qintel_helper.py +263 -0
- misp_modules/lib/stix2misp.py +2080 -0
- misp_modules/lib/stix2misp_mapping.py +460 -0
- misp_modules/lib/synonymsToTagNames.json +1 -0
- misp_modules/lib/vt_graph_parser/__init__.py +8 -0
- misp_modules/lib/vt_graph_parser/errors.py +20 -0
- misp_modules/lib/vt_graph_parser/helpers/__init__.py +7 -0
- misp_modules/lib/vt_graph_parser/helpers/parsers.py +88 -0
- misp_modules/lib/vt_graph_parser/helpers/rules.py +304 -0
- misp_modules/lib/vt_graph_parser/helpers/wrappers.py +58 -0
- misp_modules/lib/vt_graph_parser/importers/__init__.py +7 -0
- misp_modules/lib/vt_graph_parser/importers/base.py +98 -0
- misp_modules/lib/vt_graph_parser/importers/pymisp_response.py +73 -0
- misp_modules/modules/__init__.py +4 -0
- misp_modules/modules/action_mod/__init__.py +1 -0
- misp_modules/modules/action_mod/_utils/__init__.py +1 -0
- misp_modules/modules/action_mod/_utils/utils.py +70 -0
- misp_modules/modules/action_mod/mattermost.py +113 -0
- misp_modules/modules/action_mod/slack.py +96 -0
- misp_modules/modules/action_mod/testaction.py +68 -0
- misp_modules/modules/expansion/__init__.py +36 -0
- misp_modules/modules/expansion/_dnsdb_query/COPYRIGHT +27 -0
- misp_modules/modules/expansion/_dnsdb_query/LICENSE +202 -0
- misp_modules/modules/expansion/_dnsdb_query/README.md +162 -0
- misp_modules/modules/expansion/_dnsdb_query/__init__.py +0 -0
- misp_modules/modules/expansion/_dnsdb_query/dnsdb_query.py +327 -0
- misp_modules/modules/expansion/_ransomcoindb/__init__.py +0 -0
- misp_modules/modules/expansion/_ransomcoindb/ransomcoindb.py +96 -0
- misp_modules/modules/expansion/_vulnerability_parser/__init__.py +0 -0
- misp_modules/modules/expansion/_vulnerability_parser/vulnerability_parser.py +118 -0
- misp_modules/modules/expansion/abuseipdb.py +146 -0
- misp_modules/modules/expansion/apiosintds.py +365 -0
- misp_modules/modules/expansion/apivoid.py +133 -0
- misp_modules/modules/expansion/assemblyline_query.py +179 -0
- misp_modules/modules/expansion/assemblyline_submit.py +100 -0
- misp_modules/modules/expansion/backscatter_io.py +84 -0
- misp_modules/modules/expansion/btc_scam_check.py +54 -0
- misp_modules/modules/expansion/btc_steroids.py +238 -0
- misp_modules/modules/expansion/censys_enrich.py +287 -0
- misp_modules/modules/expansion/circl_passivedns.py +85 -0
- misp_modules/modules/expansion/circl_passivessl.py +113 -0
- misp_modules/modules/expansion/clamav.py +129 -0
- misp_modules/modules/expansion/cluster25_expand.py +239 -0
- misp_modules/modules/expansion/countrycode.py +69 -0
- misp_modules/modules/expansion/cpe.py +140 -0
- misp_modules/modules/expansion/crowdsec.py +235 -0
- misp_modules/modules/expansion/crowdstrike_falcon.py +148 -0
- misp_modules/modules/expansion/cuckoo_submit.py +161 -0
- misp_modules/modules/expansion/cve.py +57 -0
- misp_modules/modules/expansion/cve_advanced.py +185 -0
- misp_modules/modules/expansion/cytomic_orion.py +196 -0
- misp_modules/modules/expansion/dbl_spamhaus.py +78 -0
- misp_modules/modules/expansion/dns.py +71 -0
- misp_modules/modules/expansion/docx_enrich.py +71 -0
- misp_modules/modules/expansion/domaintools.py +290 -0
- misp_modules/modules/expansion/eql.py +91 -0
- misp_modules/modules/expansion/eupi.py +86 -0
- misp_modules/modules/expansion/extract_url_components.py +83 -0
- misp_modules/modules/expansion/farsight_passivedns.py +243 -0
- misp_modules/modules/expansion/geoip_asn.py +75 -0
- misp_modules/modules/expansion/geoip_city.py +75 -0
- misp_modules/modules/expansion/geoip_country.py +73 -0
- misp_modules/modules/expansion/google_safe_browsing.py +86 -0
- misp_modules/modules/expansion/google_search.py +57 -0
- misp_modules/modules/expansion/google_threat_intelligence.py +453 -0
- misp_modules/modules/expansion/greynoise.py +346 -0
- misp_modules/modules/expansion/hashdd.py +53 -0
- misp_modules/modules/expansion/hashlookup.py +118 -0
- misp_modules/modules/expansion/hibp.py +62 -0
- misp_modules/modules/expansion/html_to_markdown.py +63 -0
- misp_modules/modules/expansion/hyasinsight.py +881 -0
- misp_modules/modules/expansion/intel471.py +73 -0
- misp_modules/modules/expansion/intelmq_eventdb.py.experimental +67 -0
- misp_modules/modules/expansion/ip2locationio.py +90 -0
- misp_modules/modules/expansion/ipasn.py +70 -0
- misp_modules/modules/expansion/ipinfo.py +112 -0
- misp_modules/modules/expansion/ipqs_fraud_and_risk_scoring.py +633 -0
- misp_modules/modules/expansion/iprep.py +98 -0
- misp_modules/modules/expansion/jinja_template_rendering.py +54 -0
- misp_modules/modules/expansion/joesandbox_query.py +91 -0
- misp_modules/modules/expansion/joesandbox_submit.py +147 -0
- misp_modules/modules/expansion/lastline_query.py +148 -0
- misp_modules/modules/expansion/lastline_submit.py +180 -0
- misp_modules/modules/expansion/macaddress_io.py +130 -0
- misp_modules/modules/expansion/macvendors.py +55 -0
- misp_modules/modules/expansion/malshare_upload.py +107 -0
- misp_modules/modules/expansion/malwarebazaar.py +67 -0
- misp_modules/modules/expansion/mcafee_insights_enrich.py +249 -0
- misp_modules/modules/expansion/mmdb_lookup.py +138 -0
- misp_modules/modules/expansion/module.py.skeleton +44 -0
- misp_modules/modules/expansion/mwdb.py +152 -0
- misp_modules/modules/expansion/ocr_enrich.py +74 -0
- misp_modules/modules/expansion/ods_enrich.py +71 -0
- misp_modules/modules/expansion/odt_enrich.py +61 -0
- misp_modules/modules/expansion/onyphe.py +243 -0
- misp_modules/modules/expansion/onyphe_full.py +387 -0
- misp_modules/modules/expansion/otx.py +167 -0
- misp_modules/modules/expansion/passive_ssh.py +150 -0
- misp_modules/modules/expansion/passivetotal.py +358 -0
- misp_modules/modules/expansion/pdf_enrich.py +58 -0
- misp_modules/modules/expansion/pptx_enrich.py +65 -0
- misp_modules/modules/expansion/qintel_qsentry.py +229 -0
- misp_modules/modules/expansion/qrcode.py +99 -0
- misp_modules/modules/expansion/ransomcoindb.py +82 -0
- misp_modules/modules/expansion/rbl.py +126 -0
- misp_modules/modules/expansion/recordedfuture.py +544 -0
- misp_modules/modules/expansion/reversedns.py +77 -0
- misp_modules/modules/expansion/securitytrails.py +571 -0
- misp_modules/modules/expansion/shodan.py +244 -0
- misp_modules/modules/expansion/sigma_queries.py +61 -0
- misp_modules/modules/expansion/sigma_syntax_validator.py +49 -0
- misp_modules/modules/expansion/sigmf_expand.py +303 -0
- misp_modules/modules/expansion/socialscan.py +108 -0
- misp_modules/modules/expansion/sophoslabs_intelix.py +146 -0
- misp_modules/modules/expansion/sourcecache.py +57 -0
- misp_modules/modules/expansion/stairwell.py +156 -0
- misp_modules/modules/expansion/stix2_pattern_syntax_validator.py +56 -0
- misp_modules/modules/expansion/threatcrowd.py +170 -0
- misp_modules/modules/expansion/threatfox.py +75 -0
- misp_modules/modules/expansion/threatminer.py +152 -0
- misp_modules/modules/expansion/triage_submit.py +119 -0
- misp_modules/modules/expansion/trustar_enrich.py +235 -0
- misp_modules/modules/expansion/urlhaus.py +164 -0
- misp_modules/modules/expansion/urlscan.py +269 -0
- misp_modules/modules/expansion/variotdbs.py +133 -0
- misp_modules/modules/expansion/virustotal.py +311 -0
- misp_modules/modules/expansion/virustotal_public.py +272 -0
- misp_modules/modules/expansion/virustotal_upload.py +91 -0
- misp_modules/modules/expansion/vmray_submit.py +161 -0
- misp_modules/modules/expansion/vmware_nsx.py +628 -0
- misp_modules/modules/expansion/vulndb.py +292 -0
- misp_modules/modules/expansion/vulnerability_lookup.py +324 -0
- misp_modules/modules/expansion/vulners.py +81 -0
- misp_modules/modules/expansion/vysion.py +221 -0
- misp_modules/modules/expansion/whois.py +72 -0
- misp_modules/modules/expansion/whoisfreaks.py +232 -0
- misp_modules/modules/expansion/wiki.py +58 -0
- misp_modules/modules/expansion/xforceexchange.py +189 -0
- misp_modules/modules/expansion/xlsx_enrich.py +63 -0
- misp_modules/modules/expansion/yara_query.py +70 -0
- misp_modules/modules/expansion/yara_syntax_validator.py +49 -0
- misp_modules/modules/expansion/yeti.py +196 -0
- misp_modules/modules/export_mod/__init__.py +3 -0
- misp_modules/modules/export_mod/cef_export.py +93 -0
- misp_modules/modules/export_mod/cisco_firesight_manager_ACL_rule_export.py +150 -0
- misp_modules/modules/export_mod/defender_endpoint_export.py +141 -0
- misp_modules/modules/export_mod/goamlexport.py +255 -0
- misp_modules/modules/export_mod/liteexport.py +97 -0
- misp_modules/modules/export_mod/mass_eql_export.py +106 -0
- misp_modules/modules/export_mod/nexthinkexport.py +131 -0
- misp_modules/modules/export_mod/osqueryexport.py +125 -0
- misp_modules/modules/export_mod/pdfexport.py +107 -0
- misp_modules/modules/export_mod/testexport.py +73 -0
- misp_modules/modules/export_mod/threatStream_misp_export.py +114 -0
- misp_modules/modules/export_mod/threat_connect_export.py +125 -0
- misp_modules/modules/export_mod/virustotal_collections.py +141 -0
- misp_modules/modules/export_mod/vt_graph.py +120 -0
- misp_modules/modules/export_mod/yara_export.py +290 -0
- misp_modules/modules/import_mod/__init__.py +22 -0
- misp_modules/modules/import_mod/cof2misp.py +264 -0
- misp_modules/modules/import_mod/csvimport.py +319 -0
- misp_modules/modules/import_mod/cuckooimport.py +749 -0
- misp_modules/modules/import_mod/email_import.py +294 -0
- misp_modules/modules/import_mod/goamlimport.py +188 -0
- misp_modules/modules/import_mod/import_blueprint.py +93 -0
- misp_modules/modules/import_mod/joe_import.py +74 -0
- misp_modules/modules/import_mod/lastline_import.py +160 -0
- misp_modules/modules/import_mod/mispjson.py +73 -0
- misp_modules/modules/import_mod/ocr.py +122 -0
- misp_modules/modules/import_mod/openiocimport.py +99 -0
- misp_modules/modules/import_mod/taxii21.py +383 -0
- misp_modules/modules/import_mod/testimport.py +73 -0
- misp_modules/modules/import_mod/threatanalyzer_import.py +552 -0
- misp_modules/modules/import_mod/url_import.py +97 -0
- misp_modules/modules/import_mod/vmray_import.py +96 -0
- misp_modules/modules/import_mod/vmray_summary_json_import.py +87 -0
- misp_modules-2.4.196.dist-info/LICENSE +661 -0
- misp_modules-2.4.196.dist-info/METADATA +281 -0
- misp_modules-2.4.196.dist-info/RECORD +194 -0
- misp_modules-2.4.196.dist-info/WHEEL +4 -0
- misp_modules-2.4.196.dist-info/entry_points.txt +3 -0
misp_modules/__init__.py
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Core MISP expansion modules loader and web service
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2016 Alexandre Dulaunoy
|
|
6
|
+
# Copyright (C) 2016 CIRCL - Computer Incident Response Center Luxembourg
|
|
7
|
+
#
|
|
8
|
+
# This program is free software: you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU Affero General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import signal
|
|
23
|
+
import sys
|
|
24
|
+
import importlib
|
|
25
|
+
import logging
|
|
26
|
+
import fnmatch
|
|
27
|
+
import argparse
|
|
28
|
+
import re
|
|
29
|
+
import datetime
|
|
30
|
+
import psutil
|
|
31
|
+
import pkgutil
|
|
32
|
+
import platform
|
|
33
|
+
import typing
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
import orjson as json
|
|
37
|
+
except ImportError:
|
|
38
|
+
import json
|
|
39
|
+
|
|
40
|
+
import tornado.web
|
|
41
|
+
import tornado.process
|
|
42
|
+
from tornado.ioloop import IOLoop
|
|
43
|
+
from tornado.concurrent import run_on_executor
|
|
44
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
45
|
+
from pymisp import pymisp_json_default
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
import warnings
|
|
49
|
+
warnings.filterwarnings("ignore", category=SyntaxWarning)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
LIBFAUP_PATHS = [
|
|
53
|
+
"/usr/local/lib/",
|
|
54
|
+
"/usr/lib/",
|
|
55
|
+
"/opt/local/lib/",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
ARCH_TO_EXTENSION = {
|
|
59
|
+
"linux": "so",
|
|
60
|
+
"darwin": "dylib",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _get_libfaup_path(lib_path: str) -> str:
|
|
65
|
+
extension = ARCH_TO_EXTENSION.get(platform.system().lower(), "lib")
|
|
66
|
+
return f"{lib_path.rstrip('/')}/libfaupl.{extension}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _replace_libfaup_path(module_path: str, libfaup_path: str) -> None:
|
|
70
|
+
with open(module_path, "r") as f:
|
|
71
|
+
file_data = f.read()
|
|
72
|
+
file_data = re.sub(r"cdll.LoadLibrary\(.*\)", f"cdll.LoadLibrary(\"{libfaup_path}\")", file_data)
|
|
73
|
+
with open(module_path, "w") as f:
|
|
74
|
+
f.write(file_data)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _try_pyfaup_import(lib_path: typing.Optional[str]) -> None:
|
|
78
|
+
package = pkgutil.get_loader("pyfaup")
|
|
79
|
+
if not package:
|
|
80
|
+
return
|
|
81
|
+
if lib_path:
|
|
82
|
+
_replace_libfaup_path(package.path, _get_libfaup_path(lib_path))
|
|
83
|
+
importlib.import_module("pyfaup")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
for lib_path in [None, *LIBFAUP_PATHS]:
|
|
87
|
+
try:
|
|
88
|
+
_try_pyfaup_import(lib_path)
|
|
89
|
+
break
|
|
90
|
+
except OSError:
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
from .modules import * # noqa
|
|
95
|
+
HAS_PACKAGE_MODULES = True
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logging.exception(e)
|
|
98
|
+
HAS_PACKAGE_MODULES = False
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
from .helpers import * # noqa
|
|
102
|
+
HAS_PACKAGE_HELPERS = True
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logging.exception(e)
|
|
105
|
+
HAS_PACKAGE_HELPERS = False
|
|
106
|
+
|
|
107
|
+
log = logging.getLogger('misp-modules')
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def handle_signal(sig, frame):
|
|
111
|
+
IOLoop.instance().add_callback_from_signal(IOLoop.instance().stop)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def init_logger(debug=False):
|
|
115
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
116
|
+
handler = logging.StreamHandler()
|
|
117
|
+
handler.setFormatter(formatter)
|
|
118
|
+
|
|
119
|
+
# Enable access logs
|
|
120
|
+
access_log = logging.getLogger('tornado.access')
|
|
121
|
+
access_log.propagate = False
|
|
122
|
+
access_log.setLevel(logging.INFO)
|
|
123
|
+
access_log.addHandler(handler)
|
|
124
|
+
|
|
125
|
+
# Set application log
|
|
126
|
+
log.addHandler(handler)
|
|
127
|
+
log.propagate = False
|
|
128
|
+
log.setLevel(logging.DEBUG if debug else logging.INFO)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def load_helpers(helpersdir):
|
|
132
|
+
sys.path.append(helpersdir)
|
|
133
|
+
hhandlers = {}
|
|
134
|
+
helpers = []
|
|
135
|
+
for root, dirnames, filenames in os.walk(helpersdir):
|
|
136
|
+
if os.path.basename(root) == '__pycache__':
|
|
137
|
+
continue
|
|
138
|
+
if re.match(r'^\.', os.path.basename(root)):
|
|
139
|
+
continue
|
|
140
|
+
for filename in fnmatch.filter(filenames, '*.py'):
|
|
141
|
+
if filename == '__init__.py':
|
|
142
|
+
continue
|
|
143
|
+
helpername = filename.split(".")[0]
|
|
144
|
+
hhandlers[helpername] = importlib.import_module(helpername)
|
|
145
|
+
selftest = hhandlers[helpername].selftest()
|
|
146
|
+
if selftest is None:
|
|
147
|
+
helpers.append(helpername)
|
|
148
|
+
log.info(f'Helpers loaded {filename}')
|
|
149
|
+
else:
|
|
150
|
+
log.warning(f'Helpers failed {filename} due to {selftest}')
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def load_package_helpers():
|
|
154
|
+
if not HAS_PACKAGE_HELPERS:
|
|
155
|
+
log.error('Unable to load MISP helpers from package.')
|
|
156
|
+
sys.exit(1)
|
|
157
|
+
mhandlers = {}
|
|
158
|
+
helpers = []
|
|
159
|
+
for path, helper in sys.modules.items():
|
|
160
|
+
if not path.startswith('misp_modules.helpers.'):
|
|
161
|
+
continue
|
|
162
|
+
helper_name = path.replace('misp_modules.helpers.', '')
|
|
163
|
+
mhandlers[helper_name] = helper
|
|
164
|
+
selftest = mhandlers[helper_name].selftest()
|
|
165
|
+
if selftest is None:
|
|
166
|
+
helpers.append(helper_name)
|
|
167
|
+
log.info(f'Helper loaded {helper_name}')
|
|
168
|
+
else:
|
|
169
|
+
log.warning(f'Helpers failed {helper_name} due to {selftest}')
|
|
170
|
+
return mhandlers, helpers
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def load_modules(mod_dir):
|
|
174
|
+
sys.path.append(mod_dir)
|
|
175
|
+
mhandlers = {}
|
|
176
|
+
modules = []
|
|
177
|
+
for root, dirnames, filenames in os.walk(mod_dir):
|
|
178
|
+
if os.path.basename(root) == '__pycache__':
|
|
179
|
+
continue
|
|
180
|
+
if os.path.basename(root).startswith("."):
|
|
181
|
+
continue
|
|
182
|
+
for filename in fnmatch.filter(filenames, '*.py'):
|
|
183
|
+
if root.split('/')[-1].startswith('_'):
|
|
184
|
+
continue
|
|
185
|
+
if filename == '__init__.py':
|
|
186
|
+
continue
|
|
187
|
+
module_name = filename.split(".")[0]
|
|
188
|
+
module_type = os.path.split(mod_dir)[1]
|
|
189
|
+
try:
|
|
190
|
+
mhandlers[module_name] = importlib.import_module(os.path.basename(root) + '.' + module_name)
|
|
191
|
+
except Exception as e:
|
|
192
|
+
log.warning(f'MISP modules {module_name} failed due to {e}')
|
|
193
|
+
continue
|
|
194
|
+
modules.append(module_name)
|
|
195
|
+
log.info(f'MISP modules {module_name} imported')
|
|
196
|
+
mhandlers['type:' + module_name] = module_type
|
|
197
|
+
return mhandlers, modules
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def load_package_modules():
|
|
201
|
+
if not HAS_PACKAGE_MODULES:
|
|
202
|
+
log.error('Unable to load MISP modules from package.')
|
|
203
|
+
sys.exit(1)
|
|
204
|
+
mhandlers = {}
|
|
205
|
+
modules = []
|
|
206
|
+
for path, module in sys.modules.items():
|
|
207
|
+
r = re.findall(r"misp_modules[.]modules[.](\w+)[.]([^_]\w+)", path)
|
|
208
|
+
if r and len(r[0]) == 2:
|
|
209
|
+
module_type, module_name = r[0]
|
|
210
|
+
mhandlers[module_name] = module
|
|
211
|
+
modules.append(module_name)
|
|
212
|
+
log.info(f'MISP modules {module_name} imported')
|
|
213
|
+
mhandlers['type:' + module_name] = module_type
|
|
214
|
+
return mhandlers, modules
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Healthcheck(tornado.web.RequestHandler):
|
|
218
|
+
def get(self):
|
|
219
|
+
self.write(b'{"status": true}')
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class ListModules(tornado.web.RequestHandler):
|
|
223
|
+
global loaded_modules
|
|
224
|
+
global mhandlers
|
|
225
|
+
|
|
226
|
+
_cached_json = None
|
|
227
|
+
|
|
228
|
+
def get(self):
|
|
229
|
+
if not self._cached_json:
|
|
230
|
+
ret = []
|
|
231
|
+
for module_name in loaded_modules:
|
|
232
|
+
ret.append({
|
|
233
|
+
'name': module_name,
|
|
234
|
+
'type': mhandlers['type:' + module_name],
|
|
235
|
+
'mispattributes': mhandlers[module_name].introspection(),
|
|
236
|
+
'meta': mhandlers[module_name].version()
|
|
237
|
+
})
|
|
238
|
+
self._cached_json = json.dumps(ret)
|
|
239
|
+
|
|
240
|
+
log.debug('MISP ListModules request')
|
|
241
|
+
self.write(self._cached_json)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class QueryModule(tornado.web.RequestHandler):
|
|
245
|
+
|
|
246
|
+
# Default value in Python 3.5
|
|
247
|
+
# https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor
|
|
248
|
+
nb_threads = tornado.process.cpu_count() * 5
|
|
249
|
+
executor = ThreadPoolExecutor(nb_threads)
|
|
250
|
+
|
|
251
|
+
@run_on_executor
|
|
252
|
+
def run_request(self, module_name, json_payload, dict_payload):
|
|
253
|
+
log.debug('MISP QueryModule %s request %s', module_name, json_payload)
|
|
254
|
+
module = mhandlers[module_name]
|
|
255
|
+
if getattr(module, "dict_handler", None):
|
|
256
|
+
# New method that avoids double JSON decoding, new modules should define dict_handler
|
|
257
|
+
response = module.dict_handler(request=dict_payload)
|
|
258
|
+
else:
|
|
259
|
+
response = module.handler(q=json_payload)
|
|
260
|
+
return json.dumps(response, default=pymisp_json_default)
|
|
261
|
+
|
|
262
|
+
@tornado.gen.coroutine
|
|
263
|
+
def post(self):
|
|
264
|
+
try:
|
|
265
|
+
json_payload = self.request.body
|
|
266
|
+
dict_payload = json.loads(json_payload)
|
|
267
|
+
if dict_payload.get('timeout'):
|
|
268
|
+
timeout = datetime.timedelta(seconds=int(dict_payload.get('timeout')))
|
|
269
|
+
else:
|
|
270
|
+
timeout = datetime.timedelta(seconds=300)
|
|
271
|
+
future = self.run_request(dict_payload['module'], json_payload, dict_payload)
|
|
272
|
+
response = yield tornado.gen.with_timeout(timeout, future)
|
|
273
|
+
self.write(response)
|
|
274
|
+
except tornado.gen.TimeoutError:
|
|
275
|
+
log.warning('Timeout on {}'.format(dict_payload['module']))
|
|
276
|
+
self.write(json.dumps({'error': 'Timeout.'}))
|
|
277
|
+
except Exception:
|
|
278
|
+
self.write(json.dumps({'error': 'Something went wrong, look in the server logs for details'}))
|
|
279
|
+
log.exception('Something went wrong when processing query request')
|
|
280
|
+
finally:
|
|
281
|
+
self.finish()
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _launch_from_current_dir():
|
|
285
|
+
log.info('Launch MISP modules server from current directory.')
|
|
286
|
+
os.chdir(os.path.dirname(__file__))
|
|
287
|
+
modulesdir = 'modules'
|
|
288
|
+
helpersdir = 'helpers'
|
|
289
|
+
load_helpers(helpersdir=helpersdir)
|
|
290
|
+
return load_modules(modulesdir)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def main():
|
|
294
|
+
global mhandlers
|
|
295
|
+
global loaded_modules
|
|
296
|
+
signal.signal(signal.SIGINT, handle_signal)
|
|
297
|
+
signal.signal(signal.SIGTERM, handle_signal)
|
|
298
|
+
|
|
299
|
+
arg_parser = argparse.ArgumentParser(description='misp-modules server', formatter_class=argparse.RawTextHelpFormatter)
|
|
300
|
+
arg_parser.add_argument('-t', '--test', default=False, action='store_true', help='Test mode')
|
|
301
|
+
arg_parser.add_argument('-s', '--system', default=False, action='store_true', help='Run a system install (package installed via pip)')
|
|
302
|
+
arg_parser.add_argument('-d', '--debug', default=False, action='store_true', help='Enable debugging')
|
|
303
|
+
arg_parser.add_argument('-p', '--port', default=6666, help='misp-modules TCP port (default 6666)')
|
|
304
|
+
arg_parser.add_argument('-l', '--listen', default='localhost', help='misp-modules listen address (default localhost)')
|
|
305
|
+
arg_parser.add_argument('-m', default=[], action='append', help='Register a custom module')
|
|
306
|
+
arg_parser.add_argument('--devel', default=False, action='store_true', help='''Start in development mode, enable debug, start only the module(s) listed in -m.\nExample: -m misp_modules.modules.expansion.bgpranking''')
|
|
307
|
+
args = arg_parser.parse_args()
|
|
308
|
+
|
|
309
|
+
if args.devel:
|
|
310
|
+
init_logger(debug=True)
|
|
311
|
+
log.info('Launch MISP modules server in development mode. Enable debug, load a list of modules is -m is used.')
|
|
312
|
+
if args.m:
|
|
313
|
+
mhandlers = {}
|
|
314
|
+
modules = []
|
|
315
|
+
for module in args.m:
|
|
316
|
+
splitted = module.split(".")
|
|
317
|
+
modulename = splitted[-1]
|
|
318
|
+
moduletype = splitted[2]
|
|
319
|
+
mhandlers[modulename] = importlib.import_module(module)
|
|
320
|
+
mhandlers['type:' + modulename] = moduletype
|
|
321
|
+
modules.append(modulename)
|
|
322
|
+
log.info(f'MISP modules {modulename} imported')
|
|
323
|
+
else:
|
|
324
|
+
mhandlers, loaded_modules = _launch_from_current_dir()
|
|
325
|
+
else:
|
|
326
|
+
init_logger(debug=args.debug)
|
|
327
|
+
if args.system:
|
|
328
|
+
log.info('Launch MISP modules server from package.')
|
|
329
|
+
load_package_helpers()
|
|
330
|
+
mhandlers, loaded_modules = load_package_modules()
|
|
331
|
+
else:
|
|
332
|
+
mhandlers, loaded_modules = _launch_from_current_dir()
|
|
333
|
+
|
|
334
|
+
for module in args.m:
|
|
335
|
+
mispmod = importlib.import_module(module)
|
|
336
|
+
mispmod.register(mhandlers, loaded_modules)
|
|
337
|
+
|
|
338
|
+
service = [
|
|
339
|
+
(r'/modules', ListModules),
|
|
340
|
+
(r'/query', QueryModule),
|
|
341
|
+
(r'/healthcheck', Healthcheck),
|
|
342
|
+
]
|
|
343
|
+
|
|
344
|
+
application = tornado.web.Application(service)
|
|
345
|
+
try:
|
|
346
|
+
server = tornado.httpserver.HTTPServer(application, max_buffer_size=1073741824) # buffer size increase when large MISP event are submitted - GH issue 662
|
|
347
|
+
server.listen(args.port, args.listen)
|
|
348
|
+
except Exception as e:
|
|
349
|
+
if e.errno == 98:
|
|
350
|
+
pids = psutil.pids()
|
|
351
|
+
for pid in pids:
|
|
352
|
+
p = psutil.Process(pid)
|
|
353
|
+
if p.name() == "misp-modules":
|
|
354
|
+
print("\n\n\n")
|
|
355
|
+
print(e)
|
|
356
|
+
print("\nmisp-modules is still running as PID: {}\n".format(pid))
|
|
357
|
+
print("Please kill accordingly:")
|
|
358
|
+
print("sudo kill {}".format(pid))
|
|
359
|
+
return 1
|
|
360
|
+
print(e)
|
|
361
|
+
print("misp-modules might still be running.")
|
|
362
|
+
else:
|
|
363
|
+
log.exception(f"Could not listen on {args.listen}:{args.port}")
|
|
364
|
+
return 1
|
|
365
|
+
|
|
366
|
+
log.info(f'MISP modules server started on {args.listen} port {args.port}')
|
|
367
|
+
if args.test:
|
|
368
|
+
log.info('MISP modules started in test-mode, quitting immediately.')
|
|
369
|
+
return 0
|
|
370
|
+
try:
|
|
371
|
+
IOLoop.instance().start()
|
|
372
|
+
finally:
|
|
373
|
+
IOLoop.instance().stop()
|
|
374
|
+
|
|
375
|
+
return 0
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
if __name__ == '__main__':
|
|
379
|
+
sys.exit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = ['cache']
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# MISP modules helper - cache
|
|
5
|
+
#
|
|
6
|
+
# Copyright (C) 2016 Alexandre Dulaunoy
|
|
7
|
+
# Copyright (C) 2016 CIRCL - Computer Incident Response Center Luxembourg
|
|
8
|
+
#
|
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
# (at your option) any later version.
|
|
13
|
+
#
|
|
14
|
+
# This program is distributed in the hope that it will be useful,
|
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
# GNU Affero General Public License for more details.
|
|
18
|
+
#
|
|
19
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
20
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
|
|
24
|
+
import redis
|
|
25
|
+
import hashlib
|
|
26
|
+
|
|
27
|
+
port = int(os.getenv("REDIS_PORT")) if os.getenv("REDIS_PORT") else 6379
|
|
28
|
+
hostname = os.getenv("REDIS_BACKEND") or '127.0.0.1'
|
|
29
|
+
db = int(os.getenv("REDIS_DATABASE")) if os.getenv("REDIS_DATABASE") else 0
|
|
30
|
+
password = os.getenv("REDIS_PW") or None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def selftest(enable=True):
|
|
34
|
+
if not enable:
|
|
35
|
+
return False
|
|
36
|
+
r = redis.Redis(host=hostname, password=password, port=port, db=db)
|
|
37
|
+
try:
|
|
38
|
+
r.ping()
|
|
39
|
+
except Exception:
|
|
40
|
+
return 'Redis not running or not installed. Helper will be disabled.'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get(modulename=None, query=None, value=None, debug=False):
|
|
44
|
+
if (modulename is None or query is None):
|
|
45
|
+
return False
|
|
46
|
+
r = redis.Redis(host=hostname, password=password, port=port, db=db, decode_responses=True)
|
|
47
|
+
h = hashlib.sha1()
|
|
48
|
+
h.update(query.encode('UTF-8'))
|
|
49
|
+
hv = h.hexdigest()
|
|
50
|
+
key = "m:{}:{}".format(modulename, hv)
|
|
51
|
+
|
|
52
|
+
if not r.exists(key):
|
|
53
|
+
if debug:
|
|
54
|
+
print("Key {} added in cache".format(key))
|
|
55
|
+
r.setex(key, 86400, value)
|
|
56
|
+
else:
|
|
57
|
+
if debug:
|
|
58
|
+
print("Cache hit with Key {}".format(key))
|
|
59
|
+
|
|
60
|
+
return r.get(key)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def flush():
|
|
64
|
+
r = redis.StrictRedis(host=hostname, password=password, port=port, db=db, decode_responses=True)
|
|
65
|
+
returncode = r.flushdb()
|
|
66
|
+
return returncode
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
import sys
|
|
71
|
+
if selftest() is not None:
|
|
72
|
+
sys.exit()
|
|
73
|
+
else:
|
|
74
|
+
print("Selftest ok")
|
|
75
|
+
v = get(modulename="testmodule", query="abcdef", value="barfoo", debug=True)
|
|
76
|
+
if v == 'barfoo':
|
|
77
|
+
print("Cache ok")
|
|
78
|
+
v = get(modulename="testmodule", query="abcdef")
|
|
79
|
+
print(v)
|
|
80
|
+
v = get(modulename="testmodule")
|
|
81
|
+
if (not v):
|
|
82
|
+
print("Failed ok")
|
|
83
|
+
if flush():
|
|
84
|
+
print("Cache flushed ok")
|
|
File without changes
|