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,98 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
misperrors = {'error': 'Error'}
|
|
8
|
+
mispattributes = {'input': ['ip-src', 'ip-dst'], 'output': ['text']}
|
|
9
|
+
moduleinfo = {
|
|
10
|
+
'version': '1.0',
|
|
11
|
+
'author': 'Keith Faber',
|
|
12
|
+
'description': 'Module to query IPRep data for IP addresses.',
|
|
13
|
+
'module-type': ['expansion'],
|
|
14
|
+
'name': 'IPRep Lookup',
|
|
15
|
+
'logo': '',
|
|
16
|
+
'requirements': ['An access to the packetmail API (apikey)'],
|
|
17
|
+
'features': 'This module takes an IP address attribute as input and queries the database from packetmail.net to get some information about the reputation of the IP.',
|
|
18
|
+
'references': ['https://github.com/mahesh557/packetmail'],
|
|
19
|
+
'input': 'An IP address MISP attribute.',
|
|
20
|
+
'output': 'Text describing additional information about the input after a query on the IPRep API.',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
moduleconfig = ['apikey']
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def handler(q=False):
|
|
27
|
+
if q is False:
|
|
28
|
+
return False
|
|
29
|
+
request = json.loads(q)
|
|
30
|
+
if request.get('ip-src'):
|
|
31
|
+
toquery = request['ip-src']
|
|
32
|
+
elif request.get('ip-dst'):
|
|
33
|
+
toquery = request['ip-dst']
|
|
34
|
+
else:
|
|
35
|
+
misperrors['error'] = "Unsupported attributes type"
|
|
36
|
+
return misperrors
|
|
37
|
+
|
|
38
|
+
if not request.get('config') and not request['config'].get('apikey'):
|
|
39
|
+
misperrors['error'] = 'IPRep api key is missing'
|
|
40
|
+
return misperrors
|
|
41
|
+
|
|
42
|
+
err, rep = parse_iprep(toquery, request['config'].get('apikey'))
|
|
43
|
+
if len(err) > 0:
|
|
44
|
+
misperrors['error'] = ','.join(err)
|
|
45
|
+
return misperrors
|
|
46
|
+
return {'results': rep}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parse_iprep(ip, api):
|
|
50
|
+
meta_fields = ['origin', 'Query_Time', 'created_on', 'IP_Lookup_History', 'IPs_in_collection', '_id', 'disclaimer',
|
|
51
|
+
'MaxMind_Free_GeoIP', 'Unique_Lookups', 'query_result']
|
|
52
|
+
rep = []
|
|
53
|
+
err = []
|
|
54
|
+
full_text = ''
|
|
55
|
+
url = 'https://www.packetmail.net/iprep.php/%s' % ip
|
|
56
|
+
try:
|
|
57
|
+
data = requests.get(url, params={'apikey': api}).json()
|
|
58
|
+
except Exception:
|
|
59
|
+
return ['Error pulling data'], rep
|
|
60
|
+
# print '%s' % data
|
|
61
|
+
for name, val in data.items():
|
|
62
|
+
if name not in meta_fields:
|
|
63
|
+
try:
|
|
64
|
+
context = val['context']
|
|
65
|
+
if type(context) is list:
|
|
66
|
+
if context[0].get('alert'):
|
|
67
|
+
context = ','.join([hit['alert']['signature'] for hit in context])
|
|
68
|
+
elif context[0].get('signature'):
|
|
69
|
+
context = ','.join([hit['signature'] for hit in context])
|
|
70
|
+
elif context[0].get('target_port') and context[0].get('protocol'):
|
|
71
|
+
context = ','.join(
|
|
72
|
+
['Port Attacked: %s %s' % (hit['target_port'], hit['protocol']) for hit in context])
|
|
73
|
+
elif context[0].get('phishing_kit') and context[0].get('url'):
|
|
74
|
+
context = ','.join(['%s (%s)' % (hit['phishing_kit'], hit['url']) for hit in context])
|
|
75
|
+
else:
|
|
76
|
+
context = ';'.join(['%s: %s' % (k, v) for k, v in context[0].items()])
|
|
77
|
+
|
|
78
|
+
if val.get('special_note'):
|
|
79
|
+
context += '; ' + val['special_note']
|
|
80
|
+
|
|
81
|
+
misp_val = context
|
|
82
|
+
full_text += '\n%s' % context
|
|
83
|
+
misp_comment = 'IPRep Source %s: %s' % (name, val['last_seen'])
|
|
84
|
+
rep.append({'types': mispattributes['output'], 'categories': ['External analysis'], 'values': misp_val, 'comment': misp_comment})
|
|
85
|
+
except Exception:
|
|
86
|
+
err.append('Error parsing source: %s' % name)
|
|
87
|
+
|
|
88
|
+
rep.append({'types': ['freetext'], 'values': full_text, 'comment': 'Free text import of IPRep'})
|
|
89
|
+
return err, rep
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def introspection():
|
|
93
|
+
return mispattributes
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def version():
|
|
97
|
+
moduleinfo['config'] = moduleconfig
|
|
98
|
+
return moduleinfo
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env python\
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from jinja2.sandbox import SandboxedEnvironment
|
|
5
|
+
|
|
6
|
+
misperrors = {'error': 'Error'}
|
|
7
|
+
mispattributes = {'input': ['text'], 'output': ['text']}
|
|
8
|
+
moduleinfo = {
|
|
9
|
+
'version': '0.1',
|
|
10
|
+
'author': 'Sami Mokaddem',
|
|
11
|
+
'description': 'Render the template with the data passed',
|
|
12
|
+
'module-type': ['expansion'],
|
|
13
|
+
'name': 'Ninja Template Rendering',
|
|
14
|
+
'logo': '',
|
|
15
|
+
'requirements': [],
|
|
16
|
+
'features': '',
|
|
17
|
+
'references': [],
|
|
18
|
+
'input': '',
|
|
19
|
+
'output': '',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
default_template = '- Default template -'
|
|
23
|
+
|
|
24
|
+
def renderTemplate(data, template=default_template):
|
|
25
|
+
env = SandboxedEnvironment()
|
|
26
|
+
return env.from_string(template).render(data)
|
|
27
|
+
|
|
28
|
+
def handler(q=False):
|
|
29
|
+
if q is False:
|
|
30
|
+
return False
|
|
31
|
+
request = json.loads(q)
|
|
32
|
+
if request.get('text'):
|
|
33
|
+
data = request['text']
|
|
34
|
+
else:
|
|
35
|
+
return False
|
|
36
|
+
data = json.loads(data)
|
|
37
|
+
template = data.get('template', default_template)
|
|
38
|
+
templateData = data.get('data', {})
|
|
39
|
+
try:
|
|
40
|
+
rendered = renderTemplate(templateData, template)
|
|
41
|
+
except TypeError:
|
|
42
|
+
rendered = ''
|
|
43
|
+
|
|
44
|
+
r = {'results': [{'types': mispattributes['output'],
|
|
45
|
+
'values':[rendered]}]}
|
|
46
|
+
return r
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def introspection():
|
|
50
|
+
return mispattributes
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def version():
|
|
54
|
+
return moduleinfo
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import jbxapi
|
|
3
|
+
import json
|
|
4
|
+
from . import check_input_attribute, checking_error, standard_error_message
|
|
5
|
+
from joe_parser import JoeParser
|
|
6
|
+
|
|
7
|
+
misperrors = {'error': 'Error'}
|
|
8
|
+
|
|
9
|
+
inputSource = ['link']
|
|
10
|
+
|
|
11
|
+
moduleinfo = {
|
|
12
|
+
'version': '0.2',
|
|
13
|
+
'author': 'Christian Studer',
|
|
14
|
+
'description': 'Query Joe Sandbox API with a submission url to get the json report and extract its data that is parsed and converted into MISP attributes and objects.',
|
|
15
|
+
'module-type': ['expansion'],
|
|
16
|
+
'name': 'Joe Sandbox Import',
|
|
17
|
+
'logo': 'joesandbox.png',
|
|
18
|
+
'requirements': ['jbxapi: Joe Sandbox API python3 library'],
|
|
19
|
+
'features': "Module using the new format of modules able to return attributes and objects.\n\nThe module returns the same results as the import module [joe_import](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/import_mod/joe_import.py) taking directly the json report as input.\n\nEven if the introspection will allow all kinds of links to call this module, obviously only the ones presenting a sample or url submission in the Joe Sandbox API will return results.\n\nTo make it work you will need to fill the 'apikey' configuration with your Joe Sandbox API key and provide a valid link as input.",
|
|
20
|
+
'references': ['https://www.joesecurity.org', 'https://www.joesandbox.com/'],
|
|
21
|
+
'input': 'Link of a Joe Sandbox sample or url submission.',
|
|
22
|
+
'output': 'MISP attributes & objects parsed from the analysis report.',
|
|
23
|
+
}
|
|
24
|
+
moduleconfig = ['apiurl', 'apikey', 'import_executable', 'import_mitre_attack']
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def handler(q=False):
|
|
28
|
+
if q is False:
|
|
29
|
+
return False
|
|
30
|
+
request = json.loads(q)
|
|
31
|
+
apiurl = request['config'].get('apiurl') or 'https://jbxcloud.joesecurity.org/api'
|
|
32
|
+
apikey = request['config'].get('apikey')
|
|
33
|
+
parser_config = {
|
|
34
|
+
"import_executable": request["config"].get('import_executable', "false") == "true",
|
|
35
|
+
"mitre_attack": request["config"].get('import_mitre_attack', "false") == "true",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if not apikey:
|
|
39
|
+
return {'error': 'No API key provided'}
|
|
40
|
+
|
|
41
|
+
if not request.get('attribute') or not check_input_attribute(request['attribute'], requirements=('type', 'value')):
|
|
42
|
+
return {'error': f'{standard_error_message}, {checking_error} that is the link to the Joe Sandbox report.'}
|
|
43
|
+
if request['attribute']['type'] != 'link':
|
|
44
|
+
return {'error': 'Unsupported attribute type.'}
|
|
45
|
+
url = request['attribute']['value']
|
|
46
|
+
if "/submissions/" not in url:
|
|
47
|
+
return {'error': "The URL does not point to a Joe Sandbox analysis."}
|
|
48
|
+
|
|
49
|
+
submission_id = url.split('/')[-1] # The URL has the format https://example.net/submissions/12345
|
|
50
|
+
joe = jbxapi.JoeSandbox(apiurl=apiurl, apikey=apikey, user_agent='MISP joesandbox_query')
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
joe_info = joe.submission_info(submission_id)
|
|
54
|
+
except jbxapi.ApiError as e:
|
|
55
|
+
return {'error': str(e)}
|
|
56
|
+
|
|
57
|
+
if joe_info["status"] != "finished":
|
|
58
|
+
return {'error': "The analysis has not finished yet."}
|
|
59
|
+
|
|
60
|
+
if joe_info['most_relevant_analysis'] is None:
|
|
61
|
+
return {'error': "No analysis belongs to this submission."}
|
|
62
|
+
|
|
63
|
+
analysis_webid = joe_info['most_relevant_analysis']['webid']
|
|
64
|
+
|
|
65
|
+
joe_parser = JoeParser(parser_config)
|
|
66
|
+
joe_data = json.loads(joe.analysis_download(analysis_webid, 'jsonfixed')[1])
|
|
67
|
+
joe_parser.parse_data(joe_data['analysis'])
|
|
68
|
+
joe_parser.finalize_results()
|
|
69
|
+
|
|
70
|
+
return {'results': joe_parser.results}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def introspection():
|
|
74
|
+
modulesetup = {}
|
|
75
|
+
try:
|
|
76
|
+
userConfig
|
|
77
|
+
modulesetup['userConfig'] = userConfig
|
|
78
|
+
except NameError:
|
|
79
|
+
pass
|
|
80
|
+
try:
|
|
81
|
+
inputSource
|
|
82
|
+
modulesetup['input'] = inputSource
|
|
83
|
+
except NameError:
|
|
84
|
+
pass
|
|
85
|
+
modulesetup['format'] = 'misp_standard'
|
|
86
|
+
return modulesetup
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def version():
|
|
90
|
+
moduleinfo['config'] = moduleconfig
|
|
91
|
+
return moduleinfo
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import jbxapi
|
|
2
|
+
import base64
|
|
3
|
+
import io
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
import zipfile
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
from urllib.parse import urljoin
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
log.setLevel(logging.DEBUG)
|
|
15
|
+
sh = logging.StreamHandler(sys.stdout)
|
|
16
|
+
sh.setLevel(logging.DEBUG)
|
|
17
|
+
fmt = logging.Formatter(
|
|
18
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
19
|
+
)
|
|
20
|
+
sh.setFormatter(fmt)
|
|
21
|
+
log.addHandler(sh)
|
|
22
|
+
|
|
23
|
+
moduleinfo = {
|
|
24
|
+
'version': '1.0',
|
|
25
|
+
'author': 'Joe Security LLC',
|
|
26
|
+
'description': 'A module to submit files or URLs to Joe Sandbox for an advanced analysis, and return the link of the submission.',
|
|
27
|
+
'module-type': ['expansion', 'hover'],
|
|
28
|
+
'name': 'Joe Sandbox Submit',
|
|
29
|
+
'logo': 'joesandbox.png',
|
|
30
|
+
'requirements': ['jbxapi: Joe Sandbox API python3 library'],
|
|
31
|
+
'features': 'The module requires a Joe Sandbox API key to submit files or URL, and returns the link of the submitted analysis.\n\nIt is then possible, when the analysis is completed, to query the Joe Sandbox API to get the data related to the analysis, using the [joesandbox_query module](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/joesandbox_query.py) directly on this submission link.',
|
|
32
|
+
'references': ['https://www.joesecurity.org', 'https://www.joesandbox.com/'],
|
|
33
|
+
'input': 'Sample, url (or domain) to submit to Joe Sandbox for an advanced analysis.',
|
|
34
|
+
'output': 'Link of the report generated in Joe Sandbox.',
|
|
35
|
+
}
|
|
36
|
+
moduleconfig = [
|
|
37
|
+
"apiurl",
|
|
38
|
+
"apikey",
|
|
39
|
+
"accept-tac",
|
|
40
|
+
"report-cache",
|
|
41
|
+
"systems",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
mispattributes = {
|
|
45
|
+
"input": ["attachment", "malware-sample", "url", "domain"],
|
|
46
|
+
"output": ["link"],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def handler(q=False):
|
|
51
|
+
if q is False:
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
request = json.loads(q)
|
|
55
|
+
|
|
56
|
+
apiurl = request["config"].get("apiurl") or "https://jbxcloud.joesecurity.org/api"
|
|
57
|
+
apikey = request["config"].get("apikey")
|
|
58
|
+
|
|
59
|
+
# systems
|
|
60
|
+
systems = request["config"].get("systems") or ""
|
|
61
|
+
systems = [s.strip() for s in re.split(r"[\s,;]", systems) if s.strip()]
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
accept_tac = _parse_bool(request["config"].get("accept-tac"), "accept-tac")
|
|
65
|
+
report_cache = _parse_bool(request["config"].get("report-cache"), "report-cache")
|
|
66
|
+
except _ParseError as e:
|
|
67
|
+
return {"error": str(e)}
|
|
68
|
+
|
|
69
|
+
params = {
|
|
70
|
+
"report-cache": report_cache,
|
|
71
|
+
"systems": systems,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if not apikey:
|
|
75
|
+
return {"error": "No API key provided"}
|
|
76
|
+
|
|
77
|
+
joe = jbxapi.JoeSandbox(apiurl=apiurl, apikey=apikey, user_agent="MISP joesandbox_submit", accept_tac=accept_tac)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
is_url_submission = "url" in request or "domain" in request
|
|
81
|
+
|
|
82
|
+
if is_url_submission:
|
|
83
|
+
url = request.get("url") or request.get("domain")
|
|
84
|
+
|
|
85
|
+
log.info("Submitting URL: %s", url)
|
|
86
|
+
result = joe.submit_url(url, params=params)
|
|
87
|
+
else:
|
|
88
|
+
if "malware-sample" in request:
|
|
89
|
+
filename = request.get("malware-sample").split("|", 1)[0]
|
|
90
|
+
data = _decode_malware(request["data"], True)
|
|
91
|
+
elif "attachment" in request:
|
|
92
|
+
filename = request["attachment"]
|
|
93
|
+
data = _decode_malware(request["data"], False)
|
|
94
|
+
|
|
95
|
+
data_fp = io.BytesIO(data)
|
|
96
|
+
log.info("Submitting sample: %s", filename)
|
|
97
|
+
result = joe.submit_sample((filename, data_fp), params=params)
|
|
98
|
+
|
|
99
|
+
assert "submission_id" in result
|
|
100
|
+
except jbxapi.JoeException as e:
|
|
101
|
+
return {"error": str(e)}
|
|
102
|
+
|
|
103
|
+
link_to_analysis = urljoin(apiurl, "../submissions/{}".format(result["submission_id"]))
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"results": [{
|
|
107
|
+
"types": "link",
|
|
108
|
+
"categories": "External analysis",
|
|
109
|
+
"values": link_to_analysis,
|
|
110
|
+
}]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def introspection():
|
|
115
|
+
return mispattributes
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def version():
|
|
119
|
+
moduleinfo["config"] = moduleconfig
|
|
120
|
+
return moduleinfo
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _decode_malware(data, is_encrypted):
|
|
124
|
+
data = base64.b64decode(data)
|
|
125
|
+
|
|
126
|
+
if is_encrypted:
|
|
127
|
+
with zipfile.ZipFile(io.BytesIO(data)) as zipf:
|
|
128
|
+
data = zipf.read(zipf.namelist()[0], pwd=b"infected")
|
|
129
|
+
|
|
130
|
+
return data
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class _ParseError(Exception):
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _parse_bool(value, name="bool"):
|
|
138
|
+
if value is None or value == "":
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
if value == "true":
|
|
142
|
+
return True
|
|
143
|
+
|
|
144
|
+
if value == "false":
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
raise _ParseError("Cannot parse {}. Must be 'true' or 'false'".format(name))
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Deprecation notice: this module will be deprecated by December 2021, please use vmware_nsx module.
|
|
4
|
+
|
|
5
|
+
Module (type "expansion") to query a Lastline report from an analysis link.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import lastline_api
|
|
9
|
+
from . import check_input_attribute, checking_error, standard_error_message
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
misperrors = {
|
|
13
|
+
"error": "Error",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
mispattributes = {
|
|
17
|
+
"input": [
|
|
18
|
+
"link",
|
|
19
|
+
],
|
|
20
|
+
"output": ["text"],
|
|
21
|
+
"format": "misp_standard",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
moduleinfo = {
|
|
25
|
+
'version': '0.1',
|
|
26
|
+
'author': 'Stefano Ortolani',
|
|
27
|
+
'description': 'Deprecation notice: this module will be deprecated by December 2021, please use vmware_nsx module.\n\nQuery Lastline with an analysis link and parse the report into MISP attributes and objects.',
|
|
28
|
+
'module-type': ['expansion'],
|
|
29
|
+
'name': 'Lastline Lookup',
|
|
30
|
+
'logo': 'lastline.png',
|
|
31
|
+
'requirements': [],
|
|
32
|
+
'features': 'The module requires a Lastline Portal `username` and `password`.\nThe module uses the new format and it is able to return MISP attributes and objects.\nThe module returns the same results as the [lastline_import](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/import_mod/lastline_import.py) import module.',
|
|
33
|
+
'references': ['https://www.lastline.com'],
|
|
34
|
+
'input': 'Link to a Lastline analysis.',
|
|
35
|
+
'output': 'MISP attributes and objects parsed from the analysis report.',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
moduleconfig = [
|
|
39
|
+
"username",
|
|
40
|
+
"password",
|
|
41
|
+
"verify_ssl",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def introspection():
|
|
46
|
+
return mispattributes
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def version():
|
|
50
|
+
moduleinfo["config"] = moduleconfig
|
|
51
|
+
return moduleinfo
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def handler(q=False):
|
|
55
|
+
if q is False:
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
request = json.loads(q)
|
|
59
|
+
|
|
60
|
+
# Parse the init parameters
|
|
61
|
+
try:
|
|
62
|
+
config = request["config"]
|
|
63
|
+
auth_data = lastline_api.LastlineAbstractClient.get_login_params_from_dict(config)
|
|
64
|
+
if not request.get('attribute') or not check_input_attribute(request['attribute'], requirements=('type', 'value')):
|
|
65
|
+
return {'error': f'{standard_error_message}, {checking_error} that is the link to a Lastline analysis.'}
|
|
66
|
+
analysis_link = request['attribute']['value']
|
|
67
|
+
# The API url changes based on the analysis link host name
|
|
68
|
+
api_url = lastline_api.get_portal_url_from_task_link(analysis_link)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
misperrors["error"] = "Error parsing configuration: {}".format(e)
|
|
71
|
+
return misperrors
|
|
72
|
+
|
|
73
|
+
# Parse the call parameters
|
|
74
|
+
try:
|
|
75
|
+
task_uuid = lastline_api.get_uuid_from_task_link(analysis_link)
|
|
76
|
+
except (KeyError, ValueError) as e:
|
|
77
|
+
misperrors["error"] = "Error processing input parameters: {}".format(e)
|
|
78
|
+
return misperrors
|
|
79
|
+
|
|
80
|
+
# Make the API calls
|
|
81
|
+
try:
|
|
82
|
+
api_client = lastline_api.PortalClient(api_url, auth_data, verify_ssl=config.get('verify_ssl', True).lower() in ("true"))
|
|
83
|
+
response = api_client.get_progress(task_uuid)
|
|
84
|
+
if response.get("completed") != 1:
|
|
85
|
+
raise ValueError("Analysis is not finished yet.")
|
|
86
|
+
|
|
87
|
+
response = api_client.get_result(task_uuid)
|
|
88
|
+
if not response:
|
|
89
|
+
raise ValueError("Analysis report is empty.")
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
misperrors["error"] = "Error issuing the API call: {}".format(e)
|
|
93
|
+
return misperrors
|
|
94
|
+
|
|
95
|
+
# Parse and return
|
|
96
|
+
result_parser = lastline_api.LastlineResultBaseParser()
|
|
97
|
+
result_parser.parse(analysis_link, response)
|
|
98
|
+
|
|
99
|
+
event = result_parser.misp_event
|
|
100
|
+
event_dictionary = json.loads(event.to_json())
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
"results": {
|
|
104
|
+
key: event_dictionary[key]
|
|
105
|
+
for key in ('Attribute', 'Object', 'Tag')
|
|
106
|
+
if (key in event and event[key])
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
"""Test querying information from a Lastline analysis link."""
|
|
113
|
+
import argparse
|
|
114
|
+
import configparser
|
|
115
|
+
|
|
116
|
+
parser = argparse.ArgumentParser()
|
|
117
|
+
parser.add_argument("-c", "--config-file", dest="config_file")
|
|
118
|
+
parser.add_argument("-s", "--section-name", dest="section_name")
|
|
119
|
+
args = parser.parse_args()
|
|
120
|
+
c = configparser.ConfigParser()
|
|
121
|
+
c.read(args.config_file)
|
|
122
|
+
a = lastline_api.LastlineAbstractClient.get_login_params_from_conf(c, args.section_name)
|
|
123
|
+
|
|
124
|
+
j = json.dumps(
|
|
125
|
+
{
|
|
126
|
+
"config": a,
|
|
127
|
+
"attribute": {
|
|
128
|
+
"value": (
|
|
129
|
+
"https://user.lastline.com/portal#/analyst/task/"
|
|
130
|
+
"1fcbcb8f7fb400100772d6a7b62f501b/overview"
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
print(json.dumps(handler(j), indent=4, sort_keys=True))
|
|
136
|
+
|
|
137
|
+
j = json.dumps(
|
|
138
|
+
{
|
|
139
|
+
"config": a,
|
|
140
|
+
"attribute": {
|
|
141
|
+
"value": (
|
|
142
|
+
"https://user.lastline.com/portal#/analyst/task/"
|
|
143
|
+
"f3c0ae115d51001017ff8da768fa6049/overview"
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
print(json.dumps(handler(j), indent=4, sort_keys=True))
|