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.
Files changed (194) hide show
  1. misp_modules/__init__.py +379 -0
  2. misp_modules/helpers/__init__.py +1 -0
  3. misp_modules/helpers/cache.py +84 -0
  4. misp_modules/lib/__init__.py +4 -0
  5. misp_modules/lib/_vmray/__init__.py +0 -0
  6. misp_modules/lib/_vmray/parser.py +1417 -0
  7. misp_modules/lib/_vmray/rest_api.py +148 -0
  8. misp_modules/lib/cof2misp/LICENSE-2.0.txt +202 -0
  9. misp_modules/lib/cof2misp/__init__.py +0 -0
  10. misp_modules/lib/cof2misp/cof.py +165 -0
  11. misp_modules/lib/joe_mapping.py +114 -0
  12. misp_modules/lib/joe_parser.py +573 -0
  13. misp_modules/lib/lastline_api.py +841 -0
  14. misp_modules/lib/qintel_helper.py +263 -0
  15. misp_modules/lib/stix2misp.py +2080 -0
  16. misp_modules/lib/stix2misp_mapping.py +460 -0
  17. misp_modules/lib/synonymsToTagNames.json +1 -0
  18. misp_modules/lib/vt_graph_parser/__init__.py +8 -0
  19. misp_modules/lib/vt_graph_parser/errors.py +20 -0
  20. misp_modules/lib/vt_graph_parser/helpers/__init__.py +7 -0
  21. misp_modules/lib/vt_graph_parser/helpers/parsers.py +88 -0
  22. misp_modules/lib/vt_graph_parser/helpers/rules.py +304 -0
  23. misp_modules/lib/vt_graph_parser/helpers/wrappers.py +58 -0
  24. misp_modules/lib/vt_graph_parser/importers/__init__.py +7 -0
  25. misp_modules/lib/vt_graph_parser/importers/base.py +98 -0
  26. misp_modules/lib/vt_graph_parser/importers/pymisp_response.py +73 -0
  27. misp_modules/modules/__init__.py +4 -0
  28. misp_modules/modules/action_mod/__init__.py +1 -0
  29. misp_modules/modules/action_mod/_utils/__init__.py +1 -0
  30. misp_modules/modules/action_mod/_utils/utils.py +70 -0
  31. misp_modules/modules/action_mod/mattermost.py +113 -0
  32. misp_modules/modules/action_mod/slack.py +96 -0
  33. misp_modules/modules/action_mod/testaction.py +68 -0
  34. misp_modules/modules/expansion/__init__.py +36 -0
  35. misp_modules/modules/expansion/_dnsdb_query/COPYRIGHT +27 -0
  36. misp_modules/modules/expansion/_dnsdb_query/LICENSE +202 -0
  37. misp_modules/modules/expansion/_dnsdb_query/README.md +162 -0
  38. misp_modules/modules/expansion/_dnsdb_query/__init__.py +0 -0
  39. misp_modules/modules/expansion/_dnsdb_query/dnsdb_query.py +327 -0
  40. misp_modules/modules/expansion/_ransomcoindb/__init__.py +0 -0
  41. misp_modules/modules/expansion/_ransomcoindb/ransomcoindb.py +96 -0
  42. misp_modules/modules/expansion/_vulnerability_parser/__init__.py +0 -0
  43. misp_modules/modules/expansion/_vulnerability_parser/vulnerability_parser.py +118 -0
  44. misp_modules/modules/expansion/abuseipdb.py +146 -0
  45. misp_modules/modules/expansion/apiosintds.py +365 -0
  46. misp_modules/modules/expansion/apivoid.py +133 -0
  47. misp_modules/modules/expansion/assemblyline_query.py +179 -0
  48. misp_modules/modules/expansion/assemblyline_submit.py +100 -0
  49. misp_modules/modules/expansion/backscatter_io.py +84 -0
  50. misp_modules/modules/expansion/btc_scam_check.py +54 -0
  51. misp_modules/modules/expansion/btc_steroids.py +238 -0
  52. misp_modules/modules/expansion/censys_enrich.py +287 -0
  53. misp_modules/modules/expansion/circl_passivedns.py +85 -0
  54. misp_modules/modules/expansion/circl_passivessl.py +113 -0
  55. misp_modules/modules/expansion/clamav.py +129 -0
  56. misp_modules/modules/expansion/cluster25_expand.py +239 -0
  57. misp_modules/modules/expansion/countrycode.py +69 -0
  58. misp_modules/modules/expansion/cpe.py +140 -0
  59. misp_modules/modules/expansion/crowdsec.py +235 -0
  60. misp_modules/modules/expansion/crowdstrike_falcon.py +148 -0
  61. misp_modules/modules/expansion/cuckoo_submit.py +161 -0
  62. misp_modules/modules/expansion/cve.py +57 -0
  63. misp_modules/modules/expansion/cve_advanced.py +185 -0
  64. misp_modules/modules/expansion/cytomic_orion.py +196 -0
  65. misp_modules/modules/expansion/dbl_spamhaus.py +78 -0
  66. misp_modules/modules/expansion/dns.py +71 -0
  67. misp_modules/modules/expansion/docx_enrich.py +71 -0
  68. misp_modules/modules/expansion/domaintools.py +290 -0
  69. misp_modules/modules/expansion/eql.py +91 -0
  70. misp_modules/modules/expansion/eupi.py +86 -0
  71. misp_modules/modules/expansion/extract_url_components.py +83 -0
  72. misp_modules/modules/expansion/farsight_passivedns.py +243 -0
  73. misp_modules/modules/expansion/geoip_asn.py +75 -0
  74. misp_modules/modules/expansion/geoip_city.py +75 -0
  75. misp_modules/modules/expansion/geoip_country.py +73 -0
  76. misp_modules/modules/expansion/google_safe_browsing.py +86 -0
  77. misp_modules/modules/expansion/google_search.py +57 -0
  78. misp_modules/modules/expansion/google_threat_intelligence.py +453 -0
  79. misp_modules/modules/expansion/greynoise.py +346 -0
  80. misp_modules/modules/expansion/hashdd.py +53 -0
  81. misp_modules/modules/expansion/hashlookup.py +118 -0
  82. misp_modules/modules/expansion/hibp.py +62 -0
  83. misp_modules/modules/expansion/html_to_markdown.py +63 -0
  84. misp_modules/modules/expansion/hyasinsight.py +881 -0
  85. misp_modules/modules/expansion/intel471.py +73 -0
  86. misp_modules/modules/expansion/intelmq_eventdb.py.experimental +67 -0
  87. misp_modules/modules/expansion/ip2locationio.py +90 -0
  88. misp_modules/modules/expansion/ipasn.py +70 -0
  89. misp_modules/modules/expansion/ipinfo.py +112 -0
  90. misp_modules/modules/expansion/ipqs_fraud_and_risk_scoring.py +633 -0
  91. misp_modules/modules/expansion/iprep.py +98 -0
  92. misp_modules/modules/expansion/jinja_template_rendering.py +54 -0
  93. misp_modules/modules/expansion/joesandbox_query.py +91 -0
  94. misp_modules/modules/expansion/joesandbox_submit.py +147 -0
  95. misp_modules/modules/expansion/lastline_query.py +148 -0
  96. misp_modules/modules/expansion/lastline_submit.py +180 -0
  97. misp_modules/modules/expansion/macaddress_io.py +130 -0
  98. misp_modules/modules/expansion/macvendors.py +55 -0
  99. misp_modules/modules/expansion/malshare_upload.py +107 -0
  100. misp_modules/modules/expansion/malwarebazaar.py +67 -0
  101. misp_modules/modules/expansion/mcafee_insights_enrich.py +249 -0
  102. misp_modules/modules/expansion/mmdb_lookup.py +138 -0
  103. misp_modules/modules/expansion/module.py.skeleton +44 -0
  104. misp_modules/modules/expansion/mwdb.py +152 -0
  105. misp_modules/modules/expansion/ocr_enrich.py +74 -0
  106. misp_modules/modules/expansion/ods_enrich.py +71 -0
  107. misp_modules/modules/expansion/odt_enrich.py +61 -0
  108. misp_modules/modules/expansion/onyphe.py +243 -0
  109. misp_modules/modules/expansion/onyphe_full.py +387 -0
  110. misp_modules/modules/expansion/otx.py +167 -0
  111. misp_modules/modules/expansion/passive_ssh.py +150 -0
  112. misp_modules/modules/expansion/passivetotal.py +358 -0
  113. misp_modules/modules/expansion/pdf_enrich.py +58 -0
  114. misp_modules/modules/expansion/pptx_enrich.py +65 -0
  115. misp_modules/modules/expansion/qintel_qsentry.py +229 -0
  116. misp_modules/modules/expansion/qrcode.py +99 -0
  117. misp_modules/modules/expansion/ransomcoindb.py +82 -0
  118. misp_modules/modules/expansion/rbl.py +126 -0
  119. misp_modules/modules/expansion/recordedfuture.py +544 -0
  120. misp_modules/modules/expansion/reversedns.py +77 -0
  121. misp_modules/modules/expansion/securitytrails.py +571 -0
  122. misp_modules/modules/expansion/shodan.py +244 -0
  123. misp_modules/modules/expansion/sigma_queries.py +61 -0
  124. misp_modules/modules/expansion/sigma_syntax_validator.py +49 -0
  125. misp_modules/modules/expansion/sigmf_expand.py +303 -0
  126. misp_modules/modules/expansion/socialscan.py +108 -0
  127. misp_modules/modules/expansion/sophoslabs_intelix.py +146 -0
  128. misp_modules/modules/expansion/sourcecache.py +57 -0
  129. misp_modules/modules/expansion/stairwell.py +156 -0
  130. misp_modules/modules/expansion/stix2_pattern_syntax_validator.py +56 -0
  131. misp_modules/modules/expansion/threatcrowd.py +170 -0
  132. misp_modules/modules/expansion/threatfox.py +75 -0
  133. misp_modules/modules/expansion/threatminer.py +152 -0
  134. misp_modules/modules/expansion/triage_submit.py +119 -0
  135. misp_modules/modules/expansion/trustar_enrich.py +235 -0
  136. misp_modules/modules/expansion/urlhaus.py +164 -0
  137. misp_modules/modules/expansion/urlscan.py +269 -0
  138. misp_modules/modules/expansion/variotdbs.py +133 -0
  139. misp_modules/modules/expansion/virustotal.py +311 -0
  140. misp_modules/modules/expansion/virustotal_public.py +272 -0
  141. misp_modules/modules/expansion/virustotal_upload.py +91 -0
  142. misp_modules/modules/expansion/vmray_submit.py +161 -0
  143. misp_modules/modules/expansion/vmware_nsx.py +628 -0
  144. misp_modules/modules/expansion/vulndb.py +292 -0
  145. misp_modules/modules/expansion/vulnerability_lookup.py +324 -0
  146. misp_modules/modules/expansion/vulners.py +81 -0
  147. misp_modules/modules/expansion/vysion.py +221 -0
  148. misp_modules/modules/expansion/whois.py +72 -0
  149. misp_modules/modules/expansion/whoisfreaks.py +232 -0
  150. misp_modules/modules/expansion/wiki.py +58 -0
  151. misp_modules/modules/expansion/xforceexchange.py +189 -0
  152. misp_modules/modules/expansion/xlsx_enrich.py +63 -0
  153. misp_modules/modules/expansion/yara_query.py +70 -0
  154. misp_modules/modules/expansion/yara_syntax_validator.py +49 -0
  155. misp_modules/modules/expansion/yeti.py +196 -0
  156. misp_modules/modules/export_mod/__init__.py +3 -0
  157. misp_modules/modules/export_mod/cef_export.py +93 -0
  158. misp_modules/modules/export_mod/cisco_firesight_manager_ACL_rule_export.py +150 -0
  159. misp_modules/modules/export_mod/defender_endpoint_export.py +141 -0
  160. misp_modules/modules/export_mod/goamlexport.py +255 -0
  161. misp_modules/modules/export_mod/liteexport.py +97 -0
  162. misp_modules/modules/export_mod/mass_eql_export.py +106 -0
  163. misp_modules/modules/export_mod/nexthinkexport.py +131 -0
  164. misp_modules/modules/export_mod/osqueryexport.py +125 -0
  165. misp_modules/modules/export_mod/pdfexport.py +107 -0
  166. misp_modules/modules/export_mod/testexport.py +73 -0
  167. misp_modules/modules/export_mod/threatStream_misp_export.py +114 -0
  168. misp_modules/modules/export_mod/threat_connect_export.py +125 -0
  169. misp_modules/modules/export_mod/virustotal_collections.py +141 -0
  170. misp_modules/modules/export_mod/vt_graph.py +120 -0
  171. misp_modules/modules/export_mod/yara_export.py +290 -0
  172. misp_modules/modules/import_mod/__init__.py +22 -0
  173. misp_modules/modules/import_mod/cof2misp.py +264 -0
  174. misp_modules/modules/import_mod/csvimport.py +319 -0
  175. misp_modules/modules/import_mod/cuckooimport.py +749 -0
  176. misp_modules/modules/import_mod/email_import.py +294 -0
  177. misp_modules/modules/import_mod/goamlimport.py +188 -0
  178. misp_modules/modules/import_mod/import_blueprint.py +93 -0
  179. misp_modules/modules/import_mod/joe_import.py +74 -0
  180. misp_modules/modules/import_mod/lastline_import.py +160 -0
  181. misp_modules/modules/import_mod/mispjson.py +73 -0
  182. misp_modules/modules/import_mod/ocr.py +122 -0
  183. misp_modules/modules/import_mod/openiocimport.py +99 -0
  184. misp_modules/modules/import_mod/taxii21.py +383 -0
  185. misp_modules/modules/import_mod/testimport.py +73 -0
  186. misp_modules/modules/import_mod/threatanalyzer_import.py +552 -0
  187. misp_modules/modules/import_mod/url_import.py +97 -0
  188. misp_modules/modules/import_mod/vmray_import.py +96 -0
  189. misp_modules/modules/import_mod/vmray_summary_json_import.py +87 -0
  190. misp_modules-2.4.196.dist-info/LICENSE +661 -0
  191. misp_modules-2.4.196.dist-info/METADATA +281 -0
  192. misp_modules-2.4.196.dist-info/RECORD +194 -0
  193. misp_modules-2.4.196.dist-info/WHEEL +4 -0
  194. misp_modules-2.4.196.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,125 @@
