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,249 @@
1
+ # Written by mohlcyber 13.08.2021
2
+ # MISP Module for McAfee MVISION Insights to query campaign details
3
+
4
+ import json
5
+ import logging
6
+ import requests
7
+ import sys
8
+
9
+ from . import check_input_attribute, standard_error_message
10
+ from pymisp import MISPAttribute, MISPEvent, MISPObject
11
+
12
+ misperrors = {'error': 'Error'}
13
+ mispattributes = {'input': ["md5", "sha1", "sha256"],
14
+ 'format': 'misp_standard'}
15
+
16
+ # possible module-types: 'expansion', 'hover' or both
17
+ moduleinfo = {
18
+ 'version': '1',
19
+ 'author': 'Martin Ohl',
20
+ 'description': 'Lookup McAfee MVISION Insights Details',
21
+ 'module-type': ['hover'],
22
+ 'name': 'McAfee MVISION Insights Lookup',
23
+ 'logo': '',
24
+ 'requirements': [],
25
+ 'features': '',
26
+ 'references': [],
27
+ 'input': '',
28
+ 'output': '',
29
+ }
30
+
31
+ # config fields that your code expects from the site admin
32
+ moduleconfig = ['api_key', 'client_id', 'client_secret']
33
+
34
+
35
+ class MVAPI():
36
+ def __init__(self, attribute, api_key, client_id, client_secret):
37
+ self.misp_event = MISPEvent()
38
+ self.attribute = MISPAttribute()
39
+ self.attribute.from_dict(**attribute)
40
+ self.misp_event.add_attribute(**self.attribute)
41
+
42
+ self.base_url = 'https://api.mvision.mcafee.com'
43
+ self.session = requests.Session()
44
+
45
+ self.api_key = api_key
46
+ auth = (client_id, client_secret)
47
+
48
+ self.logging()
49
+ self.auth(auth)
50
+
51
+ def logging(self):
52
+ self.logger = logging.getLogger('logs')
53
+ self.logger.setLevel('INFO')
54
+ handler = logging.StreamHandler()
55
+ formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(message)s")
56
+ handler.setFormatter(formatter)
57
+ self.logger.addHandler(handler)
58
+
59
+ def auth(self, auth):
60
+ iam_url = "https://iam.mcafee-cloud.com/iam/v1.1/token"
61
+
62
+ headers = {
63
+ 'x-api-key': self.api_key,
64
+ 'Content-Type': 'application/vnd.api+json'
65
+ }
66
+
67
+ payload = {
68
+ "grant_type": "client_credentials",
69
+ "scope": "ins.user ins.suser ins.ms.r"
70
+ }
71
+
72
+ res = self.session.post(iam_url, headers=headers, auth=auth, data=payload)
73
+
74
+ if res.status_code != 200:
75
+ self.logger.error('Could not authenticate to get the IAM token: {0} - {1}'.format(res.status_code, res.text))
76
+ sys.exit()
77
+ else:
78
+ self.logger.info('Successful authenticated.')
79
+ access_token = res.json()['access_token']
80
+ headers['Authorization'] = 'Bearer ' + access_token
81
+ self.session.headers = headers
82
+
83
+ def search_ioc(self):
84
+ filters = {
85
+ 'filter[type][eq]': self.attribute.type,
86
+ 'filter[value]': self.attribute.value,
87
+ 'fields': 'id, type, value, coverage, uid, is_coat, is_sdb_dirty, category, comment, campaigns, threat, prevalence'
88
+ }
89
+ res = self.session.get(self.base_url + '/insights/v2/iocs', params=filters)
90
+
91
+ if res.ok:
92
+ if len(res.json()['data']) == 0:
93
+ self.logger.info('No Hash details in MVISION Insights found.')
94
+ else:
95
+ self.logger.info('Successfully retrieved MVISION Insights details.')
96
+ self.logger.debug(res.text)
97
+ return res.json()
98
+ else:
99
+ self.logger.error('Error in search_ioc. HTTP {0} - {1}'.format(str(res.status_code), res.text))
100
+ sys.exit()
101
+
102
+ def prep_result(self, ioc):
103
+ res = ioc['data'][0]
104
+ results = []
105
+
106
+ # Parse out Attribute Category
107
+ category_attr = {
108
+ 'type': 'text',
109
+ 'object_relation': 'text',
110
+ 'value': 'Attribute Category: {0}'.format(res['attributes']['category'])
111
+ }
112
+ results.append(category_attr)
113
+
114
+ # Parse out Attribute Comment
115
+ comment_attr = {
116
+ 'type': 'text',
117
+ 'object_relation': 'text',
118
+ 'value': 'Attribute Comment: {0}'.format(res['attributes']['comment'])
119
+ }
120
+ results.append(comment_attr)
121
+
122
+ # Parse out Attribute Dat Coverage
123
+ cover_attr = {
124
+ 'type': 'text',
125
+ 'object_relation': 'text',
126
+ 'value': 'Dat Version Coverage: {0}'.format(res['attributes']['coverage']['dat_version']['min'])
127
+ }
128
+ results.append(cover_attr)
129
+
130
+ # Parse out if Dirty
131
+ cover_attr = {
132
+ 'type': 'text',
133
+ 'object_relation': 'text',
134
+ 'value': 'Is Dirty: {0}'.format(res['attributes']['is-sdb-dirty'])
135
+ }
136
+ results.append(cover_attr)
137
+
138
+ # Parse our targeted countries
139
+ countries_dict = []
140
+ countries = res['attributes']['prevalence']['countries']
141
+
142
+ for country in countries:
143
+ countries_dict.append(country['iso_code'])
144
+
145
+ country_attr = {
146
+ 'type': 'text',
147
+ 'object_relation': 'text',
148
+ 'value': 'Targeted Countries: {0}'.format(countries_dict)
149
+ }
150
+ results.append(country_attr)
151
+
152
+ # Parse out targeted sectors
153
+ sectors_dict = []
154
+ sectors = res['attributes']['prevalence']['sectors']
155
+
156
+ for sector in sectors:
157
+ sectors_dict.append(sector['sector'])
158
+
159
+ sector_attr = {
160
+ 'type': 'text',
161
+ 'object_relation': 'text',
162
+ 'value': 'Targeted Sectors: {0}'.format(sectors_dict)
163
+ }
164
+ results.append(sector_attr)
165
+
166
+ # Parse out Threat Classification
167
+ threat_class_attr = {
168
+ 'type': 'text',
169
+ 'object_relation': 'text',
170
+ 'value': 'Threat Classification: {0}'.format(res['attributes']['threat']['classification'])
171
+ }
172
+ results.append(threat_class_attr)
173
+
174
+ # Parse out Threat Name
175
+ threat_name_attr = {
176
+ 'type': 'text',
177
+ 'object_relation': 'text',
178
+ 'value': 'Threat Name: {0}'.format(res['attributes']['threat']['name'])
179
+ }
180
+ results.append(threat_name_attr)
181
+
182
+ # Parse out Threat Severity
183
+ threat_sev_attr = {
184
+ 'type': 'text',
185
+ 'object_relation': 'text',
186
+ 'value': 'Threat Severity: {0}'.format(res['attributes']['threat']['severity'])
187
+ }
188
+ results.append(threat_sev_attr)
189
+
190
+ # Parse out Attribute ID
191
+ attr_id = {
192
+ 'type': 'text',
193
+ 'object_relation': 'text',
194
+ 'value': 'Attribute ID: {0}'.format(res['id'])
195
+ }
196
+ results.append(attr_id)
197
+
198
+ # Parse out Campaign Relationships
199
+ campaigns = ioc['included']
200
+
201
+ for campaign in campaigns:
202
+ campaign_attr = {
203
+ 'type': 'campaign-name',
204
+ 'object_relation': 'campaign-name',
205
+ 'value': campaign['attributes']['name']
206
+ }
207
+ results.append(campaign_attr)
208
+
209
+ mv_insights_obj = MISPObject(name='MVISION Insights Details')
210
+ for mvi_res in results:
211
+ mv_insights_obj.add_attribute(**mvi_res)
212
+ mv_insights_obj.add_reference(self.attribute.uuid, 'mvision-insights-details')
213
+
214
+ self.misp_event.add_object(mv_insights_obj)
215
+
216
+ event = json.loads(self.misp_event.to_json())
217
+ results_mvi = {key: event[key] for key in ('Attribute', 'Object') if (key in event and event[key])}
218
+
219
+ return {'results': results_mvi}
220
+
221
+
222
+ def handler(q=False):
223
+ if q is False:
224
+ return False
225
+ request = json.loads(q)
226
+
227
+ if not request.get('config') or not request['config'].get('api_key') or not request['config'].get('client_id') or not request['config'].get('client_secret'):
228
+ misperrors['error'] = "Please provide MVISION API Key, Client ID and Client Secret."
229
+ return misperrors
230
+ if request['attribute']['type'] not in mispattributes['input']:
231
+ return {'error': 'Unsupported attribute type. Please use {0}'.format(mispattributes['input'])}
232
+
233
+ api_key = request['config']['api_key']
234
+ client_id = request['config']['client_id']
235
+ client_secret = request['config']['client_secret']
236
+ attribute = request['attribute']
237
+
238
+ mvi = MVAPI(attribute, api_key, client_id, client_secret)
239
+ res = mvi.search_ioc()
240
+ return mvi.prep_result(res)
241
+
242
+
243
+ def introspection():
244
+ return mispattributes
245
+
246
+
247
+ def version():
248
+ moduleinfo['config'] = moduleconfig
249
+ return moduleinfo
@@ -0,0 +1,138 @@
1
+ import json
2
+ import requests
3
+ from . import check_input_attribute, standard_error_message
4
+ from pymisp import MISPEvent, MISPObject
5
+
6
+ misperrors = {'error': 'Error'}
7
+ mispattributes = {'input': ['ip-src', 'ip-src|port', 'ip-dst', 'ip-dst|port'], 'format': 'misp_standard'}
8
+ moduleinfo = {
9
+ 'version': '1',
10
+ 'author': 'Jeroen Pinoy',
11
+ 'description': "A hover and expansion module to enrich an ip with geolocation and ASN information from an mmdb server instance, such as CIRCL's ip.circl.lu.",
12
+ 'module-type': ['expansion', 'hover'],
13
+ 'name': 'GeoIP Enrichment',
14
+ 'logo': 'circl.png',
15
+ 'requirements': [],
16
+ 'features': 'The module takes an IP address related attribute as input.\n It queries the public CIRCL.lu mmdb-server instance, available at ip.circl.lu, by default. The module can be configured with a custom mmdb server url if required.\n It is also possible to filter results on 1 db_source by configuring db_source_filter.',
17
+ 'references': ['https://data.public.lu/fr/datasets/geo-open-ip-address-geolocation-per-country-in-mmdb-format/', 'https://github.com/adulau/mmdb-server'],
18
+ 'input': 'An IP address attribute (for example ip-src or ip-src|port).',
19
+ 'output': 'Geolocation and asn objects.',
20
+ }
21
+ moduleconfig = ["custom_API", "db_source_filter"]
22
+ mmdblookup_url = 'https://ip.circl.lu/'
23
+
24
+
25
+ class MmdbLookupParser():
26
+ def __init__(self, attribute, mmdblookupresult, api_url):
27
+ self.attribute = attribute
28
+ self.mmdblookupresult = mmdblookupresult
29
+ self.api_url = api_url
30
+ self.misp_event = MISPEvent()
31
+ self.misp_event.add_attribute(**attribute)
32
+
33
+ def get_result(self):
34
+ event = json.loads(self.misp_event.to_json())
35
+ results = {key: event[key] for key in ('Attribute', 'Object') if (key in event and event[key])}
36
+ return {'results': results}
37
+
38
+ def parse_mmdblookup_information(self):
39
+ # There is a chance some db's have a hit while others don't so we have to check if entry is empty each time
40
+ for result_entry in self.mmdblookupresult:
41
+ if result_entry['country_info']:
42
+ mmdblookup_object = MISPObject('geolocation')
43
+ mmdblookup_object.add_attribute('country',
44
+ **{'type': 'text', 'value': result_entry['country_info']['Country']})
45
+ mmdblookup_object.add_attribute('countrycode',
46
+ **{'type': 'text', 'value': result_entry['country']['iso_code']})
47
+ mmdblookup_object.add_attribute('latitude',
48
+ **{'type': 'float',
49
+ 'value': result_entry['country_info']['Latitude (average)']})
50
+ mmdblookup_object.add_attribute('longitude',
51
+ **{'type': 'float',
52
+ 'value': result_entry['country_info']['Longitude (average)']})
53
+ mmdblookup_object.add_attribute('text',
54
+ **{'type': 'text',
55
+ 'value': 'db_source: {}. build_db: {}. Latitude and longitude are country average.'.format(
56
+ result_entry['meta']['db_source'],
57
+ result_entry['meta']['build_db'])})
58
+ mmdblookup_object.add_reference(self.attribute['uuid'], 'related-to')
59
+ self.misp_event.add_object(mmdblookup_object)
60
+ if 'AutonomousSystemNumber' in result_entry['country']:
61
+ mmdblookup_object_asn = MISPObject('asn')
62
+ mmdblookup_object_asn.add_attribute('asn',
63
+ **{'type': 'text',
64
+ 'value': result_entry['country'][
65
+ 'AutonomousSystemNumber']})
66
+ mmdblookup_object_asn.add_attribute('description',
67
+ **{'type': 'text',
68
+ 'value': 'ASNOrganization: {}. db_source: {}. build_db: {}.'.format(
69
+ result_entry['country'][
70
+ 'AutonomousSystemOrganization'],
71
+ result_entry['meta']['db_source'],
72
+ result_entry['meta']['build_db'])})
73
+ mmdblookup_object_asn.add_reference(self.attribute['uuid'], 'related-to')
74
+ self.misp_event.add_object(mmdblookup_object_asn)
75
+
76
+
77
+ def check_url(url):
78
+ return "{}/".format(url) if not url.endswith('/') else url
79
+
80
+
81
+ def handler(q=False):
82
+ if q is False:
83
+ return False
84
+ request = json.loads(q)
85
+ if not request.get('attribute') or not check_input_attribute(request['attribute']):
86
+ return {'error': f'{standard_error_message}, which should contain at least a type, a value and an uuid.'}
87
+ attribute = request['attribute']
88
+ if attribute.get('type') == 'ip-src':
89
+ toquery = attribute['value']
90
+ elif attribute.get('type') == 'ip-src|port':
91
+ toquery = attribute['value'].split('|')[0]
92
+ elif attribute.get('type') == 'ip-dst':
93
+ toquery = attribute['value']
94
+ elif attribute.get('type') == 'ip-dst|port':
95
+ toquery = attribute['value'].split('|')[0]
96
+ else:
97
+ misperrors['error'] = 'There is no attribute of type ip-src or ip-dst provided as input'
98
+ return misperrors
99
+ api_url = check_url(request['config']['custom_API']) if 'config' in request and request['config'].get(
100
+ 'custom_API') else mmdblookup_url
101
+ r = requests.get("{}/geolookup/{}".format(api_url, toquery))
102
+ if r.status_code == 200:
103
+ mmdblookupresult = r.json()
104
+ if not mmdblookupresult or len(mmdblookupresult) == 0:
105
+ misperrors['error'] = 'Empty result returned by server'
106
+ return misperrors
107
+ if 'config' in request and request['config'].get('db_source_filter'):
108
+ db_source_filter = request['config'].get('db_source_filter')
109
+ mmdblookupresult = [entry for entry in mmdblookupresult if entry['meta']['db_source'] == db_source_filter]
110
+ if not mmdblookupresult or len(mmdblookupresult) == 0:
111
+ misperrors['error'] = 'There was no result with the selected db_source'
112
+ return misperrors
113
+ # Server might return one or multiple entries which could all be empty, we check if there is at least one
114
+ # non-empty result below
115
+ empty_result = True
116
+ for lookup_result_entry in mmdblookupresult:
117
+ if lookup_result_entry['country_info']:
118
+ empty_result = False
119
+ break
120
+ if empty_result:
121
+ misperrors['error'] = 'Empty result returned by server'
122
+ return misperrors
123
+ else:
124
+ misperrors['error'] = 'API not accessible - http status code {} was returned'.format(r.status_code)
125
+ return misperrors
126
+ parser = MmdbLookupParser(attribute, mmdblookupresult, api_url)
127
+ parser.parse_mmdblookup_information()
128
+ result = parser.get_result()
129
+ return result
130
+
131
+
132
+ def introspection():
133
+ return mispattributes
134
+
135
+
136
+ def version():
137
+ moduleinfo['config'] = moduleconfig
138
+ return moduleinfo
@@ -0,0 +1,44 @@
1
+ import json
2
+
3
+ misperrors = {'error': 'Error'}
4
+ mispattributes = {'input': ['hostname', 'domain'], 'output': ['ip-src',
5
+ 'ip-dst']}
6
+
7
+ # possible module-types: 'expansion', 'hover' or both
8
+ moduleinfo = {'version': '1', 'author': 'YOUR_NAME_HERE',
9
+ 'description': 'MODULE_DESCRIPTION',
10
+ 'module-type': ['expansion', 'hover']}
11
+
12
+ # config fields that your code expects from the site admin
13
+ moduleconfig = []
14
+
15
+
16
+ def handler(q=False):
17
+ if q is False:
18
+ return False
19
+ request = json.loads(q)
20
+ # You code that converts the data passed along in request
21
+ # input will be the query values
22
+ # output should be a list of dictionaries with types and values
23
+ # The types will be the types that the user can choose between
24
+ # for a given value
25
+ # An example would be a network indicator enrichment that returns
26
+ # a list of IP addresses and domain names.
27
+ # IP addresses would allow for attributes type ip-src and ip-dst,
28
+ # either of which the user can choose
29
+ # So the resulting list would look like this:
30
+ # r = {'results': [{'types': ['ip-src', 'ip-dst'], 'values': ips},
31
+ # {'types': ['domain'], 'values': domains}]}
32
+ r = {'results': [{'types': types1, 'values': values1},
33
+ {'types': types2, 'values': values2}]}
34
+ return r
35
+
36
+
37
+ def introspection():
38
+ return mispattributes
39
+
40
+
41
+ def version():
42
+ moduleinfo['config'] = moduleconfig
43
+ return moduleinfo
44
+
@@ -0,0 +1,152 @@
1
+ import json
2
+ import sys
3
+ import base64
4
+ #from distutils.util import strtobool
5
+
6
+ import io
7
+ import zipfile
8
+
9
+ from pymisp import PyMISP
10
+ from mwdblib import MWDB
11
+
12
+ misperrors = {'error': 'Error'}
13
+ mispattributes = {'input': ['attachment', 'malware-sample'], 'output': ['link']}
14
+ moduleinfo = {
15
+ 'version': '1',
16
+ 'author': 'Koen Van Impe',
17
+ 'description': 'Module to push malware samples to a MWDB instance',
18
+ 'module-type': ['expansion'],
19
+ 'name': 'MWDB Submit',
20
+ 'logo': '',
21
+ 'requirements': ['* mwdblib installed (pip install mwdblib) ; * (optional) keys.py file to add tags of events/attributes to MWDB * (optional) MWDB attribute created for the link back to MISP (defined in mwdb_misp_attribute)'],
22
+ 'features': 'An expansion module to push malware samples to a MWDB (https://github.com/CERT-Polska/mwdb-core) instance. This module does not push samples to a sandbox. This can be achieved via Karton (connected to the MWDB). Does: * Upload of attachment or malware sample to MWDB * Tags of events and/or attributes are added to MWDB. * Comment of the MISP attribute is added to MWDB. * A link back to the MISP event is added to MWDB via the MWDB attribute. * A link to the MWDB attribute is added as an enrichted attribute to the MISP event.',
23
+ 'references': [],
24
+ 'input': 'Attachment or malware sample',
25
+ 'output': 'Link attribute that points to the sample at the MWDB instane',
26
+ }
27
+
28
+ moduleconfig = ['mwdb_apikey', 'mwdb_url', 'mwdb_misp_attribute', 'mwdb_public', 'include_tags_event', 'include_tags_attribute']
29
+
30
+ pymisp_keys_file = "/var/www/MISP/PyMISP/"
31
+ mwdb_public_default = True
32
+
33
+ """
34
+ An expansion module to push malware samples to a MWDB (https://github.com/CERT-Polska/mwdb-core) instance.
35
+ This module does not push samples to a sandbox. This can be achieved via Karton (connected to the MWDB)
36
+
37
+ Does:
38
+ - Upload of attachment or malware sample to MWDB
39
+ - Tags of events and/or attributes are added to MWDB.
40
+ - Comment of the MISP attribute is added to MWDB.
41
+ - A link back to the MISP event is added to MWDB via the MWDB attribute.
42
+ - A link to the MWDB attribute is added as an enriched attribute to the MISP event.
43
+
44
+ Requires
45
+ - mwdblib installed (pip install mwdblib)
46
+ - (optional) keys.py file to add tags of events/attributes to MWDB
47
+ - (optional) MWDB "attribute" created for the link back to MISP (defined in mwdb_misp_attribute)
48
+ """
49
+
50
+
51
+ def handler(q=False):
52
+ if q is False:
53
+ return False
54
+ request = json.loads(q)
55
+
56
+ try:
57
+ data = request.get("data")
58
+ if 'malware-sample' in request:
59
+ # malicious samples are encrypted with zip (password infected) and then base64 encoded
60
+ sample_filename = request.get("malware-sample").split("|", 1)[0]
61
+ data = base64.b64decode(data)
62
+ fl = io.BytesIO(data)
63
+ zf = zipfile.ZipFile(fl)
64
+ sample_hashname = zf.namelist()[0]
65
+ data = zf.read(sample_hashname, b"infected")
66
+ zf.close()
67
+ elif 'attachment' in request:
68
+ # All attachments get base64 encoded
69
+ sample_filename = request.get("attachment")
70
+ data = base64.b64decode(data)
71
+
72
+ else:
73
+ misperrors['error'] = "No malware sample or attachment supplied"
74
+ return misperrors
75
+ except Exception:
76
+ misperrors['error'] = "Unable to process submited sample data"
77
+ return misperrors
78
+
79
+ if (request["config"].get("mwdb_apikey") is None) or (request["config"].get("mwdb_url") is None):
80
+ misperrors["error"] = "Missing MWDB API key or server URL"
81
+ return misperrors
82
+
83
+ mwdb_misp_attribute = request["config"].get("mwdb_misp_attribute")
84
+ mwdb_public = request["config"].get("mwdb_public", mwdb_public_default)
85
+
86
+ include_tags_event = request["config"].get("include_tags_event")
87
+ include_tags_attribute = request["config"].get("include_tags_attribute")
88
+ misp_event_id = request.get("event_id")
89
+ misp_attribute_uuid = request.get("attribute_uuid")
90
+ misp_attribute_comment = ""
91
+ mwdb_tags = []
92
+ misp_info = ""
93
+
94
+ try:
95
+ if include_tags_event:
96
+ sys.path.append(pymisp_keys_file)
97
+ from keys import misp_url, misp_key, misp_verifycert
98
+ misp = PyMISP(misp_url, misp_key, misp_verifycert, False)
99
+ misp_event = misp.get_event(misp_event_id)
100
+ if "Event" in misp_event:
101
+ misp_info = misp_event["Event"]["info"]
102
+ if "Tag" in misp_event["Event"]:
103
+ tags = misp_event["Event"]["Tag"]
104
+ for tag in tags:
105
+ if "misp-galaxy" not in tag["name"]:
106
+ mwdb_tags.append(tag["name"])
107
+ if include_tags_attribute:
108
+ sys.path.append(pymisp_keys_file)
109
+ from keys import misp_url, misp_key, misp_verifycert
110
+ misp = PyMISP(misp_url, misp_key, misp_verifycert, False)
111
+ misp_attribute = misp.get_attribute(misp_attribute_uuid)
112
+ if "Attribute" in misp_attribute:
113
+ if "Tag" in misp_attribute["Attribute"]:
114
+ tags = misp_attribute["Attribute"]["Tag"]
115
+ for tag in tags:
116
+ if "misp-galaxy" not in tag["name"]:
117
+ mwdb_tags.append(tag["name"])
118
+ misp_attribute_comment = misp_attribute["Attribute"]["comment"]
119
+ except Exception:
120
+ misperrors['error'] = "Unable to read PyMISP (keys.py) configuration file"
121
+ return misperrors
122
+
123
+ try:
124
+ mwdb = MWDB(api_key=request["config"].get("mwdb_apikey"), api_url=request["config"].get("mwdb_url"))
125
+ if mwdb_misp_attribute and len(mwdb_misp_attribute) > 0:
126
+ metakeys = {mwdb_misp_attribute: misp_event_id}
127
+ else:
128
+ metakeys = False
129
+ file_object = mwdb.upload_file(sample_filename, data, metakeys=metakeys, public=mwdb_public)
130
+ for tag in mwdb_tags:
131
+ file_object.add_tag(tag)
132
+ if len(misp_attribute_comment) < 1:
133
+ misp_attribute_comment = "MISP attribute {}".format(misp_attribute_uuid)
134
+ file_object.add_comment(misp_attribute_comment)
135
+ if len(misp_event) > 0:
136
+ file_object.add_comment("Fetched from event {} - {}".format(misp_event_id, misp_info))
137
+ mwdb_link = request["config"].get("mwdb_url").replace("/api", "/file/") + "{}".format(file_object.md5)
138
+ except Exception:
139
+ misperrors['error'] = "Unable to send sample to MWDB instance"
140
+ return misperrors
141
+
142
+ r = {'results': [{'types': 'link', 'values': mwdb_link, 'comment': 'Link to MWDB sample'}]}
143
+ return r
144
+
145
+
146
+ def introspection():
147
+ return mispattributes
148
+
149
+
150
+ def version():
151
+ moduleinfo['config'] = moduleconfig
152
+ return moduleinfo
@@ -0,0 +1,74 @@
1
+ import json
2
+ import binascii
3
+ import cv2
4
+ import np
5
+ import pytesseract
6
+
7
+ misperrors = {'error': 'Error'}
8
+ mispattributes = {'input': ['attachment'],
9
+ 'output': ['freetext']}
10
+ moduleinfo = {
11
+ 'version': '0.2',
12
+ 'author': 'Sascha Rommelfangen',
13
+ 'description': 'Module to process some optical character recognition on pictures.',
14
+ 'module-type': ['expansion'],
15
+ 'name': 'OCR Enrich',
16
+ 'logo': '',
17
+ 'requirements': ['cv2: The OpenCV python library.'],
18
+ 'features': 'The module takes an attachment attributes as input and process some optical character recognition on it. The text found is then passed to the Freetext importer to extract potential IoCs.',
19
+ 'references': [],
20
+ 'input': 'A picture attachment.',
21
+ 'output': 'Text and freetext fetched from the input picture.',
22
+ }
23
+
24
+ moduleconfig = []
25
+
26
+
27
+ def filter_decoded(decoded):
28
+ for line in decoded.split('\n'):
29
+ decoded_line = line.strip('\t\x0b\x0c\r ')
30
+ if decoded_line:
31
+ yield decoded_line
32
+
33
+
34
+ def handler(q=False):
35
+ if q is False:
36
+ return False
37
+ q = json.loads(q)
38
+ filename = q['attachment']
39
+ try:
40
+ img_array = np.frombuffer(binascii.a2b_base64(q['data']), np.uint8)
41
+ except Exception as e:
42
+ print(e)
43
+ err = "Couldn't fetch attachment (JSON 'data' is empty). Are you using the 'Query enrichment' action?"
44
+ misperrors['error'] = err
45
+ print(err)
46
+ return misperrors
47
+
48
+ image = img_array
49
+ image = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
50
+ try:
51
+ decoded = pytesseract.image_to_string(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
52
+ return {
53
+ 'results': [
54
+ {
55
+ 'types': ['freetext'],
56
+ 'values': list(filter_decoded(decoded)),
57
+ 'comment': f"OCR from file {filename}"
58
+ }
59
+ ]
60
+ }
61
+ except Exception as e:
62
+ print(e)
63
+ err = "Couldn't analyze file type. Only images are supported right now."
64
+ misperrors['error'] = err
65
+ return misperrors
66
+
67
+
68
+ def introspection():
69
+ return mispattributes
70
+
71
+
72
+ def version():
73
+ moduleinfo['config'] = moduleconfig
74
+ return moduleinfo