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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import vulners
|
|
3
|
+
|
|
4
|
+
misperrors = {'error': 'Error'}
|
|
5
|
+
mispattributes = {'input': ['vulnerability'], 'output': ['text']}
|
|
6
|
+
moduleinfo = {
|
|
7
|
+
'version': '0.1',
|
|
8
|
+
'author': 'Igor Ivanov',
|
|
9
|
+
'description': 'An expansion hover module to expand information about CVE id using Vulners API.',
|
|
10
|
+
'module-type': ['hover'],
|
|
11
|
+
'name': 'Vulners Lookup',
|
|
12
|
+
'logo': 'vulners.png',
|
|
13
|
+
'requirements': ['Vulners python library', 'An access to the Vulners API'],
|
|
14
|
+
'features': 'This module takes a vulnerability attribute as input and queries the Vulners API in order to get some additional data about it.\n\nThe API then returns details about the vulnerability.',
|
|
15
|
+
'references': ['https://vulners.com/'],
|
|
16
|
+
'input': 'A vulnerability attribute.',
|
|
17
|
+
'output': 'Text giving additional information about the CVE in input.',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Get API key from https://vulners.com/userinfo
|
|
21
|
+
moduleconfig = ["apikey"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def handler(q=False):
|
|
25
|
+
if q is False:
|
|
26
|
+
return False
|
|
27
|
+
request = json.loads(q)
|
|
28
|
+
if not request.get('vulnerability'):
|
|
29
|
+
misperrors['error'] = 'Vulnerability id missing'
|
|
30
|
+
return misperrors
|
|
31
|
+
|
|
32
|
+
ai_summary = ''
|
|
33
|
+
exploit_summary = ''
|
|
34
|
+
vuln_summary = ''
|
|
35
|
+
|
|
36
|
+
if not request.get('config') or not request['config'].get('apikey'):
|
|
37
|
+
return {'error': "A Vulners api key is required for this module."}
|
|
38
|
+
|
|
39
|
+
key = request['config']['apikey']
|
|
40
|
+
vulners_api = vulners.Vulners(api_key=key)
|
|
41
|
+
vulnerability = request.get('vulnerability')
|
|
42
|
+
vulners_document = vulners_api.document(vulnerability)
|
|
43
|
+
|
|
44
|
+
# Get AI scoring from the document if it's already calculated
|
|
45
|
+
# There is no need to call AI Scoring method
|
|
46
|
+
if 'score' in vulners_document.get('enchantments', {}):
|
|
47
|
+
vulners_ai_score = vulners_document['enchantments']['score']['value']
|
|
48
|
+
else:
|
|
49
|
+
vulners_ai_score = vulners_api.get_ai_score(vulnerability)
|
|
50
|
+
if len(vulners_ai_score) == 2:
|
|
51
|
+
vulners_ai_score = vulners_ai_score[0]
|
|
52
|
+
|
|
53
|
+
vulners_exploits = vulners_api.searchExploit(vulnerability)
|
|
54
|
+
|
|
55
|
+
if vulners_document:
|
|
56
|
+
vuln_summary += vulners_document.get('description')
|
|
57
|
+
else:
|
|
58
|
+
vuln_summary += 'Non existing CVE'
|
|
59
|
+
|
|
60
|
+
if vulners_ai_score:
|
|
61
|
+
ai_summary += 'Vulners AI Score is ' + str(vulners_ai_score) + " "
|
|
62
|
+
|
|
63
|
+
if vulners_exploits:
|
|
64
|
+
exploit_summary += " || " + str(len(vulners_exploits)) + " Public exploits available:\n "
|
|
65
|
+
for exploit in vulners_exploits:
|
|
66
|
+
exploit_summary += exploit['title'] + " " + exploit['href'] + "\n "
|
|
67
|
+
exploit_summary += "|| Vulnerability Description: " + vuln_summary
|
|
68
|
+
|
|
69
|
+
summary = ai_summary + exploit_summary + vuln_summary
|
|
70
|
+
|
|
71
|
+
r = {'results': [{'types': mispattributes['output'], 'values': summary}]}
|
|
72
|
+
return r
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def introspection():
|
|
76
|
+
return mispattributes
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def version():
|
|
80
|
+
moduleinfo['config'] = moduleconfig
|
|
81
|
+
return moduleinfo
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pymisp import MISPAttribute, MISPEvent
|
|
3
|
+
from urllib.parse import urlparse
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
import vysion.client as vysion
|
|
8
|
+
|
|
9
|
+
import vysion.dto as dto
|
|
10
|
+
from vysion.dto.util import MISPProcessor
|
|
11
|
+
from . import standard_error_message
|
|
12
|
+
|
|
13
|
+
misperrors = {"error": "Error"}
|
|
14
|
+
mispattributes = {
|
|
15
|
+
"input": [
|
|
16
|
+
"email",
|
|
17
|
+
"domain",
|
|
18
|
+
"hostname",
|
|
19
|
+
"url",
|
|
20
|
+
"text",
|
|
21
|
+
"btc",
|
|
22
|
+
"phone-number",
|
|
23
|
+
"target-org",
|
|
24
|
+
"xmr",
|
|
25
|
+
"dash",
|
|
26
|
+
],
|
|
27
|
+
"format": "misp_standard",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# possible module-types: 'expansion', 'hover' or both
|
|
31
|
+
moduleinfo = {
|
|
32
|
+
'version': '1',
|
|
33
|
+
'author': 'Byron Labs',
|
|
34
|
+
'description': 'Module to enrich the information by making use of the Vysion API.',
|
|
35
|
+
'module-type': ['expansion'],
|
|
36
|
+
'name': 'Vysion Enrich',
|
|
37
|
+
'logo': 'vysion.png',
|
|
38
|
+
'requirements': ['Vysion python library', 'Vysion API Key'],
|
|
39
|
+
'features': "This module gets correlated information from Byron Labs' dark web intelligence database. With this you will get several objects containing information related to, for example, an organization victim of a ransomware attack.",
|
|
40
|
+
'references': ['https://vysion.ai/', 'https://developers.vysion.ai/', 'https://github.com/ByronLabs/vysion-cti/tree/main'],
|
|
41
|
+
'input': 'company(target-org), country, info, BTC, XMR and DASH address.',
|
|
42
|
+
'output': 'MISP objects containing title, link to our webapp and TOR, i2p or clearnet URLs.',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# config fields that your code expects from the site admin
|
|
46
|
+
moduleconfig = [
|
|
47
|
+
"apikey",
|
|
48
|
+
"event_limit",
|
|
49
|
+
"proxy_host",
|
|
50
|
+
"proxy_port",
|
|
51
|
+
"proxy_username",
|
|
52
|
+
"proxy_password",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
LOGGER = logging.getLogger("vysion")
|
|
56
|
+
LOGGER.setLevel(logging.INFO)
|
|
57
|
+
LOGGER.debug("Starting Vysion")
|
|
58
|
+
|
|
59
|
+
DEFAULT_RESULTS_LIMIT = 10
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_proxy_settings(config: dict) -> dict:
|
|
63
|
+
"""Returns proxy settings in the requests format.
|
|
64
|
+
If no proxy settings are set, return None."""
|
|
65
|
+
proxies = None
|
|
66
|
+
host = config.get("proxy_host")
|
|
67
|
+
port = config.get("proxy_port")
|
|
68
|
+
username = config.get("proxy_username")
|
|
69
|
+
password = config.get("proxy_password")
|
|
70
|
+
|
|
71
|
+
if host:
|
|
72
|
+
if not port:
|
|
73
|
+
misperrors["error"] = (
|
|
74
|
+
"The vysion_proxy_host config is set, "
|
|
75
|
+
"please also set the vysion_proxy_port."
|
|
76
|
+
)
|
|
77
|
+
raise KeyError
|
|
78
|
+
parsed = urlparse(host)
|
|
79
|
+
if "http" in parsed.scheme:
|
|
80
|
+
scheme = "http"
|
|
81
|
+
else:
|
|
82
|
+
scheme = parsed.scheme
|
|
83
|
+
netloc = parsed.netloc
|
|
84
|
+
host = f"{netloc}:{port}"
|
|
85
|
+
|
|
86
|
+
if username:
|
|
87
|
+
if not password:
|
|
88
|
+
misperrors["error"] = (
|
|
89
|
+
"The vysion_proxy_username config is set, "
|
|
90
|
+
"please also set the vysion_proxy_password."
|
|
91
|
+
)
|
|
92
|
+
raise KeyError
|
|
93
|
+
auth = f"{username}:{password}"
|
|
94
|
+
host = auth + "@" + host
|
|
95
|
+
|
|
96
|
+
proxies = {"http": f"{scheme}://{host}", "https": f"{scheme}://{host}"}
|
|
97
|
+
return proxies
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def parse_error(status_code: int) -> str:
|
|
101
|
+
|
|
102
|
+
status_mapping = {
|
|
103
|
+
500: "Vysion is blind.",
|
|
104
|
+
400: "Incorrect request, please check the arguments.",
|
|
105
|
+
403: "You don't have enough privileges to make the request.",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if status_code in status_mapping:
|
|
109
|
+
return status_mapping[status_code]
|
|
110
|
+
|
|
111
|
+
return "Vysion may not be accessible."
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def handler(q=False):
|
|
115
|
+
|
|
116
|
+
if q is False:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
request = json.loads(q)
|
|
120
|
+
|
|
121
|
+
if not request.get("config") or not request["config"].get("apikey"):
|
|
122
|
+
misperrors["error"] = "A Vysion api key is required for this module."
|
|
123
|
+
return misperrors
|
|
124
|
+
|
|
125
|
+
if not request.get("attribute"):
|
|
126
|
+
return {
|
|
127
|
+
"error": f"{standard_error_message}, which should contain at least a type, a value and an uuid."
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if request["attribute"]["type"] not in mispattributes["input"]:
|
|
131
|
+
return {"error": "Unsupported attribute type."}
|
|
132
|
+
|
|
133
|
+
# event_limit = request["config"].get("event_limit")
|
|
134
|
+
attribute = request["attribute"]
|
|
135
|
+
proxy_settings = get_proxy_settings(request.get("config"))
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
|
|
139
|
+
client = vysion.Client(
|
|
140
|
+
api_key=request["config"]["apikey"],
|
|
141
|
+
headers={
|
|
142
|
+
"x-tool": "MISPModuleVysionExpansion",
|
|
143
|
+
},
|
|
144
|
+
proxy=proxy_settings["http"] if proxy_settings else None,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
LOGGER.debug(attribute)
|
|
148
|
+
|
|
149
|
+
misp_attribute = MISPAttribute()
|
|
150
|
+
misp_attribute.from_dict(**attribute)
|
|
151
|
+
|
|
152
|
+
attribute_type = misp_attribute.type
|
|
153
|
+
attribute_value = misp_attribute.value
|
|
154
|
+
|
|
155
|
+
# https://www.misp-project.org/datamodels/#types
|
|
156
|
+
|
|
157
|
+
LOGGER.debug(attribute_type)
|
|
158
|
+
|
|
159
|
+
result = None
|
|
160
|
+
|
|
161
|
+
if attribute_type == "email":
|
|
162
|
+
result = client.find_email(attribute_value)
|
|
163
|
+
elif attribute_type == "domain":
|
|
164
|
+
result = client.find_url(attribute_value)
|
|
165
|
+
elif attribute_type == "url":
|
|
166
|
+
result = client.find_url(attribute_value)
|
|
167
|
+
elif attribute_type == "text":
|
|
168
|
+
result = client.search(attribute_value)
|
|
169
|
+
elif attribute_type == "target-org":
|
|
170
|
+
result = client.search(attribute_value)
|
|
171
|
+
elif attribute_type == "phone-number":
|
|
172
|
+
result = client.search(attribute_value)
|
|
173
|
+
elif attribute_type == "btc":
|
|
174
|
+
result = client.find_wallet("BTC",attribute_value)
|
|
175
|
+
elif attribute_type == "xmr":
|
|
176
|
+
result = client.find_wallet("XMR",attribute_value)
|
|
177
|
+
elif attribute_type == "dash":
|
|
178
|
+
result = client.find_wallet("DASH",attribute_value)
|
|
179
|
+
|
|
180
|
+
if result is None:
|
|
181
|
+
return {"results": {}}
|
|
182
|
+
|
|
183
|
+
p = MISPProcessor()
|
|
184
|
+
misp_event: MISPEvent = p.process(result, ref_attribute=misp_attribute)
|
|
185
|
+
|
|
186
|
+
LOGGER.info("Vysion client initialized")
|
|
187
|
+
|
|
188
|
+
LOGGER.info("Vysion result obtained")
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
"results": {
|
|
192
|
+
"Object": [
|
|
193
|
+
json.loads(object.to_json()) for object in misp_event.objects
|
|
194
|
+
],
|
|
195
|
+
"Attribute": [
|
|
196
|
+
json.loads(attribute.to_json())
|
|
197
|
+
for attribute in misp_event.attributes
|
|
198
|
+
],
|
|
199
|
+
"Tag": [
|
|
200
|
+
json.loads(tag.to_json())
|
|
201
|
+
for tag in misp_event.tags
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
except vysion.APIError as ex:
|
|
207
|
+
|
|
208
|
+
LOGGER.error("Error in Vysion")
|
|
209
|
+
LOGGER.error(ex)
|
|
210
|
+
|
|
211
|
+
misperrors["error"] = ex.message
|
|
212
|
+
return misperrors
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def introspection():
|
|
216
|
+
return mispattributes
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def version():
|
|
220
|
+
moduleinfo["config"] = moduleconfig
|
|
221
|
+
return moduleinfo
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import socket
|
|
5
|
+
|
|
6
|
+
misperrors = {'error': 'Error'}
|
|
7
|
+
mispattributes = {'input': ['domain', 'ip-src', 'ip-dst'], 'output': ['freetext']}
|
|
8
|
+
moduleinfo = {
|
|
9
|
+
'version': '0.1',
|
|
10
|
+
'author': 'Raphaël Vinot',
|
|
11
|
+
'description': 'Module to query a local instance of uwhois (https://github.com/rafiot/uwhoisd).',
|
|
12
|
+
'module-type': ['expansion'],
|
|
13
|
+
'name': 'Whois Lookup',
|
|
14
|
+
'logo': '',
|
|
15
|
+
'requirements': ['uwhois: A whois python library'],
|
|
16
|
+
'features': "This module takes a domain or IP address attribute as input and queries a 'Univseral Whois proxy server' to get the correct details of the Whois query on the input value (check the references for more details about this whois server).",
|
|
17
|
+
'references': ['https://github.com/Lookyloo/uwhoisd'],
|
|
18
|
+
'input': 'A domain or IP address attribute.',
|
|
19
|
+
'output': 'Text describing the result of a whois request for the input value.',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
moduleconfig = ['server', 'port']
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def handler(q=False):
|
|
26
|
+
if q is False:
|
|
27
|
+
return False
|
|
28
|
+
request = json.loads(q)
|
|
29
|
+
if request.get('domain'):
|
|
30
|
+
toquery = request['domain']
|
|
31
|
+
elif request.get('ip-src'):
|
|
32
|
+
toquery = request['ip-src']
|
|
33
|
+
elif request.get('ip-dst'):
|
|
34
|
+
toquery = request['ip-dst']
|
|
35
|
+
else:
|
|
36
|
+
misperrors['error'] = "Unsupported attributes type"
|
|
37
|
+
return misperrors
|
|
38
|
+
|
|
39
|
+
if not request.get('config') or (
|
|
40
|
+
not request['config'].get('server') and not request['config'].get('port')
|
|
41
|
+
):
|
|
42
|
+
misperrors['error'] = 'Whois local instance address is missing'
|
|
43
|
+
return misperrors
|
|
44
|
+
|
|
45
|
+
if 'event_id' in request:
|
|
46
|
+
return handle_expansion(
|
|
47
|
+
request['config']['server'], int(request['config']['port']), toquery
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def handle_expansion(server, port, query):
|
|
52
|
+
bytes_whois = b''
|
|
53
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
54
|
+
sock.connect((server, port))
|
|
55
|
+
sock.sendall(f'{query}\n'.encode())
|
|
56
|
+
while True:
|
|
57
|
+
data = sock.recv(2048)
|
|
58
|
+
if not data:
|
|
59
|
+
break
|
|
60
|
+
bytes_whois += data
|
|
61
|
+
return {
|
|
62
|
+
'results': [{'types': mispattributes['output'], 'values': bytes_whois.decode()}]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def introspection():
|
|
67
|
+
return mispattributes
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def version():
|
|
71
|
+
moduleinfo['config'] = moduleconfig
|
|
72
|
+
return moduleinfo
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
misperrors = {'error': 'Error'}
|
|
6
|
+
mispattributes = {
|
|
7
|
+
'input': ['domain'],
|
|
8
|
+
'output': ['domain', 'dns-soa-email',
|
|
9
|
+
'whois-registrant-email', 'whois-registrant-phone',
|
|
10
|
+
'whois-registrant-name',
|
|
11
|
+
'whois-registrar', 'whois-creation-date', 'domain']
|
|
12
|
+
}
|
|
13
|
+
moduleinfo = {
|
|
14
|
+
'version': '1',
|
|
15
|
+
'author': 'WhoisFreaks',
|
|
16
|
+
'description': 'An expansion module for https://whoisfreaks.com/ that will provide an enriched analysis of the provided domain, including WHOIS and DNS information.',
|
|
17
|
+
'module-type': ['expansion', 'hover'],
|
|
18
|
+
'name': 'WhoisFreaks Lookup',
|
|
19
|
+
'logo': 'whoisfreaks.png',
|
|
20
|
+
'requirements': ['An access to the Whoisfreaks API_KEY'],
|
|
21
|
+
'features': 'The module takes a domain as input and queries the Whoisfreaks API with it.\n\nSome parsing operations are then processed on the result of the query to extract as much information as possible.\n\nAfter this we map the extracted data to MISP attributes.',
|
|
22
|
+
'references': ['https://whoisfreaks.com/'],
|
|
23
|
+
'input': 'A domain whose Data is required',
|
|
24
|
+
'output': 'MISP attributes resulting from the query on Whoisfreaks API, included in the following list:\n- domain\n- dns-soa-email\n- whois-registrant-email\n- whois-registrant-phone\n- whois-registrant-name\n- whois-registrar\n- whois-creation-date\n- domain',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# config fields that your code expects from the site admin
|
|
28
|
+
moduleconfig = ['apikey']
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def handler(q=False):
|
|
32
|
+
if q:
|
|
33
|
+
|
|
34
|
+
request = json.loads(q)
|
|
35
|
+
|
|
36
|
+
if 'config' not in request or (not (request['config'].get('apikey') or ('apiKey' in request['config']))):
|
|
37
|
+
misperrors['error'] = 'WhoisFreaks authentication is missing' + request
|
|
38
|
+
return misperrors
|
|
39
|
+
|
|
40
|
+
apiKey = request['config'].get('apikey')
|
|
41
|
+
|
|
42
|
+
if request.get('domain'):
|
|
43
|
+
domain = request['domain']
|
|
44
|
+
return handle_domain(apiKey, domain, misperrors)
|
|
45
|
+
else:
|
|
46
|
+
misperrors['error'] = "Unsupported attributes types"
|
|
47
|
+
return misperrors
|
|
48
|
+
else:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def handle_domain(apiKey, domain, errors):
|
|
53
|
+
result_filtered = {"results": []}
|
|
54
|
+
r, status_ok = expand_whois(apiKey, domain)
|
|
55
|
+
if status_ok:
|
|
56
|
+
if r:
|
|
57
|
+
result_filtered['results'].extend(r)
|
|
58
|
+
|
|
59
|
+
r, status_ok = expand_dns(apiKey, domain)
|
|
60
|
+
if status_ok:
|
|
61
|
+
if r:
|
|
62
|
+
result_filtered['results'].extend(r)
|
|
63
|
+
|
|
64
|
+
return result_filtered
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def expand_whois(apiKey, domain):
|
|
68
|
+
r = []
|
|
69
|
+
ns_servers = []
|
|
70
|
+
status_ok = False
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
results = get_whois_response(domain, apiKey)
|
|
74
|
+
|
|
75
|
+
if results:
|
|
76
|
+
status_ok = True
|
|
77
|
+
|
|
78
|
+
if 'create_date' in results:
|
|
79
|
+
r.append(
|
|
80
|
+
{
|
|
81
|
+
'types': ['whois-creation-date'],
|
|
82
|
+
'values': [results['create_date']],
|
|
83
|
+
'categories': ['Attribution'],
|
|
84
|
+
'comment': 'Creation Date for %s by whoisFreaks'
|
|
85
|
+
% domain
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if 'domain_registrar' in results:
|
|
91
|
+
if 'registrar_name' in results['domain_registrar']:
|
|
92
|
+
r.append(
|
|
93
|
+
{
|
|
94
|
+
'types': ['whois-registrant-name'],
|
|
95
|
+
'values': [results['domain_registrar']['registrar_name']],
|
|
96
|
+
'categories': ['Attribution'],
|
|
97
|
+
'comment': 'Whois information of %s by whoisFreaks'
|
|
98
|
+
% domain
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
if 'email_address' in results['domain_registrar']:
|
|
102
|
+
r.append(
|
|
103
|
+
{
|
|
104
|
+
'types': ['whois-registrant-email'],
|
|
105
|
+
'values': [results['domain_registrar']['email_address']],
|
|
106
|
+
'categories': ['Attribution'],
|
|
107
|
+
'comment': 'Whois information of %s by whoisFreaks'
|
|
108
|
+
% domain
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if 'phone_number' in results['domain_registrar']:
|
|
113
|
+
r.append(
|
|
114
|
+
{
|
|
115
|
+
'types': ['whois-registrant-email'],
|
|
116
|
+
'values': [results['domain_registrar']['phone_number']],
|
|
117
|
+
'categories': ['Attribution'],
|
|
118
|
+
'comment': 'Whois information of %s by whoisFreaks'
|
|
119
|
+
% domain
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if 'name_servers' in results:
|
|
124
|
+
ns_servers = results['name_servers']
|
|
125
|
+
r.append(
|
|
126
|
+
{
|
|
127
|
+
'types': ['domain'],
|
|
128
|
+
'values': ns_servers,
|
|
129
|
+
'categories': ['Attribution'],
|
|
130
|
+
'comment': 'Name server for %s by whoisFreaks'
|
|
131
|
+
% domain
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
except Exception:
|
|
137
|
+
misperrors['error'] = "Error while processing Whois Data"
|
|
138
|
+
return [], False
|
|
139
|
+
|
|
140
|
+
return r, status_ok
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def expand_dns(apiKey, domain):
|
|
144
|
+
r = []
|
|
145
|
+
status_ok = False
|
|
146
|
+
list_ipv4 = []
|
|
147
|
+
list_ipv6 = []
|
|
148
|
+
servers_mx = []
|
|
149
|
+
soa_hostnames = []
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
results = get_dns_response(domain, apiKey)
|
|
153
|
+
|
|
154
|
+
if results:
|
|
155
|
+
status_ok = True
|
|
156
|
+
|
|
157
|
+
if 'dnsRecords' in results:
|
|
158
|
+
dns_records = results['dnsRecords']
|
|
159
|
+
|
|
160
|
+
for record in dns_records:
|
|
161
|
+
if record['dnsType'] == 'A':
|
|
162
|
+
list_ipv4.append(record['address'])
|
|
163
|
+
elif record['dnsType'] == 'AAAA':
|
|
164
|
+
list_ipv6.append(record['address'])
|
|
165
|
+
elif record['dnsType'] == 'MX':
|
|
166
|
+
servers_mx.append(record['target'])
|
|
167
|
+
elif record['dnsType'] == 'SOA':
|
|
168
|
+
soa_hostnames.append(record['host'])
|
|
169
|
+
|
|
170
|
+
if list_ipv4:
|
|
171
|
+
r.append({'types': ['domain|ip'],
|
|
172
|
+
'values': ['%s|%s' % (domain, ipv4) for ipv4 in
|
|
173
|
+
list_ipv4],
|
|
174
|
+
'categories': ['Network activity'],
|
|
175
|
+
'comment': 'ipv4 of %s ' %
|
|
176
|
+
domain
|
|
177
|
+
})
|
|
178
|
+
if list_ipv6:
|
|
179
|
+
r.append({'types': ['domain|ip'],
|
|
180
|
+
'values': ['%s|%s' % (domain, ipv6) for ipv6 in
|
|
181
|
+
list_ipv6],
|
|
182
|
+
'categories': ['Network activity'],
|
|
183
|
+
'comment': 'ipv6 of %s' %
|
|
184
|
+
domain
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
if servers_mx:
|
|
188
|
+
r.append({'types': ['domain'],
|
|
189
|
+
'values': servers_mx,
|
|
190
|
+
'categories': ['Network activity'],
|
|
191
|
+
'comment': 'mx of %s' %
|
|
192
|
+
domain
|
|
193
|
+
})
|
|
194
|
+
if soa_hostnames:
|
|
195
|
+
r.append({'types': ['domain'],
|
|
196
|
+
'values': soa_hostnames,
|
|
197
|
+
'categories': ['Network activity'],
|
|
198
|
+
'comment': 'soa hostname of %s' %
|
|
199
|
+
domain
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
except Exception:
|
|
204
|
+
misperrors['error'] = "Error while processing Whois Data"
|
|
205
|
+
return [], False
|
|
206
|
+
|
|
207
|
+
return r, status_ok
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def get_whois_response(domain, apiKey):
|
|
211
|
+
query = requests.get(
|
|
212
|
+
f"https://api.whoisfreaks.com/v1.0/whois?apiKey={apiKey}&whois=live&domainName={domain}"
|
|
213
|
+
)
|
|
214
|
+
if query.status_code != 200 and query.status_code != 206:
|
|
215
|
+
return {'error': f'Error while querying whoisfreaks.com - {query.status_code}: {query.reason}'}
|
|
216
|
+
return query.json()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_dns_response(domain, apiKey):
|
|
220
|
+
query = requests.get(
|
|
221
|
+
f"https://api.whoisfreaks.com/v1.0/dns/live?apiKey={apiKey}&domainName={domain}&type=SOA,AAAA,A,MX"
|
|
222
|
+
)
|
|
223
|
+
if query.status_code != 200 and query.status_code != 206:
|
|
224
|
+
return {'error': f'Error while querying whoisfreaks.com - {query.status_code}: {query.reason}'}
|
|
225
|
+
return query.json()
|
|
226
|
+
|
|
227
|
+
def introspection():
|
|
228
|
+
return mispattributes
|
|
229
|
+
|
|
230
|
+
def version():
|
|
231
|
+
moduleinfo['config'] = moduleconfig
|
|
232
|
+
return moduleinfo
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from SPARQLWrapper import SPARQLWrapper, JSON
|
|
3
|
+
|
|
4
|
+
misperrors = {'error': 'Error'}
|
|
5
|
+
mispattributes = {'input': ['text'], 'output': ['text']}
|
|
6
|
+
moduleinfo = {
|
|
7
|
+
'version': '0.2',
|
|
8
|
+
'author': 'Roman Graf',
|
|
9
|
+
'description': 'An expansion hover module to extract information from Wikidata to have additional information about particular term for analysis.',
|
|
10
|
+
'module-type': ['hover'],
|
|
11
|
+
'name': 'Wikidata Lookup',
|
|
12
|
+
'logo': 'wikidata.png',
|
|
13
|
+
'requirements': ['SPARQLWrapper python library'],
|
|
14
|
+
'features': 'This module takes a text attribute as input and queries the Wikidata API. If the text attribute is clear enough to define a specific term, the API returns a wikidata link in response.',
|
|
15
|
+
'references': ['https://www.wikidata.org'],
|
|
16
|
+
'input': 'Text attribute.',
|
|
17
|
+
'output': 'Text attribute.',
|
|
18
|
+
}
|
|
19
|
+
moduleconfig = []
|
|
20
|
+
# sample query text 'Microsoft' should provide Wikidata link https://www.wikidata.org/wiki/Q2283 in response
|
|
21
|
+
wiki_api_url = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def handler(q=False):
|
|
25
|
+
if q is False:
|
|
26
|
+
return False
|
|
27
|
+
request = json.loads(q)
|
|
28
|
+
if not request.get('text'):
|
|
29
|
+
misperrors['error'] = 'Query text missing'
|
|
30
|
+
return misperrors
|
|
31
|
+
|
|
32
|
+
sparql = SPARQLWrapper(wiki_api_url, agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36')
|
|
33
|
+
query_string = \
|
|
34
|
+
"SELECT ?item \n" \
|
|
35
|
+
"WHERE { \n" \
|
|
36
|
+
"?item rdfs:label\"" + request.get('text') + "\" @en \n" \
|
|
37
|
+
"}\n"
|
|
38
|
+
sparql.setQuery(query_string)
|
|
39
|
+
sparql.setReturnFormat(JSON)
|
|
40
|
+
results = sparql.query().convert()
|
|
41
|
+
try:
|
|
42
|
+
result = results["results"]["bindings"]
|
|
43
|
+
summary = result[0]["item"]["value"] if result else 'No additional data found on Wikidata'
|
|
44
|
+
except Exception as e:
|
|
45
|
+
misperrors['error'] = 'wikidata API not accessible {}'.format(e)
|
|
46
|
+
return misperrors['error']
|
|
47
|
+
|
|
48
|
+
r = {'results': [{'types': mispattributes['output'], 'values': summary}]}
|
|
49
|
+
return r
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def introspection():
|
|
53
|
+
return mispattributes
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def version():
|
|
57
|
+
moduleinfo['config'] = moduleconfig
|
|
58
|
+
return moduleinfo
|