1
+ """
2
+ Export module for converting MISP events into ThreatConnect Structured Import files. This export data is meant to be used with the "Structured Import" ability of ThreatConnect.
3
+
4
+ Source: http://kb.threatconnect.com/customer/en/portal/articles/1912599-using-structured-import/
5
+ Source: http://kb.threatconnect.com/customer/en/portal/articles/2092925-the-threatconnect-data-model/
6
+ """
7
+ import base64
8
+ import csv
9
+ import io
10
+ import json
11
+ import logging
12
+
13
+ misperrors = {"error": "Error"}
14
+
15
+ moduleinfo = {
16
+ 'version': '0.1',
17
+ 'author': 'CenturyLink CIRT',
18
+ 'description': 'Module to export a structured CSV file for uploading to ThreatConnect.',
19
+ 'module-type': ['export'],
20
+ 'name': 'ThreadConnect Export',
21
+ 'logo': 'threatconnect.png',
22
+ 'requirements': ['csv'],
23
+ 'features': 'The module takes a MISP event in input, to look every attribute. Each attribute matching with some predefined types is then exported in a CSV format recognized by ThreatConnect.\nUsers should then provide, as module configuration, the source of data they export, because it is required by the output format.',
24
+ 'references': ['https://www.threatconnect.com'],
25
+ 'input': 'MISP Event attributes',
26
+ 'output': 'ThreatConnect CSV format file',
27
+ }
28
+
29
+ # config fields expected from the MISP administrator
30
+ # Default_Source: The source of the data. Typically this won't be changed from the default
31
+ moduleconfig = ["Default_Source"]
32
+
33
+ # Map of MISP fields => ThreatConnect fields
34
+ fieldmap = {
35
+ "domain": "Host",
36
+ "domain|ip": "Host|Address",
37
+ "hostname": "Host",
38
+ "ip-src": "Address",
39
+ "ip-dst": "Address",
40
+ "ip-src|port": "Address",
41
+ "ip-dst|port": "Address",
42
+ "whois-registrant-email": "EmailAddress",
43
+ "email-src": "EmailAddress",
44
+ "email-dst": "EmailAddress",
45
+ "url": "URL",
46
+ "md5": "File",
47
+ "filename|md5": "File"
48
+ }
49
+
50
+ # combine all the MISP fields from fieldmap into one big list
51
+ mispattributes = {
52
+ "input": list(fieldmap.keys())
53
+ }
54
+
55
+
56
+ def handler(q=False):
57
+ """
58
+ Convert a MISP query into a CSV file matching the ThreatConnect Structured Import file format.
59
+ Input
60
+ q: Query dictionary
61
+ """
62
+ if q is False or not q:
63
+ return False
64
+
65
+ # Check if we were given a configuration
66
+ request = json.loads(q)
67
+ config = request.get("config", {"Default_Source": ""})
68
+ logging.info("Setting config to: %s", config)
69
+
70
+ response = io.StringIO()
71
+ writer = csv.DictWriter(response, fieldnames=["Type", "Value", "Source", "Description"])
72
+ writer.writeheader()
73
+
74
+ # start parsing MISP data
75
+ for event in request["data"]:
76
+ for attribute in event["Attribute"]:
77
+ if attribute["type"] in mispattributes["input"]:
78
+ logging.debug("Adding %s to structured CSV export of ThreatConnectExport", attribute["value"])
79
+ if "|" in attribute["type"]:
80
+ # if the attribute type has multiple values, line it up with the corresponding ThreatConnect values in fieldmap
81
+ indicators = tuple(attribute["value"].split("|"))
82
+ tc_types = tuple(fieldmap[attribute["type"]].split("|"))
83
+ for i, indicator in enumerate(indicators):
84
+ writer.writerow({
85
+ "Type": tc_types[i],
86
+ "Value": indicator,
87
+ "Source": config["Default_Source"],
88
+ "Description": attribute["comment"]
89
+ })
90
+ else:
91
+ writer.writerow({
92
+ "Type": fieldmap[attribute["type"]],
93
+ "Value": attribute["value"],
94
+ "Source": config["Default_Source"],
95
+ "Description": attribute["comment"]
96
+ })
97
+
98
+ return {"response": [], "data": str(base64.b64encode(bytes(response.getvalue(), 'utf-8')), 'utf-8')}
99
+
100
+
101
+ def introspection():
102
+ """
103
+ Relay the supported attributes to MISP.
104
+ No Input
105
+ Output
106
+ Dictionary of supported MISP attributes
107
+ """
108
+ modulesetup = {
109
+ "responseType": "application/txt",
110
+ "outputFileExtension": "csv",
111
+ "userConfig": {},
112
+ "inputSource": []
113
+ }
114
+ return modulesetup
115
+
116
+
117
+ def version():
118
+ """
119
+ Relay module version and associated metadata to MISP.
120
+ No Input
121
+ Output
122
+ moduleinfo: metadata output containing all potential configuration values
123
+ """
124
+ moduleinfo["config"] = moduleconfig
125
+ return moduleinfo
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2022 Google Inc. All Rights Reserved.
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """Creates a VT Collection with indicators present in a given event."""
17
+
18
+ import base64
19
+ import json
20
+ import requests
21
+
22
+ misperrors = {
23
+ 'error': 'Error'
24
+ }
25
+
26
+ mispattributes = {
27
+ 'input': [
28
+ 'hostname',
29
+ 'domain',
30
+ 'ip-src',
31
+ 'ip-dst',
32
+ 'md5',
33
+ 'sha1',
34
+ 'sha256',
35
+ 'url'
36
+ ],
37
+ 'format': 'misp_standard',
38
+ 'responseType': 'application/txt',
39
+ 'outputFileExtension': 'txt',
40
+ }
41
+
42
+ moduleinfo = {
43
+ 'version': '1.0',
44
+ 'author': 'VirusTotal',
45
+ 'description': 'Creates a VT Collection from an event iocs.',
46
+ 'module-type': ['export'],
47
+ 'name': 'VirusTotal Collections Export',
48
+ 'logo': 'virustotal.png',
49
+ 'requirements': ['An access to the VirusTotal API (apikey).'],
50
+ 'features': 'This export module which takes advantage of a new endpoint in VT APIv3 to create VT Collections from IOCs contained in a MISP event. With this module users will be able to create a collection just using the Download as... button.',
51
+ 'references': ['https://www.virustotal.com/', 'https://blog.virustotal.com/2021/11/introducing-virustotal-collections.html'],
52
+ 'input': 'A domain, hash (md5, sha1, sha256 or sha512), hostname, url or IP address attribute.',
53
+ 'output': 'A VirusTotal collection in VT.',
54
+ }
55
+
56
+ moduleconfig = [
57
+ 'vt_api_key',
58
+ 'proxy_host',
59
+ 'proxy_port',
60
+ 'proxy_username',
61
+ 'proxy_password'
62
+ ]
63
+
64
+
65
+ class VTError(Exception):
66
+ "Exception class to map vt api response errors."
67
+ pass
68
+
69
+
70
+ def create_collection(api_key, event_data):
71
+ headers = {
72
+ 'x-apikey': api_key,
73
+ 'content-type': 'application/json',
74
+ 'x-tool': 'MISPModuleVirusTotalCollectionExport',
75
+ }
76
+
77
+ response = requests.post('https://www.virustotal.com/api/v3/integrations/misp/collections',
78
+ headers=headers,
79
+ json=event_data)
80
+
81
+ uuid = event_data['Event']['uuid']
82
+ response_data = response.json()
83
+
84
+ if response.status_code == 200:
85
+ col_id = response_data['data']['id']
86
+ return f'{uuid}: https://www.virustotal.com/gui/collection/{col_id}/iocs'
87
+
88
+ error = response_data['error']['message']
89
+ if response.status_code == 400:
90
+ return f'{uuid}: {error}'
91
+ else:
92
+ misperrors['error'] = error
93
+ raise VTError(error)
94
+
95
+
96
+ def normalize_misp_data(data):
97
+ normalized_data = {'Event': data.pop('Event', {})}
98
+ for attr_key in data:
99
+ if isinstance(data[attr_key], list) or isinstance(data[attr_key], dict):
100
+ if attr_key == 'EventTag':
101
+ normalized_data['Event']['Tag'] = [tag['Tag'] for tag in data[attr_key]]
102
+ else:
103
+ normalized_data['Event'][attr_key] = data[attr_key]
104
+
105
+ return normalized_data
106
+
107
+
108
+ def handler(q=False):
109
+ request = json.loads(q)
110
+
111
+ if not request.get('config') or not request['config'].get('vt_api_key'):
112
+ misperrors['error'] = 'A VirusTotal api key is required for this module.'
113
+ return misperrors
114
+
115
+ config = request['config']
116
+ data = request['data']
117
+ responses = []
118
+
119
+ try:
120
+ for event_data in data:
121
+ normalized_event = normalize_misp_data(event_data)
122
+ responses.append(create_collection(config.get('vt_api_key'),
123
+ normalized_event))
124
+
125
+ output = '\n'.join(responses)
126
+ return {
127
+ "response": [],
128
+ "data": str(base64.b64encode(bytes(output, 'utf-8')), 'utf-8'),
129
+ }
130
+ except VTError:
131
+ return misperrors
132
+
133
+
134
+
135
+ def introspection():
136
+ return mispattributes
137
+
138
+
139
+ def version():
140
+ moduleinfo['config'] = moduleconfig
141
+ return moduleinfo
@@ -0,0 +1,120 @@
1
+ '''Export MISP event to VirusTotal Graph.'''
2
+
3
+
4
+ import base64
5
+ import json
6
+ from vt_graph_parser.importers.pymisp_response import from_pymisp_response
7
+
8
+
9
+ misperrors = {
10
+ 'error': 'Error'
11
+ }
12
+ moduleinfo = {
13
+ 'version': '0.1',
14
+ 'author': 'VirusTotal',
15
+ 'description': 'This module is used to create a VirusTotal Graph from a MISP event.',
16
+ 'module-type': ['export'],
17
+ 'name': 'VirusTotal Graph Export',
18
+ 'logo': 'virustotal.png',
19
+ 'requirements': ['vt_graph_api, the python library to query the VirusTotal graph API'],
20
+ 'features': 'The module takes the MISP event as input and queries the VirusTotal Graph API to create a new graph out of the event.\n\nOnce the graph is ready, we get the url of it, which is returned so we can view it on VirusTotal.',
21
+ 'references': ['https://www.virustotal.com/gui/graph-overview'],
22
+ 'input': 'A MISP event.',
23
+ 'output': 'Link of the VirusTotal Graph created for the event.',
24
+ }
25
+ mispattributes = {
26
+ 'input': [
27
+ 'hostname',
28
+ 'domain',
29
+ 'ip-src',
30
+ 'ip-dst',
31
+ 'md5',
32
+ 'sha1',
33
+ 'sha256',
34
+ 'url',
35
+ 'filename|md5',
36
+ 'filename'
37
+ ]
38
+ }
39
+ moduleconfig = [
40
+ 'vt_api_key',
41
+ 'fetch_information',
42
+ 'private',
43
+ 'fetch_vt_enterprise',
44
+ 'expand_one_level',
45
+ 'user_editors',
46
+ 'user_viewers',
47
+ 'group_editors',
48
+ 'group_viewers'
49
+ ]
50
+
51
+
52
+ def handler(q=False):
53
+ """Expansion handler.
54
+
55
+ Args:
56
+ q (bool, optional): module data. Defaults to False.
57
+
58
+ Returns:
59
+ [str]: VirusTotal graph links
60
+ """
61
+ if not q:
62
+ return False
63
+ request = json.loads(q)
64
+
65
+ if not request.get('config') or not request['config'].get('vt_api_key'):
66
+ misperrors['error'] = 'A VirusTotal api key is required for this module.'
67
+ return misperrors
68
+
69
+ config = request['config']
70
+
71
+ api_key = config.get('vt_api_key')
72
+ fetch_information = config.get('fetch_information') or False
73
+ private = config.get('private') or False
74
+ fetch_vt_enterprise = config.get('fetch_vt_enterprise') or False
75
+ expand_one_level = config.get('expand_one_level') or False
76
+
77
+ user_editors = config.get('user_editors')
78
+ if user_editors:
79
+ user_editors = user_editors.split(',')
80
+ user_viewers = config.get('user_viewers')
81
+ if user_viewers:
82
+ user_viewers = user_viewers.split(',')
83
+ group_editors = config.get('group_editors')
84
+ if group_editors:
85
+ group_editors = group_editors.split(',')
86
+ group_viewers = config.get('group_viewers')
87
+ if group_viewers:
88
+ group_viewers = group_viewers.split(',')
89
+
90
+ graphs = from_pymisp_response(
91
+ request, api_key, fetch_information=fetch_information,
92
+ private=private, fetch_vt_enterprise=fetch_vt_enterprise,
93
+ user_editors=user_editors, user_viewers=user_viewers,
94
+ group_editors=group_editors, group_viewers=group_viewers,
95
+ expand_node_one_level=expand_one_level)
96
+ links = []
97
+
98
+ for graph in graphs:
99
+ graph.save_graph()
100
+ links.append(graph.get_ui_link())
101
+
102
+ # This file will contains one VirusTotal graph link for each exported event
103
+ file_data = str(base64.b64encode(
104
+ bytes('\n'.join(links), 'utf-8')), 'utf-8')
105
+ return {'response': [], 'data': file_data}
106
+
107
+
108
+ def introspection():
109
+ modulesetup = {
110
+ 'responseType': 'application/txt',
111
+ 'outputFileExtension': 'txt',
112
+ 'userConfig': {},
113
+ 'inputSource': []
114
+ }
115
+ return modulesetup
116
+
117
+
118
+ def version():
119
+ moduleinfo['config'] = moduleconfig
120
+ return moduleinfo
@@ -0,0 +1,290 @@
1
+ import json
2
+ import base64
3
+ import re
4
+ try:
5
+ import yara
6
+ except (OSError, ImportError):
7
+ print("yara is missing, use 'pip3 install -I -r REQUIREMENTS' from the root of this repository to install it.")
8
+
9
+
10
+ misperrors = {'error': 'Error'}
11
+
12
+
13
+ userConfig = {
14
+
15
+ }
16
+
17
+ moduleconfig = []
18
+
19
+ # fixed for now, options in the future:
20
+ # event, attribute, event-collection, attribute-collection
21
+ inputSource = ['event']
22
+
23
+ outputFileExtension = 'yara'
24
+ responseType = 'text/plain'
25
+
26
+
27
+ moduleinfo = {
28
+ 'version': '0.1',
29
+ 'author': 'Christophe Vandeplas',
30
+ 'description': 'This module is used to export MISP events to YARA.',
31
+ 'module-type': ['export'],
32
+ 'name': 'YARA Rule Export',
33
+ 'logo': 'yara.png',
34
+ 'requirements': ['yara-python python library'],
35
+ 'features': 'The module will dynamically generate YARA rules for attributes that are marked as to IDS. Basic metadata about the event is added to the rule.\nAttributes that are already YARA rules are also exported, with a rewritten rule name.',
36
+ 'references': ['https://virustotal.github.io/yara/'],
37
+ 'input': 'Attributes and Objects.',
38
+ 'output': 'A YARA file that can be used with the YARA scanning tool.',
39
+ }
40
+
41
+
42
+ class YaraRule():
43
+ def __init__(self, name):
44
+ self.name = name
45
+ self.strings = {}
46
+ self.conditions = []
47
+ self.meta = {}
48
+
49
+ def add_string(self, type_: str, s: str):
50
+ type_clean = ''.join(c if c.isalnum() or c == '_' else '_' for c in type_)
51
+ if type_clean not in self.strings:
52
+ self.strings[type_clean] = []
53
+ self.strings[type_clean].append(s)
54
+
55
+ def add_condition(self, condition: str):
56
+ self.conditions.append(condition)
57
+
58
+ def add_meta(self, key: str, value: str):
59
+ if key not in self.meta:
60
+ self.meta[key] = []
61
+ self.meta[key].append(value)
62
+
63
+ def __str__(self):
64
+ if len(self.strings) == 0 and len(self.conditions) == 0:
65
+ return "\n" # no strings, so no rule
66
+
67
+ result = []
68
+ result.append(f"rule {self.name} {{")
69
+
70
+ result.append(" meta:")
71
+ for key, values in self.meta.items():
72
+ i = 0
73
+ if len(values) == 1:
74
+ result.append(f" {key} = \"{values[0]}\"")
75
+ continue
76
+ for value in values:
77
+ result.append(f" {key}_{i} = \"{value}\"")
78
+ i += 1
79
+
80
+ result.append(" strings:")
81
+ for key, values in self.strings.items():
82
+ i = 0
83
+ for value in values:
84
+ result.append(f" ${key}_{i} = \"{value}\"")
85
+ i += 1
86
+
87
+ result.append(" condition:")
88
+ if len(self.conditions) == 0:
89
+ result.append(" any of them")
90
+ for condition in self.conditions:
91
+ result.append(f" {condition}")
92
+
93
+ result.append("}")
94
+ result.append("")
95
+ return '\n'.join(result)
96
+
97
+
98
+ def handle_string(yara_rules: list, yr: YaraRule, attribute: dict):
99
+ if not attribute['to_ids']: # skip non IDS attributes
100
+ return
101
+ yr.add_string(attribute['type'], attribute['value'])
102
+ return
103
+
104
+
105
+ def handle_combined(yara_rules: list, yr: YaraRule, attribute: dict):
106
+ if not attribute['to_ids']: # skip non IDS attributes
107
+ return
108
+ type_1, type_2 = attribute['type'].split('|')
109
+ value_1, value_2 = attribute['value'].split('|')
110
+ try:
111
+ handlers[type_1](yara_rules, yr, type_1, value_1)
112
+ except KeyError:
113
+ # ignore unsupported types
114
+ pass
115
+ try:
116
+ handlers[type_2](yara_rules, yr, type_2, value_2)
117
+ except KeyError:
118
+ # ignore unsupported types
119
+ pass
120
+
121
+
122
+ def handle_yara(yara_rules: list, yr: YaraRule, attribute: dict):
123
+ # do not check for to_ids, as we want to always export the Yara rule
124
+ # split out as a separate rule, and rewrite the rule name
125
+ value = re.sub('^[ \t]*rule ', 'rule MISP_e{}_'.format(attribute['event_id']), attribute['value'], flags=re.MULTILINE)
126
+ # cleanup dirty stuff from people
127
+ substitutions = (('”', '"'),
128
+ ('“', '"'),
129
+ ('″', '"'),
130
+ ('`', "'"),
131
+ ('\r', ''),
132
+ ('Rule ', 'rule ') # some people write this with the wrong case
133
+ # ('$ ', '$'), # this breaks rules
134
+ # ('\t\t', '\n'), # this breaks rules
135
+ )
136
+ for substitution in substitutions:
137
+ if substitution[0] in value:
138
+ value = value.replace(substitution[0], substitution[1])
139
+
140
+ # we may ignore any global rules as they might disable everything
141
+ # on the other hand we're only processing one event...
142
+ # if 'global rule' in value:
143
+ # return
144
+
145
+ # private rules need some more rewriting
146
+ if 'private rule' in value:
147
+ priv_rules = re.findall(r'private rule (\w+)', value, flags=re.MULTILINE)
148
+ for priv_rule in priv_rules:
149
+ value = re.sub(priv_rule, 'MISP_e{}_{}'.format(attribute['event_id'], priv_rule), value, flags=re.MULTILINE)
150
+
151
+ # compile the yara rule to confirm it's validity
152
+ try:
153
+ yara.compile(source=value)
154
+ except Exception:
155
+ # skip rules that do not compile
156
+ return
157
+
158
+ # all checks done, add the rule
159
+ yara_rules.append(value)
160
+ return
161
+
162
+
163
+ def handle_malware_sample(yara_rules: list, yr: YaraRule, attribute: dict):
164
+ if not attribute['to_ids']: # skip non IDS attributes
165
+ return
166
+ handle_combined(yara_rules, yr, 'filename|md5', attribute['value'])
167
+
168
+
169
+ def handle_meta(yara_rules: list, yr: YaraRule, attribute: dict):
170
+ yr.add_meta(attribute['type'], attribute['value'])
171
+ return
172
+
173
+
174
+ handlers = {
175
+ 'yara': handle_yara,
176
+ 'hostname': handle_string,
177
+ 'hostname|port': handle_combined,
178
+ 'domain': handle_string,
179
+ 'domain|ip': handle_combined,
180
+ 'ip': handle_string,
181
+ 'ip-src': handle_string,
182
+ 'ip-dst': handle_string,
183
+ 'ip-dst|port': handle_combined, # we could also handle_string, which would be more specific. Less false positives, but less true positives too...
184
+ 'ip-src|port': handle_combined,
185
+ 'url': handle_string,
186
+ 'email': handle_string,
187
+ 'email-src': handle_string,
188
+ 'email-dst': handle_string,
189
+ 'email-subject': handle_string,
190
+ 'email-attachment': handle_string,
191
+ 'email-header': handle_string,
192
+ 'email-reply-to': handle_string,
193
+ 'email-x-mailer': handle_string,
194
+ 'email-mime-boundary': handle_string,
195
+ 'email-thread-index': handle_string,
196
+ 'email-message-id': handle_string,
197
+ 'filename': handle_string,
198
+ 'filename|md5': handle_combined,
199
+ 'filename|sha1': handle_combined,
200
+ 'filename|sha256': handle_combined,
201
+ 'filename|authentihash': handle_combined,
202
+ 'filename|vhash': handle_combined,
203
+ 'filename|ssdeep': handle_combined,
204
+ 'filename|imphash': handle_combined,
205
+ 'filename|impfuzzy': handle_combined,
206
+ 'filename|pehash': handle_combined,
207
+ 'filename|sha224': handle_combined,
208
+ 'filename|sha384': handle_combined,
209
+ 'filename|sha512': handle_combined,
210
+ 'filename|sha512/224': handle_combined,
211
+ 'filename|sha512/256': handle_combined,
212
+ 'filename|sha3-224': handle_combined,
213
+ 'filename|sha3-256': handle_combined,
214
+ 'filename|sha3-384': handle_combined,
215
+ 'filename|sha3-512': handle_combined,
216
+ 'filename|tlsh': handle_combined,
217
+ 'malware-sample': handle_malware_sample,
218
+ 'pattern-in-file': handle_string,
219
+ 'pattern-in-traffic': handle_string,
220
+ 'pattern-in-memory': handle_string,
221
+ 'link': handle_meta
222
+ }
223
+
224
+ # auto-generate the list of types to use
225
+ types_to_use = handlers.keys()
226
+
227
+
228
+ def handler(q=False):
229
+ if q is False:
230
+ return False
231
+ request = json.loads(q)
232
+
233
+ yara_rules = []
234
+ for event in request["data"]:
235
+ event_info_clean = ''.join(c if c.isalnum() or c == '_' else '_' for c in event['Event']['info'])
236
+ yr = YaraRule(f"MISP_e{event['Event']['id']}_{event_info_clean}")
237
+
238
+ yr.add_meta('description', event['Event']['info'])
239
+ yr.add_meta('author', f"MISP - {event['Orgc']['name']}")
240
+ yr.add_meta('misp_event_date', event['Event']['date'])
241
+ yr.add_meta('misp_event_id', event['Event']['id'])
242
+ yr.add_meta('misp_event_uuid', event['Event']['uuid'])
243
+
244
+ for attribute in event.get("Attribute", []):
245
+ try:
246
+ handlers[attribute['type']](yara_rules, yr, attribute)
247
+ except KeyError:
248
+ # ignore unsupported types
249
+ pass
250
+ for obj in event.get("Object", []):
251
+ for attribute in obj["Attribute"]:
252
+ try:
253
+ handlers[attribute['type']](yara_rules, yr, attribute)
254
+ except KeyError:
255
+ # ignore unsupported types
256
+ pass
257
+ yara_rules.append(str(yr))
258
+ r = {"response": [], "data": str(base64.b64encode(bytes('\n'.join(yara_rules), 'utf-8')), 'utf-8')}
259
+
260
+ return r
261
+
262
+
263
+ def introspection():
264
+ modulesetup = {}
265
+ try:
266
+ responseType
267
+ modulesetup['responseType'] = responseType
268
+ except NameError:
269
+ pass
270
+ try:
271
+ userConfig
272
+ modulesetup['userConfig'] = userConfig
273
+ except NameError:
274
+ pass
275
+ try:
276
+ outputFileExtension
277
+ modulesetup['outputFileExtension'] = outputFileExtension
278
+ except NameError:
279
+ pass
280
+ try:
281
+ inputSource
282
+ modulesetup['inputSource'] = inputSource
283
+ except NameError:
284
+ pass
285
+ return modulesetup
286
+
287
+
288
+ def version():
289
+ moduleinfo['config'] = moduleconfig
290
+ return moduleinfo
@@ -0,0 +1,22 @@
1
+ import os
2
+ import sys
3
+ sys.path.append('{}/lib'.format('/'.join((os.path.realpath(__file__)).split('/')[:-3])))
4
+
5
+ __all__ = [
6
+ 'vmray_import',
7
+ 'lastline_import',
8
+ 'ocr',
9
+ 'cuckooimport',
10
+ 'goamlimport',
11
+ 'email_import',
12
+ 'mispjson',
13
+ 'openiocimport',
14
+ 'threatanalyzer_import',
15
+ 'csvimport',
16
+ 'cof2misp',
17
+ 'joe_import',
18
+ 'taxii21',
19
+ 'url_import',
20
+ 'vmray_summary_json_import',
21
+ 'import_blueprint'
22
+ ]