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,189 @@
1
+ import requests
2
+ import json
3
+ import sys
4
+ from . import check_input_attribute, standard_error_message
5
+ from collections import defaultdict
6
+ from pymisp import MISPAttribute, MISPEvent, MISPObject
7
+ from requests.auth import HTTPBasicAuth
8
+
9
+ sys.path.append('./')
10
+
11
+ misperrors = {'error': 'Error'}
12
+ mispattributes = {'input': ['ip-src', 'ip-dst', 'vulnerability', 'md5', 'sha1', 'sha256', 'domain', 'hostname', 'url'],
13
+ 'output': ['ip-src', 'ip-dst', 'text', 'domain'],
14
+ 'format': 'misp_standard'}
15
+
16
+ # possible module-types: 'expansion', 'hover' or both
17
+ moduleinfo = {
18
+ 'version': '2',
19
+ 'author': 'Joerg Stephan (@johest)',
20
+ 'description': 'An expansion module for IBM X-Force Exchange.',
21
+ 'module-type': ['expansion', 'hover'],
22
+ 'name': 'IBM X-Force Exchange Lookup',
23
+ 'logo': 'xforce.png',
24
+ 'requirements': ['An access to the X-Force API (apikey)'],
25
+ 'features': 'This module takes a MISP attribute as input to query the X-Force API. The API returns then additional information known in their threats data, that is mapped into MISP attributes.',
26
+ 'references': ['https://exchange.xforce.ibmcloud.com/'],
27
+ 'input': 'A MISP attribute included in the following list:\n- ip-src\n- ip-dst\n- vulnerability\n- md5\n- sha1\n- sha256',
28
+ 'output': 'MISP attributes mapped from the result of the query on X-Force Exchange.',
29
+ }
30
+
31
+ # config fields that your code expects from the site admin
32
+ moduleconfig = ["apikey", "apipassword"]
33
+
34
+
35
+ class XforceExchange():
36
+ def __init__(self, attribute, apikey, apipassword):
37
+ self.base_url = "https://api.xforce.ibmcloud.com"
38
+ self.misp_event = MISPEvent()
39
+ self.attribute = MISPAttribute()
40
+ self.attribute.from_dict(**attribute)
41
+ self._apikey = apikey
42
+ self._apipassword = apipassword
43
+ self.result = {}
44
+ self.objects = defaultdict(dict)
45
+ self.status_mapping = {403: "Access denied, please check if your authentication is valid and if you did not reach the limit of queries.",
46
+ 404: "No result found for your query."}
47
+
48
+ def parse(self):
49
+ mapping = {'url': '_parse_url', 'vulnerability': '_parse_vulnerability'}
50
+ mapping.update(dict.fromkeys(('md5', 'sha1', 'sha256'), '_parse_hash'))
51
+ mapping.update(dict.fromkeys(('domain', 'hostname'), '_parse_dns'))
52
+ mapping.update(dict.fromkeys(('ip-src', 'ip-dst'), '_parse_ip'))
53
+ to_call = mapping[self.attribute.type]
54
+ getattr(self, to_call)(self.attribute.value)
55
+
56
+ def get_result(self):
57
+ if not self.misp_event.objects:
58
+ if 'error' not in self.result:
59
+ self.result['error'] = "No additional data found on Xforce Exchange."
60
+ return self.result
61
+ self.misp_event.add_attribute(**self.attribute)
62
+ event = json.loads(self.misp_event.to_json())
63
+ result = {key: event[key] for key in ('Attribute', 'Object') if (key in event and event[key])}
64
+ return {'results': result}
65
+
66
+ def _api_call(self, url):
67
+ try:
68
+ result = requests.get(url, auth=HTTPBasicAuth(self._apikey, self._apipassword))
69
+ except Exception as e:
70
+ self.result['error'] = e
71
+ return
72
+ status_code = result.status_code
73
+ if status_code != 200:
74
+ try:
75
+ self.result['error'] = self.status_mapping[status_code]
76
+ except KeyError:
77
+ self.result['error'] = 'An error with the API has occurred.'
78
+ return
79
+ return result.json()
80
+
81
+ def _create_file(self, malware, relationship):
82
+ file_object = MISPObject('file')
83
+ for key, relation in zip(('filepath', 'md5'), ('filename', 'md5')):
84
+ file_object.add_attribute(relation, malware[key])
85
+ file_object.add_reference(self.attribute.uuid, relationship)
86
+ return file_object
87
+
88
+ def _create_url(self, malware):
89
+ url_object = MISPObject('url')
90
+ for key, relation in zip(('uri', 'domain'), ('url', 'domain')):
91
+ url_object.add_attribute(relation, malware[key])
92
+ attributes = tuple(f'{attribute.object_relation}_{attribute.value}' for attribute in url_object.attributes)
93
+ if attributes in self.objects['url']:
94
+ del url_object
95
+ return self.objects['url'][attributes]
96
+ url_uuid = url_object.uuid
97
+ self.misp_event.add_object(**url_object)
98
+ self.objects['url'][attributes] = url_uuid
99
+ return url_uuid
100
+
101
+ def _fetch_types(self, value):
102
+ if self.attribute.type in ('ip-src', 'ip-dst'):
103
+ return 'ip', 'domain', self.attribute.value
104
+ return 'domain', 'ip', value
105
+
106
+ def _handle_file(self, malware, relationship):
107
+ file_object = self._create_file(malware, relationship)
108
+ attributes = tuple(f'{attribute.object_relation}_{attribute.value}' for attribute in file_object.attributes)
109
+ if attributes in self.objects['file']:
110
+ self.objects['file'][attributes].add_reference(self._create_url(malware), 'dropped-by')
111
+ del file_object
112
+ return
113
+ file_object.add_reference(self._create_url(malware), 'dropped-by')
114
+ self.objects['file'][attributes] = file_object
115
+ self.misp_event.add_object(**file_object)
116
+
117
+ def _parse_dns(self, value):
118
+ dns_result = self._api_call(f'{self.base_url}/resolve/{value}')
119
+ if dns_result.get('Passive') and dns_result['Passive'].get('records'):
120
+ itype, ftype, value = self._fetch_types(dns_result['Passive']['query'])
121
+ misp_object = MISPObject('domain-ip')
122
+ misp_object.add_attribute(itype, value)
123
+ for record in dns_result['Passive']['records']:
124
+ misp_object.add_attribute(ftype, record['value'])
125
+ misp_object.add_reference(self.attribute.uuid, 'related-to')
126
+ self.misp_event.add_object(**misp_object)
127
+
128
+ def _parse_hash(self, value):
129
+ malware_result = self._api_call(f'{self.base_url}/malware/{value}')
130
+ if malware_result and malware_result.get('malware'):
131
+ malware_report = malware_result['malware']
132
+ for malware in malware_report.get('origins', {}).get('CnCServers', {}).get('rows', []):
133
+ self._handle_file(malware, 'related-to')
134
+
135
+ def _parse_ip(self, value):
136
+ self._parse_dns(value)
137
+ self._parse_malware(value, 'ipr')
138
+
139
+ def _parse_malware(self, value, feature):
140
+ malware_result = self._api_call(f'{self.base_url}/{feature}/malware/{value}')
141
+ if malware_result and malware_result.get('malware'):
142
+ for malware in malware_result['malware']:
143
+ self._handle_file(malware, 'associated-with')
144
+
145
+ def _parse_url(self, value):
146
+ self._parse_dns(value)
147
+ self._parse_malware(value, 'url')
148
+
149
+ def _parse_vulnerability(self, value):
150
+ vulnerability_result = self._api_call(f'{self.base_url}/vulnerabilities/search/{value}')
151
+ if vulnerability_result:
152
+ for vulnerability in vulnerability_result:
153
+ misp_object = MISPObject('vulnerability')
154
+ for code in vulnerability['stdcode']:
155
+ misp_object.add_attribute('id', code)
156
+ for feature, relation in zip(('title', 'description', 'temporal_score'),
157
+ ('summary', 'description', 'cvss-score')):
158
+ misp_object.add_attribute(relation, vulnerability[feature])
159
+ for reference in vulnerability['references']:
160
+ misp_object.add_attribute('references', reference['link_target'])
161
+ misp_object.add_reference(self.attribute.uuid, 'related-to')
162
+ self.misp_event.add_object(**misp_object)
163
+
164
+
165
+ def handler(q=False):
166
+ if q is False:
167
+ return False
168
+ request = json.loads(q)
169
+ if not request.get('config') or not (request['config'].get('apikey') and request['config'].get('apipassword')):
170
+ misperrors['error'] = 'An API authentication is required (key and password).'
171
+ return misperrors
172
+ key = request["config"]["apikey"]
173
+ password = request['config']['apipassword']
174
+ if not request.get('attribute') or not check_input_attribute(request['attribute']):
175
+ return {'error': f'{standard_error_message} which should contain at least a type, a value and an uuid.'}
176
+ if request['attribute']['type'] not in mispattributes['input']:
177
+ return {'error': 'Unsupported attribute type.'}
178
+ parser = XforceExchange(request['attribute'], key, password)
179
+ parser.parse()
180
+ return parser.get_result()
181
+
182
+
183
+ def introspection():
184
+ return mispattributes
185
+
186
+
187
+ def version():
188
+ moduleinfo['config'] = moduleconfig
189
+ return moduleinfo
@@ -0,0 +1,63 @@
1
+ import json
2
+ import binascii
3
+ import np
4
+ import pandas
5
+ import io
6
+
7
+ misperrors = {'error': 'Error'}
8
+ mispattributes = {'input': ['attachment'],
9
+ 'output': ['freetext', 'text']}
10
+ moduleinfo = {
11
+ 'version': '0.1',
12
+ 'author': 'Sascha Rommelfangen',
13
+ 'description': 'Module to extract freetext from a .xlsx document.',
14
+ 'module-type': ['expansion'],
15
+ 'name': 'XLXS Enrich',
16
+ 'logo': 'xlsx.png',
17
+ 'requirements': ['pandas: Python library to perform data analysis, time series and statistics.'],
18
+ 'features': 'The module reads the text contained in a .xlsx document. The result is passed to the freetext import parser so IoCs can be extracted out of it.',
19
+ 'references': [],
20
+ 'input': 'Attachment attribute containing a .xlsx document.',
21
+ 'output': 'Text and freetext parsed from the document.',
22
+ }
23
+
24
+ moduleconfig = []
25
+
26
+
27
+ def handler(q=False):
28
+ if q is False:
29
+ return False
30
+ q = json.loads(q)
31
+ filename = q['attachment']
32
+ try:
33
+ xlsx_array = np.frombuffer(binascii.a2b_base64(q['data']), np.uint8)
34
+ except Exception as e:
35
+ print(e)
36
+ err = "Couldn't fetch attachment (JSON 'data' is empty). Are you using the 'Query enrichment' action?"
37
+ misperrors['error'] = err
38
+ print(err)
39
+ return misperrors
40
+
41
+ xls_content = ""
42
+ xls_file = io.BytesIO(xlsx_array)
43
+ pandas.set_option('display.max_colwidth', -1)
44
+ try:
45
+ xls = pandas.read_excel(xls_file)
46
+ xls_content = xls.to_string(max_rows=None)
47
+ print(xls_content)
48
+ return {'results': [{'types': ['freetext'], 'values': xls_content, 'comment': ".xlsx-to-text from file " + filename},
49
+ {'types': ['text'], 'values': xls_content, 'comment': ".xlsx-to-text from file " + filename}]}
50
+ except Exception as e:
51
+ print(e)
52
+ err = "Couldn't analyze file as .xlsx. Error was: " + str(e)
53
+ misperrors['error'] = err
54
+ return misperrors
55
+
56
+
57
+ def introspection():
58
+ return mispattributes
59
+
60
+
61
+ def version():
62
+ moduleinfo['config'] = moduleconfig
63
+ return moduleinfo
@@ -0,0 +1,70 @@
1
+ import json
2
+ import re
3
+ try:
4
+ import yara
5
+ except (OSError, ImportError):
6
+ print("yara is missing, use 'pip3 install -I -r REQUIREMENTS' from the root of this repository to install it.")
7
+
8
+ misperrors = {'error': 'Error'}
9
+ moduleinfo = {
10
+ 'version': '1',
11
+ 'author': 'Christian STUDER',
12
+ 'description': 'jj',
13
+ 'module-type': ['expansion', 'hover'],
14
+ 'name': 'YARA Rule Generator',
15
+ 'require_standard_format': True,
16
+ 'logo': 'yara.png',
17
+ 'requirements': ['yara-python python library'],
18
+ 'features': "The module takes a hash attribute (md5, sha1, sha256, imphash) as input, and is returning a YARA rule from it. This YARA rule is also validated using the same method as in 'yara_syntax_validator' module.\nBoth hover and expansion functionalities are supported with this module, where the hover part is displaying the resulting YARA rule and the expansion part allows you to add the rule as a new attribute, as usual with expansion modules.",
19
+ 'references': ['https://virustotal.github.io/yara/', 'https://github.com/virustotal/yara-python'],
20
+ 'input': 'MISP Hash attribute (md5, sha1, sha256, imphash, or any of the composite attribute with filename and one of the previous hash type).',
21
+ 'output': 'YARA rule.',
22
+ }
23
+ moduleconfig = []
24
+ mispattributes = {'input': ['md5', 'sha1', 'sha256', 'filename|md5', 'filename|sha1', 'filename|sha256', 'imphash'], 'output': ['yara']}
25
+
26
+
27
+ def extract_input_attribute(request):
28
+ for input_type in mispattributes['input']:
29
+ if input_type in request:
30
+ return input_type, request[input_type]
31
+
32
+
33
+ def get_hash_condition(hashtype, hashvalue):
34
+ hashvalue = hashvalue.lower()
35
+ required_module, params = ('pe', '()') if hashtype == 'imphash' else ('hash', '(0, filesize)')
36
+ return '{}.{}{} == "{}"'.format(required_module, hashtype, params, hashvalue), required_module
37
+
38
+
39
+ def handler(q=False):
40
+ if q is False:
41
+ return False
42
+ request = json.loads(q)
43
+ attribute = extract_input_attribute(request)
44
+ if attribute is None:
45
+ return {'error': f'Wrong input type, please choose in the following: {", ".join(mispattributes["input"])}'}
46
+ uuid = request.pop('attribute_uuid') if 'attribute_uuid' in request else None
47
+ attribute_type, value = attribute
48
+ if 'filename' in attribute_type:
49
+ _, attribute_type = attribute_type.split('|')
50
+ _, value = value.split('|')
51
+ condition, required_module = get_hash_condition(attribute_type, value)
52
+ import_section = 'import "{}"'.format(required_module)
53
+ rule_start = '%s\r\nrule %s_%s {' % (import_section, attribute_type.upper(), re.sub(r'\W+', '_', uuid)) if uuid else '%s\r\nrule %s {' % (import_section, attribute_type.upper())
54
+ condition = '\tcondition:\r\n\t\t{}'.format(condition)
55
+ rule = '\r\n'.join([rule_start, condition, '}'])
56
+ try:
57
+ yara.compile(source=rule)
58
+ except Exception as e:
59
+ misperrors['error'] = 'Syntax error: {}'.format(e)
60
+ return misperrors
61
+ return {'results': [{'types': mispattributes['output'], 'values': rule}]}
62
+
63
+
64
+ def introspection():
65
+ return mispattributes
66
+
67
+
68
+ def version():
69
+ moduleinfo['config'] = moduleconfig
70
+ return moduleinfo
@@ -0,0 +1,49 @@
1
+ import json
2
+ try:
3
+ import yara
4
+ except (OSError, ImportError):
5
+ print("yara is missing, use 'pip3 install -I -r REQUIREMENTS' from the root of this repository to install it.")
6
+
7
+ misperrors = {'error': 'Error'}
8
+ mispattributes = {'input': ['yara'], 'output': ['text']}
9
+ moduleinfo = {
10
+ 'version': '0.1',
11
+ 'author': 'Dennis Rand',
12
+ 'description': 'An expansion hover module to perform a syntax check on if yara rules are valid or not.',
13
+ 'module-type': ['hover'],
14
+ 'name': 'YARA Syntax Validator',
15
+ 'logo': 'yara.png',
16
+ 'requirements': ['yara_python python library'],
17
+ 'features': 'This modules simply takes a YARA rule as input, and checks its syntax. It returns then a confirmation if the syntax is valid, otherwise the syntax error is displayed.',
18
+ 'references': ['http://virustotal.github.io/yara/'],
19
+ 'input': 'YARA rule attribute.',
20
+ 'output': 'Text to inform users if their rule is valid.',
21
+ }
22
+ moduleconfig = []
23
+
24
+
25
+ def handler(q=False):
26
+ if q is False:
27
+ return False
28
+ request = json.loads(q)
29
+ if not request.get('yara'):
30
+ misperrors['error'] = 'Yara rule missing'
31
+ return misperrors
32
+
33
+ try:
34
+ yara.compile(source=request.get('yara'))
35
+ summary = ("Syntax valid")
36
+ except Exception as e:
37
+ summary = ("Syntax error: " + str(e))
38
+
39
+ r = {'results': [{'types': mispattributes['output'], 'values': summary}]}
40
+ return r
41
+
42
+
43
+ def introspection():
44
+ return mispattributes
45
+
46
+
47
+ def version():
48
+ moduleinfo['config'] = moduleconfig
49
+ return moduleinfo
@@ -0,0 +1,196 @@
1
+ import json
2
+ import logging
3
+
4
+ try:
5
+ import pyeti
6
+ except ImportError:
7
+ print("pyeti module not installed.")
8
+
9
+ from pymisp import MISPEvent, MISPObject
10
+
11
+ misperrors = {'error': 'Error'}
12
+
13
+ mispattributes = {'input': ['AS', 'ip-src', 'ip-dst', 'hostname', 'domain', 'sha256', 'sha1', 'md5', 'url'],
14
+ 'format': 'misp_standard'
15
+ }
16
+ # possible module-types: 'expansion', 'hover' or both
17
+ moduleinfo = {
18
+ 'version': '1',
19
+ 'author': 'Sebastien Larinier @sebdraven',
20
+ 'description': 'Module to process a query on Yeti.',
21
+ 'module-type': ['expansion', 'hover'],
22
+ 'name': 'Yeti Lookup',
23
+ 'logo': 'yeti.png',
24
+ 'requirements': ['pyeti', 'API key '],
25
+ 'features': 'This module add context and links between observables using yeti',
26
+ 'references': ['https://github.com/yeti-platform/yeti', 'https://github.com/sebdraven/pyeti'],
27
+ 'input': 'A domain, hostname,IP, sha256,sha1, md5, url of MISP attribute.',
28
+ 'output': 'MISP attributes and objects fetched from the Yeti instances.',
29
+ }
30
+
31
+ moduleconfig = ['apikey', 'url']
32
+
33
+
34
+ class Yeti():
35
+
36
+ def __init__(self, url, key, attribute):
37
+ self.misp_mapping = {'Ip': 'ip-dst', 'Domain': 'domain', 'Hostname': 'hostname', 'Url': 'url',
38
+ 'AutonomousSystem': 'AS', 'File': 'sha256'}
39
+ self.yeti_client = pyeti.YetiApi(url=url, api_key=key)
40
+ self.attribute = attribute
41
+ self.misp_event = MISPEvent()
42
+ self.misp_event.add_attribute(**attribute)
43
+
44
+ def search(self, value):
45
+ obs = self.yeti_client.observable_search(value=value)
46
+ if obs:
47
+ return obs[0]
48
+
49
+ def get_neighboors(self, obs_id):
50
+ neighboors = self.yeti_client.neighbors_observables(obs_id)
51
+ if neighboors and 'objs' in neighboors:
52
+ links_by_id = {link['dst']['id']: (link['description'], 'dst') for link in neighboors['links']
53
+ if link['dst']['id'] != obs_id}
54
+ links_by_id.update({link['src']['id']: (link['description'], 'src') for link in neighboors['links']
55
+ if link['src']['id'] != obs_id})
56
+
57
+ for n in neighboors['objs']:
58
+ yield n, links_by_id[n['id']]
59
+
60
+ def parse_yeti_result(self):
61
+ obs = self.search(self.attribute['value'])
62
+
63
+ for obs_to_add, link in self.get_neighboors(obs['id']):
64
+ object_misp_domain_ip = self.__get_object_domain_ip(obs_to_add)
65
+ if object_misp_domain_ip:
66
+ self.misp_event.add_object(object_misp_domain_ip)
67
+ continue
68
+ object_misp_url = self.__get_object_url(obs_to_add)
69
+ if object_misp_url:
70
+ self.misp_event.add_object(object_misp_url)
71
+ continue
72
+ if link[0] == 'NS record':
73
+ object_ns_record = self.__get_object_ns_record(obs_to_add, link[1])
74
+ if object_ns_record:
75
+ self.misp_event.add_object(object_ns_record)
76
+ continue
77
+ self.__get_attribute(obs_to_add, link[0])
78
+
79
+ def get_result(self):
80
+ event = json.loads(self.misp_event.to_json())
81
+ results = {key: event[key] for key in ('Attribute', 'Object') if key in event}
82
+ return results
83
+
84
+ def __get_attribute(self, obs_to_add, link):
85
+
86
+ try:
87
+ type_attr = self.misp_mapping[obs_to_add['type']]
88
+ value = None
89
+ if obs_to_add['type'] == 'File':
90
+ value = obs_to_add['value'].split(':')[1]
91
+ else:
92
+ value = obs_to_add['value']
93
+ attr = self.misp_event.add_attribute(value=value, type=type_attr)
94
+ attr.comment = '%s: %s' % (link, self.attribute['value'])
95
+ except KeyError:
96
+ logging.error('type not found %s' % obs_to_add['type'])
97
+ return
98
+
99
+ for t in obs_to_add['tags']:
100
+ self.misp_event.add_attribute_tag(t['name'], attr['uuid'])
101
+
102
+ def __get_object_domain_ip(self, obj_to_add):
103
+ if (obj_to_add['type'] == 'Ip' and self.attribute['type'] in ['hostname', 'domain']) or \
104
+ (obj_to_add['type'] in ('Hostname', 'Domain') and self.attribute['type'] in ('ip-src', 'ip-dst')):
105
+ domain_ip_object = MISPObject('domain-ip')
106
+ domain_ip_object.add_attribute(self.__get_relation(obj_to_add),
107
+ obj_to_add['value'])
108
+ domain_ip_object.add_attribute(self.__get_relation(self.attribute, is_yeti_object=False),
109
+ self.attribute['value'])
110
+ domain_ip_object.add_reference(self.attribute['uuid'], 'related_to')
111
+
112
+ return domain_ip_object
113
+
114
+ def __get_object_url(self, obj_to_add):
115
+ if (obj_to_add['type'] == 'Url' and self.attribute['type'] in ['hostname', 'domain', 'ip-src', 'ip-dst']) or (
116
+ obj_to_add['type'] in ('Hostname', 'Domain', 'Ip') and self.attribute['type'] == 'url'
117
+ ):
118
+ url_object = MISPObject('url')
119
+ obj_relation = self.__get_relation(obj_to_add)
120
+ if obj_relation:
121
+ url_object.add_attribute(obj_relation, obj_to_add['value'])
122
+ obj_relation = self.__get_relation(self.attribute, is_yeti_object=False)
123
+ if obj_relation:
124
+ url_object.add_attribute(obj_relation,
125
+ self.attribute['value'])
126
+ url_object.add_reference(self.attribute['uuid'], 'related_to')
127
+
128
+ return url_object
129
+
130
+ def __get_object_ns_record(self, obj_to_add, link):
131
+ queried_domain = None
132
+ ns_domain = None
133
+ object_dns_record = MISPObject('dns-record')
134
+ if link == 'dst':
135
+ queried_domain = self.attribute['value']
136
+ ns_domain = obj_to_add['value']
137
+ elif link == 'src':
138
+ queried_domain = obj_to_add['value']
139
+ ns_domain = self.attribute['value']
140
+ if queried_domain and ns_domain:
141
+ object_dns_record.add_attribute('queried-domain', queried_domain)
142
+ object_dns_record.add_attribute('ns-record', ns_domain)
143
+ object_dns_record.add_reference(self.attribute['uuid'], 'related_to')
144
+
145
+ return object_dns_record
146
+
147
+ def __get_relation(self, obj, is_yeti_object=True):
148
+ if is_yeti_object:
149
+ type_attribute = self.misp_mapping[obj['type']]
150
+ else:
151
+ type_attribute = obj['type']
152
+ if type_attribute == 'ip-src' or type_attribute == 'ip-dst':
153
+ return 'ip'
154
+ elif 'domain' == type_attribute:
155
+ return 'domain'
156
+ elif 'hostname' == type_attribute:
157
+ return 'domain'
158
+ elif type_attribute == 'url':
159
+ return type_attribute
160
+
161
+
162
+ def handler(q=False):
163
+ if q is False:
164
+ return False
165
+
166
+ apikey = None
167
+ yeti_url = None
168
+ yeti_client = None
169
+
170
+ request = json.loads(q)
171
+ attribute = request['attribute']
172
+ if attribute['type'] not in mispattributes['input']:
173
+ return {'error': 'Unsupported attributes type'}
174
+
175
+ if 'config' in request and 'url' in request['config']:
176
+ yeti_url = request['config']['url']
177
+ if 'config' in request and 'apikey' in request['config']:
178
+ apikey = request['config']['apikey']
179
+ if apikey and yeti_url:
180
+ yeti_client = Yeti(yeti_url, apikey, attribute)
181
+
182
+ if yeti_client:
183
+ yeti_client.parse_yeti_result()
184
+ return {'results': yeti_client.get_result()}
185
+ else:
186
+ misperrors['error'] = 'Yeti Config Error'
187
+ return misperrors
188
+
189
+
190
+ def version():
191
+ moduleinfo['config'] = moduleconfig
192
+ return moduleinfo
193
+
194
+
195
+ def introspection():
196
+ return mispattributes
@@ -0,0 +1,3 @@
1
+ __all__ = ['cef_export', 'mass_eql_export', 'liteexport', 'goamlexport', 'threat_connect_export', 'pdfexport',
2
+ 'threatStream_misp_export', 'osqueryexport', 'nexthinkexport', 'vt_graph', 'defender_endpoint_export',
3
+ 'virustotal_collections', 'yara_export', 'cisco_firesight_manager_ACL_rule_export']
@@ -0,0 +1,93 @@
1
+ import json
2
+ import base64
3
+ import datetime
4
+
5
+ misperrors = {'error': 'Error'}
6
+
7
+ # possible module-types: 'expansion', 'hover' or both
8
+ moduleinfo = {
9
+ 'version': '1',
10
+ 'author': 'Hannah Ward',
11
+ 'description': 'Module to export a MISP event in CEF format.',
12
+ 'module-type': ['export'],
13
+ 'name': 'CEF Export',
14
+ 'logo': '',
15
+ 'requirements': [],
16
+ 'features': 'The module takes a MISP event in input, to look every attribute. Each attribute matching with some predefined types is then exported in Common Event Format.\nThus, there is no particular feature concerning MISP Events since any event can be exported. However, 4 configuration parameters recognized by CEF format are required and should be provided by users before exporting data: the device vendor, product and version, as well as the default severity of data.',
17
+ 'references': ['https://community.softwaregrp.com/t5/ArcSight-Connectors/ArcSight-Common-Event-Format-CEF-Guide/ta-p/1589306?attachment-id=65537'],
18
+ 'input': 'MISP Event attributes',
19
+ 'output': 'Common Event Format file',
20
+ }
21
+
22
+ # config fields that your code expects from the site admin
23
+ moduleconfig = ["Default_Severity", "Device_Vendor", "Device_Product", "Device_Version"]
24
+
25
+ cefmapping = {"ip-src": "src", "ip-dst": "dst", "hostname": "dhost", "domain": "dhost",
26
+ "md5": "fileHash", "sha1": "fileHash", "sha256": "fileHash",
27
+ "url": "request"}
28
+
29
+ mispattributes = {'input': list(cefmapping.keys())}
30
+ outputFileExtension = "cef"
31
+ responseType = "application/txt"
32
+
33
+
34
+ def handler(q=False):
35
+ if q is False:
36
+ return False
37
+ request = json.loads(q)
38
+ if "config" in request:
39
+ config = request["config"]
40
+ else:
41
+ config = {"Default_Severity": 1, "Device_Vendor": "MISP",
42
+ "Device_Product": "MISP", "Device_Version": 1}
43
+
44
+ data = request["data"]
45
+ response = ""
46
+ for ev in data:
47
+ event = ev["Attribute"]
48
+ for attr in event:
49
+ if attr["type"] in cefmapping:
50
+ response += "{} host CEF:0|{}|{}|{}|{}|{}|{}|{}={}\n".format(
51
+ datetime.datetime.fromtimestamp(int(attr["timestamp"])).strftime("%b %d %H:%M:%S"),
52
+ config["Device_Vendor"],
53
+ config["Device_Product"],
54
+ config["Device_Version"],
55
+ attr["category"],
56
+ attr["category"],
57
+ config["Default_Severity"],
58
+ cefmapping[attr["type"]],
59
+ attr["value"],
60
+ )
61
+
62
+ r = {"response": [], "data": str(base64.b64encode(bytes(response, 'utf-8')), 'utf-8')}
63
+ return r
64
+
65
+
66
+ def introspection():
67
+ modulesetup = {}
68
+ try:
69
+ responseType
70
+ modulesetup['responseType'] = responseType
71
+ except NameError:
72
+ pass
73
+ try:
74
+ userConfig
75
+ modulesetup['userConfig'] = userConfig
76
+ except NameError:
77
+ pass
78
+ try:
79
+ outputFileExtension
80
+ modulesetup['outputFileExtension'] = outputFileExtension
81
+ except NameError:
82
+ pass
83
+ try:
84
+ inputSource
85
+ modulesetup['inputSource'] = inputSource
86
+ except NameError:
87
+ pass
88
+ return modulesetup
89
+
90
+
91
+ def version():
92
+ moduleinfo['config'] = moduleconfig
93
+ return moduleinfo