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,108 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from socialscan.platforms import Platforms
|
|
3
|
+
from socialscan.util import sync_execute_queries
|
|
4
|
+
|
|
5
|
+
moduleinfo = {
|
|
6
|
+
'version': '1',
|
|
7
|
+
'author': 'Christian Studer',
|
|
8
|
+
'description': 'A hover module to get information on the availability of an email address or username on some online platforms.',
|
|
9
|
+
'module-type': ['hover'],
|
|
10
|
+
'name': 'Socialscan Lookup',
|
|
11
|
+
'logo': '',
|
|
12
|
+
'requirements': ['The socialscan python library'],
|
|
13
|
+
'features': 'The module takes an email address or username as input and check its availability on some online platforms. The results for each platform are then returned to see if the email address or the username is used, available or if there is an issue with it.',
|
|
14
|
+
'references': ['https://github.com/iojw/socialscan'],
|
|
15
|
+
'input': 'An email address or usename attribute.',
|
|
16
|
+
'output': 'Text containing information about the availability of an email address or a username in some online platforms.',
|
|
17
|
+
}
|
|
18
|
+
mispattributes = {
|
|
19
|
+
'input': [
|
|
20
|
+
'github-username',
|
|
21
|
+
'target-user',
|
|
22
|
+
'email',
|
|
23
|
+
'email-src',
|
|
24
|
+
'email-dst',
|
|
25
|
+
'target-email',
|
|
26
|
+
'whois-registrant-email'
|
|
27
|
+
],
|
|
28
|
+
'output': ['text']
|
|
29
|
+
}
|
|
30
|
+
moduleconfig = []
|
|
31
|
+
|
|
32
|
+
_PLATFORMS = [
|
|
33
|
+
Platforms.INSTAGRAM,
|
|
34
|
+
Platforms.TWITTER,
|
|
35
|
+
Platforms.GITHUB,
|
|
36
|
+
Platforms.TUMBLR,
|
|
37
|
+
Platforms.LASTFM
|
|
38
|
+
]
|
|
39
|
+
_EMAIL_PLATFORMS = [
|
|
40
|
+
Platforms.PINTEREST,
|
|
41
|
+
Platforms.SPOTIFY,
|
|
42
|
+
Platforms.FIREFOX
|
|
43
|
+
]
|
|
44
|
+
_EMAIL_PLATFORMS.extend(_PLATFORMS)
|
|
45
|
+
_USERNAME_PLATFORMS = [
|
|
46
|
+
Platforms.SNAPCHAT,
|
|
47
|
+
Platforms.GITLAB,
|
|
48
|
+
Platforms.REDDIT,
|
|
49
|
+
Platforms.YAHOO
|
|
50
|
+
]
|
|
51
|
+
_USERNAME_PLATFORMS.extend(_PLATFORMS)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def parse_results(query_results, feature):
|
|
55
|
+
results = []
|
|
56
|
+
for result in query_results:
|
|
57
|
+
if not result.success:
|
|
58
|
+
results.append(f'Unable to retrieve the {feature} on {result.platform}.')
|
|
59
|
+
continue
|
|
60
|
+
if not result.valid:
|
|
61
|
+
results.append(f'Invalid response from {result.platform}, or invalid {feature}.')
|
|
62
|
+
continue
|
|
63
|
+
statement = 'No account' if result.available else 'There is an account'
|
|
64
|
+
results.append(f'{statement} linked to the {feature} on {result.platform}.')
|
|
65
|
+
to_return = [
|
|
66
|
+
{
|
|
67
|
+
'types': mispattributes['output'],
|
|
68
|
+
'values': result
|
|
69
|
+
} for result in results
|
|
70
|
+
]
|
|
71
|
+
return {'results': to_return}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def parse_email(email):
|
|
75
|
+
results = sync_execute_queries([email], platforms=_EMAIL_PLATFORMS)
|
|
76
|
+
return parse_results(results, 'email address')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def parse_username(username, platforms=_USERNAME_PLATFORMS):
|
|
80
|
+
results = sync_execute_queries([username], platforms=platforms)
|
|
81
|
+
return parse_results(results, 'username')
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def parse_github_username(username):
|
|
85
|
+
return parse_username(username, platforms=[Platforms.GITHUB])
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def handler(q=False):
|
|
89
|
+
if q is False:
|
|
90
|
+
return False
|
|
91
|
+
request = json.loads(q)
|
|
92
|
+
if request.get('github-username'):
|
|
93
|
+
return parse_github_username(request['github-username'])
|
|
94
|
+
if request.get('target-user'):
|
|
95
|
+
return parse_username(request['target-user'])
|
|
96
|
+
for attribute_type in mispattributes['input'][2:]:
|
|
97
|
+
if request.get(attribute_type):
|
|
98
|
+
return parse_email(request[attribute_type])
|
|
99
|
+
return {'error': 'Unsupported attributes type'}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def introspection():
|
|
103
|
+
return mispattributes
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def version():
|
|
107
|
+
moduleinfo['config'] = moduleconfig
|
|
108
|
+
return moduleinfo
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import requests
|
|
3
|
+
import base64
|
|
4
|
+
from . import check_input_attribute, checking_error, standard_error_message
|
|
5
|
+
from pymisp import MISPEvent, MISPObject
|
|
6
|
+
from urllib.parse import quote
|
|
7
|
+
|
|
8
|
+
moduleinfo = {
|
|
9
|
+
'version': '1.0',
|
|
10
|
+
'author': 'Ben Verschaeren',
|
|
11
|
+
'description': 'An expansion module to query the Sophoslabs intelix API to get additional information about an ip address, url, domain or sha256 attribute.',
|
|
12
|
+
'module-type': ['expansion'],
|
|
13
|
+
'name': 'SophosLabs Intelix Lookup',
|
|
14
|
+
'logo': 'sophoslabs_intelix.svg',
|
|
15
|
+
'requirements': ['A client_id and client_secret pair to authenticate to the SophosLabs Intelix API'],
|
|
16
|
+
'features': 'The module takes an ip address, url, domain or sha256 attribute and queries the SophosLabs Intelix API with the attribute value. The result of this query is a SophosLabs Intelix hash report, or an ip or url lookup, that is then parsed and returned in a MISP object.',
|
|
17
|
+
'references': ['https://aws.amazon.com/marketplace/pp/B07SLZPMCS'],
|
|
18
|
+
'input': 'An ip address, url, domain or sha256 attribute.',
|
|
19
|
+
'output': 'SophosLabs Intelix report and lookup objects',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
moduleconfig = ['client_id', 'client_secret']
|
|
23
|
+
|
|
24
|
+
misperrors = {'error': 'Error'}
|
|
25
|
+
|
|
26
|
+
misp_types_in = ['sha256', 'ip', 'ip-src', 'ip-dst', 'uri', 'url', 'domain', 'hostname']
|
|
27
|
+
|
|
28
|
+
mispattributes = {'input': misp_types_in,
|
|
29
|
+
'format': 'misp_standard'}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SophosLabsApi():
|
|
33
|
+
def __init__(self, client_id, client_secret):
|
|
34
|
+
self.misp_event = MISPEvent()
|
|
35
|
+
self.client_id = client_id
|
|
36
|
+
self.client_secret = client_secret
|
|
37
|
+
self.authToken = f"{self.client_id}:{self.client_secret}"
|
|
38
|
+
self.baseurl = 'de.api.labs.sophos.com'
|
|
39
|
+
d = {'grant_type': 'client_credentials'}
|
|
40
|
+
h = {'Authorization': f"Basic {base64.b64encode(self.authToken.encode('UTF-8')).decode('ascii')}",
|
|
41
|
+
'Content-Type': 'application/x-www-form-urlencoded'}
|
|
42
|
+
r = requests.post('https://api.labs.sophos.com/oauth2/token', headers=h, data=d)
|
|
43
|
+
if r.status_code == 200:
|
|
44
|
+
j = json.loads(r.text)
|
|
45
|
+
self.accessToken = j['access_token']
|
|
46
|
+
|
|
47
|
+
def get_result(self):
|
|
48
|
+
event = json.loads(self.misp_event.to_json())
|
|
49
|
+
results = {key: event[key] for key in ('Attribute', 'Object') if (key in event and event[key])}
|
|
50
|
+
return {'results': results}
|
|
51
|
+
|
|
52
|
+
def hash_lookup(self, filehash):
|
|
53
|
+
sophos_object = MISPObject('SOPHOSLabs Intelix SHA256 Report')
|
|
54
|
+
h = {"Authorization": f"{self.accessToken}"}
|
|
55
|
+
r = requests.get(f"https://{self.baseurl}/lookup/files/v1/{filehash}", headers=h)
|
|
56
|
+
if r.status_code == 200:
|
|
57
|
+
j = json.loads(r.text)
|
|
58
|
+
if 'reputationScore' in j:
|
|
59
|
+
sophos_object.add_attribute('Reputation Score', type='text', value=j['reputationScore'])
|
|
60
|
+
if 0 <= j['reputationScore'] <= 19:
|
|
61
|
+
sophos_object.add_attribute('Decision', type='text', value='This file is malicious')
|
|
62
|
+
if 20 <= j['reputationScore'] <= 29:
|
|
63
|
+
sophos_object.add_attribute('Decision', type='text', value='This file is potentially unwanted')
|
|
64
|
+
if 30 <= j['reputationScore'] <= 69:
|
|
65
|
+
sophos_object.add_attribute('Decision', type='text', value='This file is unknown and suspicious')
|
|
66
|
+
if 70 <= j['reputationScore'] <= 100:
|
|
67
|
+
sophos_object.add_attribute('Decision', type='text', value='This file is known good')
|
|
68
|
+
if 'detectionName' in j:
|
|
69
|
+
sophos_object.add_attribute('Detection Name', type='text', value=j['detectionName'])
|
|
70
|
+
else:
|
|
71
|
+
sophos_object.add_attribute('Detection Name', type='text', value='No name associated with this IoC')
|
|
72
|
+
self.misp_event.add_object(**sophos_object)
|
|
73
|
+
|
|
74
|
+
def ip_lookup(self, ip):
|
|
75
|
+
sophos_object = MISPObject('SOPHOSLabs Intelix IP Category Lookup')
|
|
76
|
+
h = {"Authorization": f"{self.accessToken}"}
|
|
77
|
+
r = requests.get(f"https://{self.baseurl}/lookup/ips/v1/{ip}", headers=h)
|
|
78
|
+
if r.status_code == 200:
|
|
79
|
+
j = json.loads(r.text)
|
|
80
|
+
if 'category' in j:
|
|
81
|
+
for c in j['category']:
|
|
82
|
+
sophos_object.add_attribute('IP Address Categorisation', type='text', value=c)
|
|
83
|
+
else:
|
|
84
|
+
sophos_object.add_attribute('IP Address Categorisation', type='text', value='No category assocaited with IoC')
|
|
85
|
+
self.misp_event.add_object(**sophos_object)
|
|
86
|
+
|
|
87
|
+
def url_lookup(self, url):
|
|
88
|
+
sophos_object = MISPObject('SOPHOSLabs Intelix URL Lookup')
|
|
89
|
+
h = {"Authorization": f"{self.accessToken}"}
|
|
90
|
+
r = requests.get(f"https://{self.baseurl}/lookup/urls/v1/{quote(url, safe='')}", headers=h)
|
|
91
|
+
if r.status_code == 200:
|
|
92
|
+
j = json.loads(r.text)
|
|
93
|
+
if 'productivityCategory' in j:
|
|
94
|
+
sophos_object.add_attribute('URL Categorisation', type='text', value=j['productivityCategory'])
|
|
95
|
+
else:
|
|
96
|
+
sophos_object.add_attribute('URL Categorisation', type='text', value='No category assocaited with IoC')
|
|
97
|
+
|
|
98
|
+
if 'riskLevel' in j:
|
|
99
|
+
sophos_object.add_attribute('URL Risk Level', type='text', value=j['riskLevel'])
|
|
100
|
+
else:
|
|
101
|
+
sophos_object.add_attribute('URL Risk Level', type='text', value='No risk level associated with IoC')
|
|
102
|
+
|
|
103
|
+
if 'securityCategory' in j:
|
|
104
|
+
sophos_object.add_attribute('URL Security Category', type='text', value=j['securityCategory'])
|
|
105
|
+
else:
|
|
106
|
+
sophos_object.add_attribute('URL Security Category', type='text', value='No Security Category associated with IoC')
|
|
107
|
+
self.misp_event.add_object(**sophos_object)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def handler(q=False):
|
|
111
|
+
if q is False:
|
|
112
|
+
return False
|
|
113
|
+
j = json.loads(q)
|
|
114
|
+
if not j.get('config') or not j['config'].get('client_id') or not j['config'].get('client_secret'):
|
|
115
|
+
misperrors['error'] = "Missing client_id or client_secret value for SOPHOSLabs Intelix. \
|
|
116
|
+
It's free to sign up here https://aws.amazon.com/marketplace/pp/B07SLZPMCS."
|
|
117
|
+
return misperrors
|
|
118
|
+
to_check = (('type', 'value'), ('type', 'value1'))
|
|
119
|
+
if not j.get('attribute') or not any(check_input_attribute(j['attribute'], requirements=check) for check in to_check):
|
|
120
|
+
return {'error': f'{standard_error_message}, {checking_error}.'}
|
|
121
|
+
attribute = j['attribute']
|
|
122
|
+
if attribute['type'] not in misp_types_in:
|
|
123
|
+
return {'error': 'Unsupported attribute type.'}
|
|
124
|
+
client = SophosLabsApi(j['config']['client_id'], j['config']['client_secret'])
|
|
125
|
+
mapping = {
|
|
126
|
+
'sha256': 'hash_lookup',
|
|
127
|
+
'ip-dst': 'ip_lookup',
|
|
128
|
+
'ip-src': 'ip_lookup',
|
|
129
|
+
'ip': 'ip_lookup',
|
|
130
|
+
'uri': 'url_lookup',
|
|
131
|
+
'url': 'url_lookup',
|
|
132
|
+
'domain': 'url_lookup',
|
|
133
|
+
'hostname': 'url_lookup'
|
|
134
|
+
}
|
|
135
|
+
attribute_value = attribute['value'] if 'value' in attribute else attribute['value1']
|
|
136
|
+
getattr(client, mapping[attribute['type']])(attribute_value)
|
|
137
|
+
return client.get_result()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def introspection():
|
|
141
|
+
return mispattributes
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def version():
|
|
145
|
+
moduleinfo['config'] = moduleconfig
|
|
146
|
+
return moduleinfo
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from url_archiver import url_archiver
|
|
3
|
+
|
|
4
|
+
misperrors = {'error': 'Error'}
|
|
5
|
+
mispattributes = {'input': ['link', 'url'], 'output': ['attachment', 'malware-sample']}
|
|
6
|
+
moduleinfo = {
|
|
7
|
+
'version': '0.1',
|
|
8
|
+
'author': 'Alexandre Dulaunoy',
|
|
9
|
+
'description': 'Module to cache web pages of analysis reports, OSINT sources. The module returns a link of the cached page.',
|
|
10
|
+
'module-type': ['expansion'],
|
|
11
|
+
'name': 'URL Archiver',
|
|
12
|
+
'logo': '',
|
|
13
|
+
'requirements': ['urlarchiver: python library to fetch and archive URL on the file-system'],
|
|
14
|
+
'features': 'This module takes a link or url attribute as input and caches the related web page. It returns then a link of the cached page.',
|
|
15
|
+
'references': ['https://github.com/adulau/url_archiver'],
|
|
16
|
+
'input': 'A link or url attribute.',
|
|
17
|
+
'output': 'A malware-sample attribute describing the cached page.',
|
|
18
|
+
}
|
|
19
|
+
moduleconfig = ['archivepath']
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def handler(q=False):
|
|
23
|
+
if q is False:
|
|
24
|
+
return False
|
|
25
|
+
request = json.loads(q)
|
|
26
|
+
if (request.get('config')):
|
|
27
|
+
archive_path = request['config']['archivepath']
|
|
28
|
+
else:
|
|
29
|
+
archive_path = '/tmp/'
|
|
30
|
+
if request.get('link'):
|
|
31
|
+
tocache = request['link']
|
|
32
|
+
data = __archiveLink(archive_path, tocache)
|
|
33
|
+
mispattributes['output'] = ['attachment']
|
|
34
|
+
elif request.get('url'):
|
|
35
|
+
tocache = request['url']
|
|
36
|
+
data = __archiveLink(archive_path, tocache)
|
|
37
|
+
mispattributes['output'] = ['malware-sample']
|
|
38
|
+
else:
|
|
39
|
+
misperrors['error'] = "Link is missing"
|
|
40
|
+
return misperrors
|
|
41
|
+
enc_data = data.decode('ascii')
|
|
42
|
+
r = {'results': [{'types': mispattributes['output'], 'values': tocache, 'data': enc_data}]}
|
|
43
|
+
return r
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def __archiveLink(archive_path, tocache):
|
|
47
|
+
archiver = url_archiver.Archive(archive_path=archive_path)
|
|
48
|
+
return archiver.fetch(url=tocache, armor=True)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def introspection():
|
|
52
|
+
return mispattributes
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def version():
|
|
56
|
+
moduleinfo['config'] = moduleconfig
|
|
57
|
+
return moduleinfo
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
import requests
|
|
4
|
+
from pymisp import MISPEvent, MISPObject
|
|
5
|
+
from . import check_input_attribute, checking_error, standard_error_message
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
misperrors = {
|
|
9
|
+
'error': 'Error'
|
|
10
|
+
}
|
|
11
|
+
mispattributes = {
|
|
12
|
+
'input': [
|
|
13
|
+
'md5',
|
|
14
|
+
'sha1',
|
|
15
|
+
'sha256'
|
|
16
|
+
],
|
|
17
|
+
'format': 'misp_standard'
|
|
18
|
+
}
|
|
19
|
+
moduleinfo = {
|
|
20
|
+
'version': '0.1',
|
|
21
|
+
'author': 'goodlandsecurity',
|
|
22
|
+
'description': 'Module to query the Stairwell API to get additional information about the input hash attribute',
|
|
23
|
+
'module-type': ['expansion'],
|
|
24
|
+
'name': 'Stairwell Lookup',
|
|
25
|
+
'logo': 'stairwell.png',
|
|
26
|
+
'requirements': ['Access to Stairwell platform (apikey)'],
|
|
27
|
+
'features': "The module takes a hash attribute as input and queries Stariwell's API to fetch additional data about it. The result, if the payload is observed in Stariwell, is a file object describing the file the input hash is related to.",
|
|
28
|
+
'references': ['https://stairwell.com', 'https://docs.stairwell.com'],
|
|
29
|
+
'input': 'A hash attribute (md5, sha1, sha256).',
|
|
30
|
+
'output': 'File object related to the input attribute found on Stairwell platform.',
|
|
31
|
+
}
|
|
32
|
+
moduleconfig = ["apikey"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def parse_response(response: dict):
|
|
36
|
+
attribute_mapping = {
|
|
37
|
+
'environments': {'type': 'comment', 'object_relation': 'environment', 'distribution': 5},
|
|
38
|
+
'imphash': {'type': 'imphash', 'object_relation': 'impash', 'distribution': 5},
|
|
39
|
+
'magic': {'type': 'comment', 'object_relation': 'magic', 'distribution': 5},
|
|
40
|
+
'malEval': {
|
|
41
|
+
'probabilityBucket': {'type': 'comment', 'object_relation': 'malEval-probability', 'distribution': 5},
|
|
42
|
+
'severity': {'type': 'comment', 'object_relation': 'malEval-severity', 'distribution': 5}
|
|
43
|
+
},
|
|
44
|
+
'md5': {'type': 'md5', 'object_relation': 'md5', 'distribution': 5},
|
|
45
|
+
'mimeType': {'type': 'mime-type', 'object_relation': 'mime-type', 'distribution': 5},
|
|
46
|
+
'sha1': {'type': 'sha1', 'object_relation': 'sha1', 'distribution': 5},
|
|
47
|
+
'sha256': {'type': 'sha256', 'object_relation': 'sha256', 'distribution': 5},
|
|
48
|
+
'shannonEntropy': {'type': 'float', 'object_relation': 'entropy', 'distribution': 5},
|
|
49
|
+
'size': {'type': 'size-in-bytes', 'object_relation': 'size-in-bytes', 'distribution': 5},
|
|
50
|
+
'stairwellFirstSeenTime': {'type': 'datetime', 'object_relation': 'stairwell-first-seen', 'distribution': 5},
|
|
51
|
+
'tlsh': {'type': 'tlsh', 'object_relation': 'tlsh', 'distribution': 5},
|
|
52
|
+
'yaraRuleMatches': {'type': 'text', 'object_relation': 'yara-rule-match', 'comment': 'matching Stairwell yara rule name', 'distribution': 5}
|
|
53
|
+
}
|
|
54
|
+
environments_mapping = {
|
|
55
|
+
"NCS2SM-YHB2KT-SAFUDX-JC7F6WYA": "Florian's Open Rules",
|
|
56
|
+
"VR9Z98-4KU7ZC-PCNFEG-FURQ66FW": "Jotti",
|
|
57
|
+
"D7W6M6-BA9BS4-BQ23Z4-NKCNWQ96": "Malshare",
|
|
58
|
+
"D4447Q-WJJL6P-W7ME89-WHXJK8TW": "Malware Bazaar",
|
|
59
|
+
"XAKLND-DKWP3Z-56RL88-6XJ5NH46": "Pro Rules",
|
|
60
|
+
"GMEELM-K226XF-F95XZL-7VEJFKZ6": "Public Samples",
|
|
61
|
+
"5HEG8N-9T7UPG-8SZJ7T-2J4XSDC6": "RH-ISAC",
|
|
62
|
+
"2NN2BJ-HDVQHS-49824H-2SEDBBLJ": "RH-ISAC Malware Sharing",
|
|
63
|
+
"VCZTNF-8S76AK-LUU53W-2SWFFZWJ": "Stairwell Experimental Rules",
|
|
64
|
+
"GEG6FU-MRARGF-TLTM6X-H6MGDT5E": "Stairwell Methodology Rules",
|
|
65
|
+
"EB3DXY-3ZYFVH-6HNKJQ-GAPKHESS": "Stairwell OSINT Rules",
|
|
66
|
+
"NQNJM6-5LSCAF-3MC5FJ-W8EKGW6N": "Stairwell Research Rules",
|
|
67
|
+
"TT9GM5-JUMD8H-9828FL-GAW5NNXE": "stairwell-public-verdicts",
|
|
68
|
+
"MKYSAR-3XN9MB-3VAK3R-888ZJUTJ": "Threat Report Feeds",
|
|
69
|
+
"6HP5R3-ZM7DAN-RB4732-X6QPCJ36": "Virusshare",
|
|
70
|
+
"TV6WCV-7Y79LE-BK79EY-C8GUEY46": "vxintel"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
misp_event = MISPEvent()
|
|
74
|
+
misp_object = MISPObject('stairwell')
|
|
75
|
+
for feature, attribute in attribute_mapping.items():
|
|
76
|
+
if feature in response.keys() and response[feature]:
|
|
77
|
+
if feature == 'yaraRuleMatches':
|
|
78
|
+
for rule in response[feature]:
|
|
79
|
+
env_pattern = r'\b[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{8}\b'
|
|
80
|
+
env = re.findall(env_pattern, rule.split('yaraRules/')[0])[0]
|
|
81
|
+
misp_attribute = {
|
|
82
|
+
'value': rule.split('yaraRules/')[1],
|
|
83
|
+
'comment': f'Rule from: {environments_mapping.get(env, "Unknown UUID!")}'
|
|
84
|
+
}
|
|
85
|
+
misp_attribute.update(attribute)
|
|
86
|
+
misp_object.add_attribute(**misp_attribute)
|
|
87
|
+
elif feature == 'environments':
|
|
88
|
+
for env in response[feature]:
|
|
89
|
+
misp_attribute = {
|
|
90
|
+
'value': environments_mapping.get(env, f'Unknown Environment: {env}'),
|
|
91
|
+
'comment': 'Hash observed in'
|
|
92
|
+
}
|
|
93
|
+
misp_attribute.update(attribute)
|
|
94
|
+
misp_object.add_attribute(**misp_attribute)
|
|
95
|
+
elif feature == 'malEval':
|
|
96
|
+
for attr in attribute:
|
|
97
|
+
misp_attribute = {'value': response[feature][attr]}
|
|
98
|
+
misp_attribute.update(attribute[attr])
|
|
99
|
+
misp_object.add_attribute(**misp_attribute)
|
|
100
|
+
else:
|
|
101
|
+
misp_attribute = {'value': response[feature]}
|
|
102
|
+
misp_attribute.update(attribute)
|
|
103
|
+
attr = misp_object.add_attribute(**misp_attribute)
|
|
104
|
+
if feature in ('md5', 'sha1', 'sha256'):
|
|
105
|
+
for label in response['malEval']['labels']:
|
|
106
|
+
attr.add_tag(label)
|
|
107
|
+
misp_event.add_object(**misp_object)
|
|
108
|
+
|
|
109
|
+
event = json.loads(misp_event.to_json())
|
|
110
|
+
results = {'Object': event['Object']}
|
|
111
|
+
|
|
112
|
+
return {'results': results}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def handler(q=False):
|
|
116
|
+
if q is False:
|
|
117
|
+
return False
|
|
118
|
+
request = json.loads(q)
|
|
119
|
+
if not request.get('config') or not request['config'].get('apikey'):
|
|
120
|
+
misperrors['error'] = 'A Stairwell api key is required for this module!'
|
|
121
|
+
return misperrors
|
|
122
|
+
if not request.get('attribute') or not check_input_attribute(request['attribute'], requirements=('type', 'value')):
|
|
123
|
+
misperrors['error'] = f'{standard_error_message}, {checking_error}.'
|
|
124
|
+
return misperrors
|
|
125
|
+
attribute = request['attribute']
|
|
126
|
+
if attribute['type'] not in mispattributes['input']:
|
|
127
|
+
misperrors['error'] = 'Unsupported attribute type!'
|
|
128
|
+
return misperrors
|
|
129
|
+
|
|
130
|
+
headers = {
|
|
131
|
+
"Accept": "application/json",
|
|
132
|
+
"Authorization": request['config']['apikey'],
|
|
133
|
+
"User-Agent": f"misp-module {__file__} {moduleinfo['version']}"
|
|
134
|
+
}
|
|
135
|
+
url = f"https://app.stairwell.com/v1/objects/{attribute['value']}/metadata"
|
|
136
|
+
response = requests.get(url=url, headers=headers).json()
|
|
137
|
+
|
|
138
|
+
if response.get('code') == 16: # bad auth
|
|
139
|
+
return {'error': f"{response['message']} Is api key valid?"}
|
|
140
|
+
elif response.get('code') == 5: # not found
|
|
141
|
+
return {'error': f"{attribute['type']}:{attribute['value']} {response['message']}"}
|
|
142
|
+
elif response.get('code') == 2: # encoding/hex: invalid byte
|
|
143
|
+
return {'error': response['message']}
|
|
144
|
+
elif response.get('code'): # catchall for potential unforeseen errors
|
|
145
|
+
return {'error': response['message'], 'code': response['code']}
|
|
146
|
+
else:
|
|
147
|
+
return parse_response(response)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def introspection():
|
|
151
|
+
return mispattributes
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def version():
|
|
155
|
+
moduleinfo['config'] = moduleconfig
|
|
156
|
+
return moduleinfo
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import json
|
|
2
|
+
try:
|
|
3
|
+
from stix2patterns.validator import run_validator
|
|
4
|
+
except ImportError:
|
|
5
|
+
print("stix2 patterns python library is missing, use 'pip3 install stix2-patterns' to install it.")
|
|
6
|
+
|
|
7
|
+
misperrors = {'error': 'Error'}
|
|
8
|
+
mispattributes = {'input': ['stix2-pattern'], 'output': ['text']}
|
|
9
|
+
moduleinfo = {
|
|
10
|
+
'version': '0.1',
|
|
11
|
+
'author': 'Christian Studer',
|
|
12
|
+
'module-type': ['hover'],
|
|
13
|
+
'name': 'STIX2 Pattern Syntax Validator',
|
|
14
|
+
'description': 'An expansion hover module to perform a syntax check on stix2 patterns.',
|
|
15
|
+
'logo': 'stix.png',
|
|
16
|
+
'requirements': ['stix2patterns python library'],
|
|
17
|
+
'features': 'This module takes a STIX2 pattern attribute as input and performs a syntax check on it.\n\nIt displays then that the rule is valid if it is the case, and the error related to the rule otherwise.',
|
|
18
|
+
'references': ['[STIX2.0 patterning specifications](http://docs.oasis-open.org/cti/stix/v2.0/cs01/part5-stix-patterning/stix-v2.0-cs01-part5-stix-patterning.html)'],
|
|
19
|
+
'input': 'A STIX2 pattern attribute.',
|
|
20
|
+
'output': 'Text describing the validity of the STIX2 pattern.',
|
|
21
|
+
}
|
|
22
|
+
moduleconfig = []
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def handler(q=False):
|
|
26
|
+
if q is False:
|
|
27
|
+
return False
|
|
28
|
+
request = json.loads(q)
|
|
29
|
+
if not request.get('stix2-pattern'):
|
|
30
|
+
misperrors['error'] = 'STIX2 pattern missing'
|
|
31
|
+
return misperrors
|
|
32
|
+
pattern = request.get('stix2-pattern')
|
|
33
|
+
syntax_errors = []
|
|
34
|
+
for p in pattern[1:-1].split(' AND '):
|
|
35
|
+
syntax_validator = run_validator("[{}]".format(p))
|
|
36
|
+
if syntax_validator:
|
|
37
|
+
for error in syntax_validator:
|
|
38
|
+
syntax_errors.append(error)
|
|
39
|
+
if syntax_errors:
|
|
40
|
+
s = 's' if len(syntax_errors) > 1 else ''
|
|
41
|
+
s_errors = ""
|
|
42
|
+
for error in syntax_errors:
|
|
43
|
+
s_errors += "{}\n".format(error[6:])
|
|
44
|
+
result = "Syntax error{}: \n{}".format(s, s_errors[:-1])
|
|
45
|
+
else:
|
|
46
|
+
result = "Syntax valid"
|
|
47
|
+
return {'results': [{'types': mispattributes['output'], 'values': result}]}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def introspection():
|
|
51
|
+
return mispattributes
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def version():
|
|
55
|
+
moduleinfo['config'] = moduleconfig
|
|
56
|
+
return moduleinfo
|