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,552 @@
|
|
|
1
|
+
'''
|
|
2
|
+
import
|
|
3
|
+
define mandatory
|
|
4
|
+
|
|
5
|
+
'''
|
|
6
|
+
import json
|
|
7
|
+
import base64
|
|
8
|
+
import re
|
|
9
|
+
import zipfile
|
|
10
|
+
import ipaddress
|
|
11
|
+
import io
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
misperrors = {'error': 'Error'}
|
|
15
|
+
userConfig = {}
|
|
16
|
+
inputSource = ['file']
|
|
17
|
+
|
|
18
|
+
moduleinfo = {
|
|
19
|
+
'version': '0.10',
|
|
20
|
+
'author': 'Christophe Vandeplas',
|
|
21
|
+
'description': 'Module to import ThreatAnalyzer archive.zip / analysis.json files.',
|
|
22
|
+
'module-type': ['import'],
|
|
23
|
+
'name': 'ThreadAnalyzer Sandbox Import',
|
|
24
|
+
'logo': '',
|
|
25
|
+
'requirements': [],
|
|
26
|
+
'features': 'The module imports MISP Attributes from a ThreatAnalyzer format file. This file can be either ZIP, or JSON format.\nThere is by the way no special feature for users to make the module work.',
|
|
27
|
+
'references': ['https://www.threattrack.com/malware-analysis.aspx'],
|
|
28
|
+
'input': 'ThreatAnalyzer format file',
|
|
29
|
+
'output': 'MISP Event attributes',
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
moduleconfig = []
|
|
33
|
+
log = logging.getLogger('misp-modules')
|
|
34
|
+
|
|
35
|
+
# FIXME - many hardcoded filters should be migrated to import regexes. See also https://github.com/MISP/MISP/issues/2712
|
|
36
|
+
# DISCLAIMER - This module is to be considered as experimental and needs much fine-tuning.
|
|
37
|
+
# more can be done with what's in the ThreatAnalyzer archive.zip
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def handler(q=False):
|
|
41
|
+
if q is False:
|
|
42
|
+
return False
|
|
43
|
+
results = []
|
|
44
|
+
zip_starts = 'PK'
|
|
45
|
+
request = json.loads(q)
|
|
46
|
+
data = base64.b64decode(request['data'])
|
|
47
|
+
|
|
48
|
+
if data[:len(zip_starts)].decode() == zip_starts:
|
|
49
|
+
with zipfile.ZipFile(io.BytesIO(data), 'r') as zf:
|
|
50
|
+
# unzipped_files = []
|
|
51
|
+
modified_files_mapping = {}
|
|
52
|
+
# pre-process some of the files in the zip
|
|
53
|
+
for zip_file_name in zf.namelist(): # Get all files in the zip file
|
|
54
|
+
# find the filenames of the modified_files
|
|
55
|
+
if re.match(r"Analysis/proc_\d+/modified_files/mapping\.log", zip_file_name):
|
|
56
|
+
with zf.open(zip_file_name, mode='r', pwd=None) as fp:
|
|
57
|
+
file_data = fp.read()
|
|
58
|
+
for line in file_data.decode("utf-8", 'ignore').split('\n'):
|
|
59
|
+
if not line:
|
|
60
|
+
continue
|
|
61
|
+
if line.count('|') == 3:
|
|
62
|
+
l_fname, l_size, l_md5, l_created = line.split('|')
|
|
63
|
+
if line.count('|') == 4:
|
|
64
|
+
l_fname, l_size, l_md5, l_sha256, l_created = line.split('|')
|
|
65
|
+
l_fname = cleanup_filepath(l_fname)
|
|
66
|
+
if l_fname:
|
|
67
|
+
if l_size == 0:
|
|
68
|
+
results.append({'values': l_fname, 'type': 'filename', 'to_ids': True,
|
|
69
|
+
'categories': ['Artifacts dropped', 'Payload delivery'], 'comment': ''})
|
|
70
|
+
else:
|
|
71
|
+
# file is a non empty sample, upload the sample later
|
|
72
|
+
modified_files_mapping[l_md5] = l_fname
|
|
73
|
+
|
|
74
|
+
# now really process the data
|
|
75
|
+
for zip_file_name in zf.namelist(): # Get all files in the zip file
|
|
76
|
+
# print('Processing file: {}'.format(zip_file_name))
|
|
77
|
+
if re.match(r"Analysis/proc_\d+/modified_files/.+\.", zip_file_name) and "mapping.log" not in zip_file_name:
|
|
78
|
+
sample_md5 = zip_file_name.split('/')[-1].split('.')[0]
|
|
79
|
+
if sample_md5 in modified_files_mapping:
|
|
80
|
+
current_sample_filename = modified_files_mapping[sample_md5]
|
|
81
|
+
# print("{} maps to {}".format(sample_md5, current_sample_filename))
|
|
82
|
+
with zf.open(zip_file_name, mode='r', pwd=None) as fp:
|
|
83
|
+
file_data = fp.read()
|
|
84
|
+
results.append({
|
|
85
|
+
'values': current_sample_filename,
|
|
86
|
+
'data': base64.b64encode(file_data).decode(),
|
|
87
|
+
'type': 'malware-sample', 'categories': ['Artifacts dropped', 'Payload delivery'], 'to_ids': True, 'comment': ''})
|
|
88
|
+
|
|
89
|
+
if 'Analysis/analysis.json' in zip_file_name:
|
|
90
|
+
with zf.open(zip_file_name, mode='r', pwd=None) as fp:
|
|
91
|
+
file_data = fp.read()
|
|
92
|
+
analysis_json = json.loads(file_data.decode('utf-8'))
|
|
93
|
+
results += process_analysis_json(analysis_json)
|
|
94
|
+
try:
|
|
95
|
+
sample_filename = analysis_json.get('analysis').get('@filename')
|
|
96
|
+
if sample_filename:
|
|
97
|
+
with zf.open('sample', mode='r', pwd=None) as fp:
|
|
98
|
+
file_data = fp.read()
|
|
99
|
+
results.append({
|
|
100
|
+
'values': sample_filename,
|
|
101
|
+
'data': base64.b64encode(file_data).decode(),
|
|
102
|
+
'type': 'malware-sample', 'categories': ['Payload delivery', 'Artifacts dropped'], 'to_ids': True, 'comment': ''})
|
|
103
|
+
except Exception:
|
|
104
|
+
# no 'sample' in archive, might be an url analysis, just ignore
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
else:
|
|
108
|
+
try:
|
|
109
|
+
results = process_analysis_json(json.loads(data.decode('utf-8')))
|
|
110
|
+
except ValueError:
|
|
111
|
+
log.warning('MISP modules {0} failed: uploaded file is not a zip or json file.'.format(request['module']))
|
|
112
|
+
return {'error': 'Uploaded file is not a zip or json file.'}
|
|
113
|
+
pass
|
|
114
|
+
# keep only unique entries based on the value field
|
|
115
|
+
results = list({v['values']: v for v in results}.values())
|
|
116
|
+
r = {'results': results}
|
|
117
|
+
return r
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def process_analysis_json(analysis_json):
|
|
121
|
+
if 'analysis' in analysis_json and 'processes' in analysis_json['analysis'] and 'process' in analysis_json['analysis']['processes']:
|
|
122
|
+
# if 'analysis' in analysis_json and '@filename' in analysis_json['analysis']:
|
|
123
|
+
# sample['values'] = analysis_json['analysis']['@filename']
|
|
124
|
+
for process in analysis_json['analysis']['processes']['process']:
|
|
125
|
+
# print_json(process)
|
|
126
|
+
if 'connection_section' in process and 'connection' in process['connection_section']:
|
|
127
|
+
# compensate for absurd behavior of the data format: if one entry = immediately the dict, if multiple entries = list containing dicts
|
|
128
|
+
# this will always create a list, even with only one item
|
|
129
|
+
if isinstance(process['connection_section']['connection'], dict):
|
|
130
|
+
process['connection_section']['connection'] = [process['connection_section']['connection']]
|
|
131
|
+
|
|
132
|
+
# iterate over each entry
|
|
133
|
+
for connection_section_connection in process['connection_section']['connection']:
|
|
134
|
+
# compensate for absurd behavior of the data format: if one entry = immediately the dict, if multiple entries = list containing dicts
|
|
135
|
+
# this will always create a list, even with only one item
|
|
136
|
+
for subsection in ['http_command', 'http_header']:
|
|
137
|
+
if isinstance(connection_section_connection[subsection], dict):
|
|
138
|
+
connection_section_connection[subsection] = [connection_section_connection[subsection]]
|
|
139
|
+
|
|
140
|
+
if 'name_to_ip' in connection_section_connection: # TA 6.1 data format
|
|
141
|
+
connection_section_connection['@remote_ip'] = connection_section_connection['name_to_ip']['@result_addresses']
|
|
142
|
+
connection_section_connection['@remote_hostname'] = connection_section_connection['name_to_ip']['@request_name']
|
|
143
|
+
|
|
144
|
+
connection_section_connection['@remote_ip'] = cleanup_ip(connection_section_connection['@remote_ip'])
|
|
145
|
+
connection_section_connection['@remote_hostname'] = cleanup_hostname(connection_section_connection['@remote_hostname'])
|
|
146
|
+
if connection_section_connection['@remote_ip'] and connection_section_connection['@remote_hostname']:
|
|
147
|
+
val = '{}|{}'.format(connection_section_connection['@remote_hostname'],
|
|
148
|
+
connection_section_connection['@remote_ip'])
|
|
149
|
+
# print("connection_section_connection hostname|ip: {}|{} IDS:yes".format(
|
|
150
|
+
# connection_section_connection['@remote_hostname'],
|
|
151
|
+
# connection_section_connection['@remote_ip'])
|
|
152
|
+
# )
|
|
153
|
+
yield({'values': val, 'type': 'domain|ip', 'categories': ['Network activity'], 'to_ids': True, 'comment': ''})
|
|
154
|
+
elif connection_section_connection['@remote_ip']:
|
|
155
|
+
# print("connection_section_connection ip-dst: {} IDS:yes".format(
|
|
156
|
+
# connection_section_connection['@remote_ip'])
|
|
157
|
+
# )
|
|
158
|
+
yield({'values': connection_section_connection['@remote_ip'], 'type': 'ip-dst', 'to_ids': True, 'comment': ''})
|
|
159
|
+
elif connection_section_connection['@remote_hostname']:
|
|
160
|
+
# print("connection_section_connection hostname: {} IDS:yes".format(
|
|
161
|
+
# connection_section_connection['@remote_hostname'])
|
|
162
|
+
# )
|
|
163
|
+
yield({'values': connection_section_connection['@remote_hostname'], 'type': 'hostname', 'to_ids': True, 'comment': ''})
|
|
164
|
+
if 'http_command' in connection_section_connection:
|
|
165
|
+
for http_command in connection_section_connection['http_command']:
|
|
166
|
+
# print('connection_section_connection HTTP COMMAND: {}\t{}'.format(
|
|
167
|
+
# connection_section_connection['http_command']['@method'], # comment
|
|
168
|
+
# connection_section_connection['http_command']['@url']) # url
|
|
169
|
+
# )
|
|
170
|
+
val = cleanup_url(http_command['@url'])
|
|
171
|
+
if val:
|
|
172
|
+
yield({'values': val, 'type': 'url', 'categories': ['Network activity'], 'to_ids': True, 'comment': http_command['@method']})
|
|
173
|
+
|
|
174
|
+
if 'http_header' in connection_section_connection:
|
|
175
|
+
for http_header in connection_section_connection['http_header']:
|
|
176
|
+
if 'User-Agent:' in http_header['@header']:
|
|
177
|
+
val = http_header['@header'][len('User-Agent: '):]
|
|
178
|
+
yield({'values': val, 'type': 'user-agent', 'categories': ['Network activity'], 'to_ids': False, 'comment': ''})
|
|
179
|
+
elif 'Host:' in http_header['@header']:
|
|
180
|
+
val = http_header['@header'][len('Host: '):]
|
|
181
|
+
if ':' in val:
|
|
182
|
+
try:
|
|
183
|
+
val_port = int(val.split(':')[1])
|
|
184
|
+
except ValueError:
|
|
185
|
+
val_port = False
|
|
186
|
+
val_hostname = cleanup_hostname(val.split(':')[0])
|
|
187
|
+
val_ip = cleanup_ip(val.split(':')[0])
|
|
188
|
+
if val_hostname and val_port:
|
|
189
|
+
val_combined = '{}|{}'.format(val_hostname, val_port)
|
|
190
|
+
# print({'values': val_combined, 'type': 'hostname|port', 'to_ids': True, 'comment': ''})
|
|
191
|
+
yield({'values': val_combined, 'type': 'hostname|port', 'categories': ['Network activity'], 'to_ids': True, 'comment': ''})
|
|
192
|
+
elif val_ip and val_port:
|
|
193
|
+
val_combined = '{}|{}'.format(val_ip, val_port)
|
|
194
|
+
# print({'values': val_combined, 'type': 'ip-dst|port', 'to_ids': True, 'comment': ''})
|
|
195
|
+
yield({'values': val_combined, 'type': 'ip-dst|port', 'to_ids': True, 'comment': ''})
|
|
196
|
+
else:
|
|
197
|
+
continue
|
|
198
|
+
val_hostname = cleanup_hostname(val)
|
|
199
|
+
if val_hostname:
|
|
200
|
+
# print({'values': val_hostname, 'type': 'hostname', 'to_ids': True, 'comment': ''})
|
|
201
|
+
yield({'values': val_hostname, 'type': 'hostname', 'to_ids': True, 'comment': ''})
|
|
202
|
+
else:
|
|
203
|
+
# LATER header not processed
|
|
204
|
+
pass
|
|
205
|
+
if 'filesystem_section' in process and 'create_file' in process['filesystem_section']:
|
|
206
|
+
for filesystem_section_create_file in process['filesystem_section']['create_file']:
|
|
207
|
+
# first skip some items
|
|
208
|
+
if filesystem_section_create_file['@create_disposition'] in {'FILE_OPEN_IF'}:
|
|
209
|
+
continue
|
|
210
|
+
# FIXME - this section is probably not needed considering the 'stored_files stored_created_file' section we process later.
|
|
211
|
+
# print('CREATE FILE: {}\t{}'.format(
|
|
212
|
+
# filesystem_section_create_file['@srcfile'], # filename
|
|
213
|
+
# filesystem_section_create_file['@create_disposition']) # comment - use this to filter out cases
|
|
214
|
+
# )
|
|
215
|
+
|
|
216
|
+
if 'networkoperation_section' in process and 'dns_request_by_addr' in process['networkoperation_section']:
|
|
217
|
+
for networkoperation_section_dns_request_by_addr in process['networkoperation_section']['dns_request_by_addr']:
|
|
218
|
+
# FIXME - it's unclear what this section is for.
|
|
219
|
+
# TODO filter this
|
|
220
|
+
# print('DNS REQUEST: {}\t{}'.format(
|
|
221
|
+
# networkoperation_section_dns_request_by_addr['@request_address'], # ip-dst
|
|
222
|
+
# networkoperation_section_dns_request_by_addr['@result_name']) # hostname
|
|
223
|
+
# ) # => NOT hostname|ip
|
|
224
|
+
pass
|
|
225
|
+
if 'networkoperation_section' in process and 'dns_request_by_name' in process['networkoperation_section']:
|
|
226
|
+
for networkoperation_section_dns_request_by_name in process['networkoperation_section']['dns_request_by_name']:
|
|
227
|
+
networkoperation_section_dns_request_by_name['@request_name'] = cleanup_hostname(networkoperation_section_dns_request_by_name['@request_name'].rstrip('.'))
|
|
228
|
+
networkoperation_section_dns_request_by_name['@result_addresses'] = cleanup_ip(networkoperation_section_dns_request_by_name['@result_addresses'])
|
|
229
|
+
if networkoperation_section_dns_request_by_name['@request_name'] and networkoperation_section_dns_request_by_name['@result_addresses']:
|
|
230
|
+
val = '{}|{}'.format(networkoperation_section_dns_request_by_name['@request_name'],
|
|
231
|
+
networkoperation_section_dns_request_by_name['@result_addresses'])
|
|
232
|
+
# print("networkoperation_section_dns_request_by_name hostname|ip: {}|{} IDS:yes".format(
|
|
233
|
+
# networkoperation_section_dns_request_by_name['@request_name'],
|
|
234
|
+
# networkoperation_section_dns_request_by_name['@result_addresses'])
|
|
235
|
+
# )
|
|
236
|
+
yield({'values': val, 'type': 'domain|ip', 'categories': ['Network activity'], 'to_ids': True, 'comment': ''})
|
|
237
|
+
elif networkoperation_section_dns_request_by_name['@request_name']:
|
|
238
|
+
# print("networkoperation_section_dns_request_by_name hostname: {} IDS:yes".format(
|
|
239
|
+
# networkoperation_section_dns_request_by_name['@request_name'])
|
|
240
|
+
# )
|
|
241
|
+
yield({'values': networkoperation_section_dns_request_by_name['@request_name'], 'type': 'hostname', 'to_ids': True, 'comment': ''})
|
|
242
|
+
elif networkoperation_section_dns_request_by_name['@result_addresses']:
|
|
243
|
+
# this happens when the IP is both in the request_name and result_address.
|
|
244
|
+
# print("networkoperation_section_dns_request_by_name hostname: {} IDS:yes".format(
|
|
245
|
+
# networkoperation_section_dns_request_by_name['@result_addresses'])
|
|
246
|
+
# )
|
|
247
|
+
yield({'values': networkoperation_section_dns_request_by_name['@result_addresses'], 'type': 'ip-dst', 'to_ids': True, 'comment': ''})
|
|
248
|
+
|
|
249
|
+
if 'networkpacket_section' in process and 'connect_to_computer' in process['networkpacket_section']:
|
|
250
|
+
for networkpacket_section_connect_to_computer in process['networkpacket_section']['connect_to_computer']:
|
|
251
|
+
networkpacket_section_connect_to_computer['@remote_hostname'] = cleanup_hostname(networkpacket_section_connect_to_computer['@remote_hostname'])
|
|
252
|
+
networkpacket_section_connect_to_computer['@remote_ip'] = cleanup_ip(networkpacket_section_connect_to_computer['@remote_ip'])
|
|
253
|
+
if networkpacket_section_connect_to_computer['@remote_hostname'] and networkpacket_section_connect_to_computer['@remote_ip']:
|
|
254
|
+
# print("networkpacket_section_connect_to_computer hostname|ip: {}|{} IDS:yes COMMENT:port {}".format(
|
|
255
|
+
# networkpacket_section_connect_to_computer['@remote_hostname'],
|
|
256
|
+
# networkpacket_section_connect_to_computer['@remote_ip'],
|
|
257
|
+
# networkpacket_section_connect_to_computer['@remote_port'])
|
|
258
|
+
# )
|
|
259
|
+
val_combined = "{}|{}".format(networkpacket_section_connect_to_computer['@remote_hostname'], networkpacket_section_connect_to_computer['@remote_ip'])
|
|
260
|
+
yield({'values': val_combined, 'type': 'domain|ip', 'to_ids': True, 'comment': ''})
|
|
261
|
+
elif networkpacket_section_connect_to_computer['@remote_hostname']:
|
|
262
|
+
# print("networkpacket_section_connect_to_computer hostname: {} IDS:yes COMMENT:port {}".format(
|
|
263
|
+
# networkpacket_section_connect_to_computer['@remote_hostname'],
|
|
264
|
+
# networkpacket_section_connect_to_computer['@remote_port'])
|
|
265
|
+
# )
|
|
266
|
+
val_combined = "{}|{}".format(networkpacket_section_connect_to_computer['@remote_hostname'], networkpacket_section_connect_to_computer['@remote_port'])
|
|
267
|
+
yield({'values': val_combined, 'type': 'hostname|port', 'categories': ['Network activity'], 'to_ids': True, 'comment': ''})
|
|
268
|
+
elif networkpacket_section_connect_to_computer['@remote_ip']:
|
|
269
|
+
# print("networkpacket_section_connect_to_computer ip-dst: {} IDS:yes COMMENT:port {}".format(
|
|
270
|
+
# networkpacket_section_connect_to_computer['@remote_ip'],
|
|
271
|
+
# networkpacket_section_connect_to_computer['@remote_port'])
|
|
272
|
+
# )
|
|
273
|
+
val_combined = "{}|{}".format(networkpacket_section_connect_to_computer['@remote_ip'], networkpacket_section_connect_to_computer['@remote_port'])
|
|
274
|
+
yield({'values': val_combined, 'type': 'ip-dst|port', 'to_ids': True, 'comment': ''})
|
|
275
|
+
|
|
276
|
+
if 'registry_section' in process and 'create_key' in process['registry_section']:
|
|
277
|
+
# FIXME this is a complicated section, together with the 'set_value'.
|
|
278
|
+
# it looks like this section is not ONLY about creating registry keys,
|
|
279
|
+
# more about accessing a handle to keys (with specific permissions)
|
|
280
|
+
# maybe we don't want to keep this, in favor of 'set_value'
|
|
281
|
+
for create_key in process['registry_section']['create_key']:
|
|
282
|
+
# print('REG CREATE: {}\t{}'.format(
|
|
283
|
+
# create_key['@desired_access'],
|
|
284
|
+
# create_key['@key_name']))
|
|
285
|
+
pass
|
|
286
|
+
if 'registry_section' in process and 'delete_key' in process['registry_section']:
|
|
287
|
+
# LATER we probably don't want to keep this. Much pollution.
|
|
288
|
+
# Maybe for later once we have filtered out this.
|
|
289
|
+
for delete_key in process['registry_section']['delete_key']:
|
|
290
|
+
# print('REG DELETE: {}'.format(
|
|
291
|
+
# delete_key['@key_name'])
|
|
292
|
+
# )
|
|
293
|
+
pass
|
|
294
|
+
if 'registry_section' in process and 'set_value' in process['registry_section']:
|
|
295
|
+
# FIXME this is a complicated section, together with the 'create_key'.
|
|
296
|
+
for set_value in process['registry_section']['set_value']:
|
|
297
|
+
# '@data_type' == 'REG_BINARY',
|
|
298
|
+
# '@data_type' == 'REG_DWORD',
|
|
299
|
+
# '@data_type' == 'REG_EXPAND_SZ',
|
|
300
|
+
# '@data_type' == 'REG_MULTI_SZ',
|
|
301
|
+
# '@data_type' == 'REG_NONE',
|
|
302
|
+
# '@data_type' == 'REG_QWORD',
|
|
303
|
+
# '@data_type' == 'REG_SZ',
|
|
304
|
+
regkey = cleanup_regkey("{}\\{}".format(set_value['@key_name'], set_value['@value_name']))
|
|
305
|
+
regdata = cleanup_regdata(set_value.get('@data'))
|
|
306
|
+
if not regkey:
|
|
307
|
+
continue
|
|
308
|
+
if set_value['@data_size'] == '0' or not regdata:
|
|
309
|
+
# print('registry_section set_value REG SET: {}\t{}\t{}'.format(
|
|
310
|
+
# set_value['@data_type'],
|
|
311
|
+
# set_value['@key_name'],
|
|
312
|
+
# set_value['@value_name'])
|
|
313
|
+
# )
|
|
314
|
+
yield({'values': regkey, 'type': 'regkey', 'to_ids': True,
|
|
315
|
+
'categories': ['External analysis', 'Persistence mechanism', 'Artifacts dropped'], 'comment': set_value['@data_type']})
|
|
316
|
+
else:
|
|
317
|
+
try:
|
|
318
|
+
# unicode fun...
|
|
319
|
+
# print('registry_section set_value REG SET: {}\t{}\t{}\t{}'.format(
|
|
320
|
+
# set_value['@data_type'],
|
|
321
|
+
# set_value['@key_name'],
|
|
322
|
+
# set_value['@value_name'],
|
|
323
|
+
# set_value['@data'])
|
|
324
|
+
# )
|
|
325
|
+
val = "{}|{}".format(regkey, regdata)
|
|
326
|
+
yield({'values': val, 'type': 'regkey|value', 'to_ids': True,
|
|
327
|
+
'categories': ['External analysis', 'Persistence mechanism', 'Artifacts dropped'], 'comment': set_value['@data_type']})
|
|
328
|
+
except Exception as e:
|
|
329
|
+
print("EXCEPTION registry_section {}".format(e))
|
|
330
|
+
# TODO - maybe we want to handle these later, or not...
|
|
331
|
+
pass
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
if 'stored_files' in process and 'stored_created_file' in process['stored_files']:
|
|
335
|
+
for stored_created_file in process['stored_files']['stored_created_file']:
|
|
336
|
+
stored_created_file['@filename'] = cleanup_filepath(stored_created_file['@filename'])
|
|
337
|
+
if stored_created_file['@filename']:
|
|
338
|
+
if stored_created_file['@filesize'] != '0':
|
|
339
|
+
val = '{}|{}'.format(stored_created_file['@filename'], stored_created_file['@md5'])
|
|
340
|
+
# print("stored_created_file filename|md5: {}|{} IDS:yes".format(
|
|
341
|
+
# stored_created_file['@filename'], # filename
|
|
342
|
+
# stored_created_file['@md5']) # md5
|
|
343
|
+
# ) # => filename|md5
|
|
344
|
+
yield({'values': val, 'type': 'filename|md5', 'to_ids': True,
|
|
345
|
+
'categories': ['Artifacts dropped', 'Payload delivery'], 'comment': ''})
|
|
346
|
+
|
|
347
|
+
else:
|
|
348
|
+
# print("stored_created_file filename: {} IDS:yes".format(
|
|
349
|
+
# stored_created_file['@filename']) # filename
|
|
350
|
+
# ) # => filename
|
|
351
|
+
yield({'values': stored_created_file['@filename'],
|
|
352
|
+
'type': 'filename', 'to_ids': True,
|
|
353
|
+
'categories': ['Artifacts dropped', 'Payload delivery'], 'comment': ''})
|
|
354
|
+
|
|
355
|
+
if 'stored_files' in process and 'stored_modified_file' in process['stored_files']:
|
|
356
|
+
for stored_modified_file in process['stored_files']['stored_modified_file']:
|
|
357
|
+
stored_modified_file['@filename'] = cleanup_filepath(stored_modified_file['@filename'])
|
|
358
|
+
if stored_modified_file['@filename']:
|
|
359
|
+
if stored_modified_file['@filesize'] != '0':
|
|
360
|
+
val = '{}|{}'.format(stored_modified_file['@filename'], stored_modified_file['@md5'])
|
|
361
|
+
# print("stored_modified_file MODIFY FILE: {}\t{}".format(
|
|
362
|
+
# stored_modified_file['@filename'], # filename
|
|
363
|
+
# stored_modified_file['@md5']) # md5
|
|
364
|
+
# ) # => filename|md5
|
|
365
|
+
yield({'values': val, 'type': 'filename|md5', 'to_ids': True,
|
|
366
|
+
'categories': ['Artifacts dropped', 'Payload delivery'],
|
|
367
|
+
'comment': 'modified'})
|
|
368
|
+
else:
|
|
369
|
+
# print("stored_modified_file MODIFY FILE: {}\t{}".format(
|
|
370
|
+
# stored_modified_file['@filename']) # filename
|
|
371
|
+
# ) # => filename
|
|
372
|
+
yield({'values': stored_modified_file['@filename'], 'type': 'filename', 'to_ids': True,
|
|
373
|
+
'categories': ['Artifacts dropped', 'Payload delivery'],
|
|
374
|
+
'comment': 'modified'})
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def add_file(filename, results, hash, index, filedata=None):
|
|
378
|
+
pass
|
|
379
|
+
# results.append({'values': filename, 'data': "{}|{}".format(filename, filedata.decode()), 'type': 'malware-sample',
|
|
380
|
+
# 'categories': ['Artifacts dropped', 'Payload delivery']})
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def add_file_zip():
|
|
384
|
+
# if 'malware-sample' in request:
|
|
385
|
+
# sample_filename = request.get("malware-sample").split("|", 1)[0]
|
|
386
|
+
# data = base64.b64decode(data)
|
|
387
|
+
# fl = io.BytesIO(data)
|
|
388
|
+
# zf = zipfile.ZipFile(fl)
|
|
389
|
+
# sample_hashname = zf.namelist()[0]
|
|
390
|
+
# data = zf.read(sample_hashname, b"infected")
|
|
391
|
+
# zf.close()
|
|
392
|
+
pass
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def print_json(data):
|
|
396
|
+
print(json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')))
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def list_in_string(lst, data, regex=False):
|
|
400
|
+
for item in lst:
|
|
401
|
+
if regex:
|
|
402
|
+
if re.search(item, data, flags=re.IGNORECASE):
|
|
403
|
+
return True
|
|
404
|
+
else:
|
|
405
|
+
if item in data:
|
|
406
|
+
return True
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def cleanup_ip(item):
|
|
410
|
+
# you should exclude private IP ranges via import regexes
|
|
411
|
+
noise_substrings = {
|
|
412
|
+
'224.0.0.',
|
|
413
|
+
'127.0.0.',
|
|
414
|
+
'8.8.8.8',
|
|
415
|
+
'8.8.4.4',
|
|
416
|
+
'0.0.0.0',
|
|
417
|
+
'NONE'
|
|
418
|
+
}
|
|
419
|
+
if list_in_string(noise_substrings, item):
|
|
420
|
+
return None
|
|
421
|
+
try:
|
|
422
|
+
ipaddress.ip_address(item)
|
|
423
|
+
return item
|
|
424
|
+
except ValueError:
|
|
425
|
+
return None
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def cleanup_hostname(item):
|
|
429
|
+
noise_substrings = {
|
|
430
|
+
'wpad',
|
|
431
|
+
'teredo.ipv6.microsoft.com',
|
|
432
|
+
'WIN7SP1-x64-UNP'
|
|
433
|
+
}
|
|
434
|
+
# take away common known bad
|
|
435
|
+
if list_in_string(noise_substrings, item):
|
|
436
|
+
return None
|
|
437
|
+
# eliminate IP addresses
|
|
438
|
+
try:
|
|
439
|
+
ipaddress.ip_address(item)
|
|
440
|
+
except ValueError:
|
|
441
|
+
# this is not an IP, so continue
|
|
442
|
+
return item
|
|
443
|
+
return None
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def cleanup_url(item):
|
|
447
|
+
if item in ['/']:
|
|
448
|
+
return None
|
|
449
|
+
return item
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def cleanup_filepath(item):
|
|
453
|
+
noise_substrings = {
|
|
454
|
+
'\\AppData\\Local\\GDIPFONTCACHEV1.DAT',
|
|
455
|
+
'\\AppData\\Local\\Microsoft\\Internet Explorer\\DOMStore\\',
|
|
456
|
+
'\\AppData\\Local\\Microsoft\\Internet Explorer\\Recovery\\High\\',
|
|
457
|
+
'\\AppData\\Local\\Microsoft\\Windows\\Caches\\',
|
|
458
|
+
'\\AppData\\Local\\Microsoft\\Windows\\Explorer\\thumbcache',
|
|
459
|
+
'\\AppData\\Local\\Microsoft\\Windows\\History\\History.',
|
|
460
|
+
'\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files\\Content.',
|
|
461
|
+
'\\AppData\\Local\\Microsoft\\Windows\\WebCache\\',
|
|
462
|
+
'\\AppData\\Local\\Temp\\.*tmp$',
|
|
463
|
+
'\\AppData\\LocalLow\\Microsoft\\CryptnetUrlCache\\',
|
|
464
|
+
'\\AppData\\LocalLow\\Microsoft\\Internet Explorer\\Services\\search_',
|
|
465
|
+
'\\AppData\\Roaming\\Microsoft\\Office\\Recent\\',
|
|
466
|
+
'\\AppData\\Roaming\\Microsoft\\Windows\\Cookies\\',
|
|
467
|
+
'\\AppData\\Roaming\\Microsoft\\Windows\\Recent\\',
|
|
468
|
+
'C:\\ProgramData\\Microsoft\\OfficeSoftwareProtectionPlatform\\Cache\\cache.dat',
|
|
469
|
+
'C:\\Windows\\Prefetch\\',
|
|
470
|
+
|
|
471
|
+
'\\AppData\\Roaming\\Adobe\\Acrobat\\9.0\\SharedDataEvents-journal',
|
|
472
|
+
'\\AppData\\Roaming\\Adobe\\Acrobat\\9.0\\UserCache.bin',
|
|
473
|
+
|
|
474
|
+
'\\AppData\\Roaming\\Macromedia\\Flash Player\\macromedia.com\\support\\flashplayer\\sys\\settings.sol',
|
|
475
|
+
'\\AppData\\Roaming\\Adobe\\Flash Player\\NativeCache\\',
|
|
476
|
+
'C:\\Windows\\AppCompat\\Programs\\',
|
|
477
|
+
'C:\\~' # caused by temp file created by MS Office when opening malicious doc/xls/...
|
|
478
|
+
}
|
|
479
|
+
if list_in_string(noise_substrings, item):
|
|
480
|
+
return None
|
|
481
|
+
return item
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def cleanup_regkey(item):
|
|
485
|
+
noise_substrings = {
|
|
486
|
+
r'\\CurrentVersion\\Explorer\\FileExts\\[a-z\.]+\\OpenWith',
|
|
487
|
+
r'\\CurrentVersion\\Explorer\\RecentDocs\\',
|
|
488
|
+
r'\\CurrentVersion\\Explorer\\UserAssist\\',
|
|
489
|
+
r'\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bag',
|
|
490
|
+
r'\\Software\\Classes\\CLSID\\',
|
|
491
|
+
r'\\Software\\Classes\\Local Settings\\MuiCache\\',
|
|
492
|
+
r'\\Software\\Microsoft\\Internet Explorer\\Main\\WindowsSearch',
|
|
493
|
+
r'\\Software\\Microsoft\\Office\\[0-9\.]+\\',
|
|
494
|
+
r'\\Software\\Microsoft\\Office\\Common\\Smart Tag\\',
|
|
495
|
+
r'\\Software\\Microsoft\\OfficeSoftwareProtectionPlatform\\',
|
|
496
|
+
r'\\Software\\Microsoft\\Shared Tools\\Panose\\',
|
|
497
|
+
r'\\Software\\Microsoft\\Tracing\\',
|
|
498
|
+
r'\\Software\\Microsoft\\Tracing\\powershell_RASAPI32\\',
|
|
499
|
+
r'\\Software\\Microsoft\\Tracing\\powershell_RASMANCS\\',
|
|
500
|
+
r'\\Software\\Microsoft\\Windows\\CurrentVersion\\Action Center\\',
|
|
501
|
+
r'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU\\',
|
|
502
|
+
r'\\Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\',
|
|
503
|
+
r'\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\',
|
|
504
|
+
r'\\System\\CurrentControlSet\\Services\\RdyBoost\\',
|
|
505
|
+
r'\\Usage\\SpellingAndGrammarFiles'
|
|
506
|
+
}
|
|
507
|
+
if list_in_string(noise_substrings, item, regex=True):
|
|
508
|
+
return None
|
|
509
|
+
return item
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def cleanup_regdata(item):
|
|
513
|
+
if not item:
|
|
514
|
+
return None
|
|
515
|
+
item = item.replace('(UNICODE_0x00000000)', '')
|
|
516
|
+
return item
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def get_zipped_contents(filename, data, password=None):
|
|
520
|
+
with zipfile.ZipFile(io.BytesIO(data), 'r') as zf:
|
|
521
|
+
unzipped_files = []
|
|
522
|
+
if password is not None:
|
|
523
|
+
password = str.encode(password) # Byte encoded password required
|
|
524
|
+
for zip_file_name in zf.namelist(): # Get all files in the zip file
|
|
525
|
+
# print(zip_file_name)
|
|
526
|
+
with zf.open(zip_file_name, mode='r', pwd=password) as fp:
|
|
527
|
+
file_data = fp.read()
|
|
528
|
+
unzipped_files.append({'values': zip_file_name,
|
|
529
|
+
'data': file_data,
|
|
530
|
+
'comment': 'Extracted from {0}'.format(filename)})
|
|
531
|
+
# print("{} : {}".format(zip_file_name, len(file_data)))
|
|
532
|
+
return unzipped_files
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def introspection():
|
|
536
|
+
modulesetup = {}
|
|
537
|
+
try:
|
|
538
|
+
userConfig
|
|
539
|
+
modulesetup['userConfig'] = userConfig
|
|
540
|
+
except NameError:
|
|
541
|
+
pass
|
|
542
|
+
try:
|
|
543
|
+
inputSource
|
|
544
|
+
modulesetup['inputSource'] = inputSource
|
|
545
|
+
except NameError:
|
|
546
|
+
pass
|
|
547
|
+
return modulesetup
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def version():
|
|
551
|
+
moduleinfo['config'] = moduleconfig
|
|
552
|
+
return moduleinfo
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import base64
|
|
3
|
+
from pymisp import MISPEvent, MISPObject, MISPAttribute
|
|
4
|
+
from pyfaup.faup import Faup
|
|
5
|
+
|
|
6
|
+
misperrors = {'error': 'Error'}
|
|
7
|
+
userConfig = {
|
|
8
|
+
'include_scheme': {
|
|
9
|
+
'type': 'Boolean',
|
|
10
|
+
'message': 'Include scheme'
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
mispattributes = {
|
|
15
|
+
'inputSource': ['file', 'paste'],
|
|
16
|
+
'output': ['MISP Format'],
|
|
17
|
+
'format': 'misp_standard'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
moduleinfo = {
|
|
22
|
+
'version': '0.1',
|
|
23
|
+
'author': 'Sami Mokaddem',
|
|
24
|
+
'description': 'Simple URL import tool with Faup',
|
|
25
|
+
'module-type': ['import'],
|
|
26
|
+
'name': 'URL Import',
|
|
27
|
+
'logo': '',
|
|
28
|
+
'requirements': [],
|
|
29
|
+
'features': '',
|
|
30
|
+
'references': [],
|
|
31
|
+
'input': '',
|
|
32
|
+
'output': '',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
moduleconfig = []
|
|
36
|
+
|
|
37
|
+
fp = Faup()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def generateData(event, data, config):
|
|
41
|
+
for url in data.splitlines():
|
|
42
|
+
fp.decode(url)
|
|
43
|
+
parsed = fp.get()
|
|
44
|
+
obj = MISPObject('url')
|
|
45
|
+
obj.add_attribute('url', type='url', value=url)
|
|
46
|
+
if parsed['tld'] is not None:
|
|
47
|
+
obj.add_attribute('tld', type='text', value=parsed['tld'])
|
|
48
|
+
if parsed['subdomain'] is not None:
|
|
49
|
+
obj.add_attribute('subdomain', type='text', value=parsed['subdomain'])
|
|
50
|
+
if config['include_scheme'] is True:
|
|
51
|
+
obj.add_attribute('scheme', type='text', value=parsed['scheme'])
|
|
52
|
+
obj.add_attribute('resource_path', type='text', value=parsed['resource_path'])
|
|
53
|
+
obj.add_attribute('query_string', type='text', value=parsed['query_string'])
|
|
54
|
+
obj.add_attribute('port', type='port', value=parsed['port'])
|
|
55
|
+
obj.add_attribute('host', type='hostname', value=parsed['host'])
|
|
56
|
+
if parsed['fragment'] is not None:
|
|
57
|
+
obj.add_attribute('fragment', type='text', value=parsed['fragment'])
|
|
58
|
+
obj.add_attribute('domain_without_tld', type='text', value=parsed['domain_without_tld'])
|
|
59
|
+
obj.add_attribute('domain', type='domain', value=parsed['domain'])
|
|
60
|
+
event.objects.append(obj)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def handler(q=False):
|
|
64
|
+
if q is False:
|
|
65
|
+
return False
|
|
66
|
+
request = json.loads(q)
|
|
67
|
+
data = getUploadedData(request)
|
|
68
|
+
config = getPassedConfig(request)
|
|
69
|
+
event = MISPEvent()
|
|
70
|
+
generateData(event, data, config)
|
|
71
|
+
return {"results": json.loads(event.to_json())}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def getUploadedData(request):
|
|
75
|
+
return base64.b64decode(request['data']).decode('utf8')
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def getPassedConfig(request):
|
|
79
|
+
for k, v in userConfig.items():
|
|
80
|
+
if v['type'] == 'Boolean':
|
|
81
|
+
request['config'][k] = True if request['config'][k] == '1' else False
|
|
82
|
+
return request['config']
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def introspection():
|
|
86
|
+
modulesetup = mispattributes
|
|
87
|
+
try:
|
|
88
|
+
userConfig
|
|
89
|
+
modulesetup['userConfig'] = userConfig
|
|
90
|
+
except NameError:
|
|
91
|
+
pass
|
|
92
|
+
return modulesetup
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def version():
|
|
96
|
+
moduleinfo['config'] = moduleconfig
|
|
97
|
+
return moduleinfo
|