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,358 @@
1
+ import json
2
+ import logging
3
+ import sys
4
+
5
+ from passivetotal.common.utilities import is_ip
6
+
7
+
8
+ log = logging.getLogger('passivetotal')
9
+ log.setLevel(logging.DEBUG)
10
+ ch = logging.StreamHandler(sys.stdout)
11
+ ch.setLevel(logging.DEBUG)
12
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13
+ ch.setFormatter(formatter)
14
+ log.addHandler(ch)
15
+
16
+ misperrors = {'error': 'Error'}
17
+ mispattributes = {
18
+ 'input': ['hostname', 'domain', 'ip-src', 'ip-dst',
19
+ 'x509-fingerprint-sha1', 'email-src', 'email-dst',
20
+ 'target-email', 'whois-registrant-email',
21
+ 'whois-registrant-phone', 'text', 'whois-registrant-name',
22
+ 'whois-registrar', 'whois-creation-date'],
23
+ 'output': ['hostname', 'domain', 'ip-src', 'ip-dst',
24
+ 'x509-fingerprint-sha1', 'email-src', 'email-dst',
25
+ 'target-email', 'whois-registrant-email',
26
+ 'whois-registrant-phone', 'text', 'whois-registrant-name',
27
+ 'whois-registrar', 'whois-creation-date', 'md5', 'sha1',
28
+ 'sha256', 'link']
29
+ }
30
+ moduleinfo = {
31
+ 'version': '1.0',
32
+ 'author': 'Brandon Dixon',
33
+ 'description': 'The PassiveTotal MISP expansion module brings the datasets derived from Internet scanning directly into your MISP instance. This module supports passive DNS, historic SSL, WHOIS, and host attributes. In order to use the module, you must have a valid PassiveTotal account username and API key. Registration is free and can be done by visiting https://www.passivetotal.org/register',
34
+ 'module-type': ['expansion', 'hover'],
35
+ 'name': 'PassiveTotal Lookup',
36
+ 'logo': 'passivetotal.png',
37
+ 'requirements': ['Passivetotal python library', 'An access to the PassiveTotal API (apikey)'],
38
+ 'features': 'The PassiveTotal MISP expansion module brings the datasets derived from Internet scanning directly into your MISP instance. This module supports passive DNS, historic SSL, WHOIS, and host attributes. In order to use the module, you must have a valid PassiveTotal account username and API key. Registration is free and can be done by visiting https://www.passivetotal.org/register',
39
+ 'references': ['https://www.passivetotal.org/register'],
40
+ 'input': 'A MISP attribute included in the following list:\n- hostname\n- domain\n- ip-src\n- ip-dst\n- x509-fingerprint-sha1\n- email-src\n- email-dst\n- target-email\n- whois-registrant-email\n- whois-registrant-phone\n- text\n- whois-registrant-name\n- whois-registrar\n- whois-creation-date',
41
+ 'output': 'MISP attributes mapped from the result of the query on PassiveTotal, included in the following list:\n- hostname\n- domain\n- ip-src\n- ip-dst\n- x509-fingerprint-sha1\n- email-src\n- email-dst\n- target-email\n- whois-registrant-email\n- whois-registrant-phone\n- text\n- whois-registrant-name\n- whois-registrar\n- whois-creation-date\n- md5\n- sha1\n- sha256\n- link',
42
+ }
43
+ moduleconfig = ['username', 'api_key']
44
+ query_playbook = [
45
+ {'inputs': ['ip-src', 'ip-dst', 'hostname', 'domain'],
46
+ 'services': ['whois', 'ssl', 'dns', 'enrichment'],
47
+ 'name': 'generic'},
48
+ {'inputs': ['whois-registrant-email', 'whois-registrant-phone',
49
+ 'whois-registrant-name', 'email-src', 'email-dst',
50
+ 'target-email'],
51
+ 'services': ['whois'],
52
+ 'name': 'reverse-whois'},
53
+ {'inputs': ['x509-fingerprint-sha1'],
54
+ 'services': ['ssl'],
55
+ 'name': 'ssl-history'},
56
+ ]
57
+
58
+
59
+ def query_finder(request):
60
+ """Find the query value in the client request."""
61
+ for item in mispattributes['input']:
62
+ if not request.get(item, None):
63
+ continue
64
+
65
+ playbook = None
66
+ for x in query_playbook:
67
+ if item not in x['inputs']:
68
+ continue
69
+ playbook = x
70
+ break
71
+
72
+ return {'type': item, 'value': request.get(item), 'playbook': playbook}
73
+
74
+
75
+ def build_profile(request):
76
+ """Check the incoming request for a valid configuration."""
77
+ output = {'success': False}
78
+ config = request.get('config', None)
79
+ if not config:
80
+ misperrors['error'] = "Configuration is missing from the request."
81
+ return output
82
+
83
+ for item in moduleconfig:
84
+ if config.get(item, None):
85
+ continue
86
+ misperrors['error'] = "PassiveTotal authentication is missing."
87
+ return output
88
+
89
+ profile = {'success': True, 'config': config}
90
+ profile.update(query_finder(request))
91
+
92
+ return profile
93
+
94
+
95
+ def _generate_request_instance(conf, request_type):
96
+ """Automatically generate a request instance to use.
97
+
98
+ In the end, this saves us from having to load each request class in a
99
+ explicit way. Loading via a string is helpful to reduce the code per
100
+ call.
101
+
102
+ :param request_type: Type of client to load
103
+ :return: Loaded PassiveTotal client
104
+ """
105
+ pt_username = conf.get('username')
106
+ pt_api_key = conf.get('api_key')
107
+
108
+ class_lookup = {'dns': 'DnsRequest', 'whois': 'WhoisRequest',
109
+ 'ssl': 'SslRequest', 'enrichment': 'EnrichmentRequest',
110
+ 'attributes': 'AttributeRequest'}
111
+ class_name = class_lookup[request_type]
112
+ mod = __import__('passivetotal.libs.%s' % request_type,
113
+ fromlist=[class_name])
114
+ loaded = getattr(mod, class_name)
115
+ headers = {'PT-INTEGRATION': 'MISP'}
116
+ authenticated = loaded(pt_username, pt_api_key, headers=headers)
117
+ return authenticated
118
+
119
+
120
+ def _has_error(results):
121
+ """Check to see if there's an error in place and log it."""
122
+ if 'error' in results:
123
+ msg = "%s - %s" % (results['error']['message'],
124
+ results['error']['developer_message'])
125
+ misperrors['error'] = msg
126
+ return True
127
+
128
+ return False
129
+
130
+
131
+ def process_ssl_details(instance, query):
132
+ """Process details for a specific certificate."""
133
+ log.debug("SSL Details: starting")
134
+ values = list()
135
+ details = instance.get_ssl_certificate_details(query=query)
136
+ err = _has_error(details)
137
+ if err:
138
+ raise Exception("We hit an error, time to bail!")
139
+ if details.get('message') and details['message'].startswith('quota_exceeded'):
140
+ raise Exception("API quota exceeded.")
141
+ values = {value for value in details.values() if value}
142
+ txt = [{'types': ['ssl-cert-attributes'], 'values': list(values)}]
143
+ log.debug("SSL Details: ending")
144
+
145
+ return txt
146
+
147
+
148
+ def process_ssl_history(instance, query):
149
+ """Process the history for an SSL certificate."""
150
+ log.debug("SSL History: starting")
151
+
152
+ type_map = {
153
+ 'ip': ['ip-src', 'ip-dst'],
154
+ 'domain': ['domain', 'hostname'],
155
+ 'sha1': ['x509-fingerprint-sha1']
156
+ }
157
+
158
+ hits = {'ip': list(), 'sha1': list(), 'domain': list()}
159
+ history = instance.get_ssl_certificate_history(query=query)
160
+ err = _has_error(history)
161
+ if err:
162
+ raise Exception("We hit an error, time to bail!")
163
+ if history.get('message') and history['message'].startswith('quota_exceeded'):
164
+ raise Exception("API quota exceeded.")
165
+ for item in history.get('results', []):
166
+ hits['ip'] += item.get('ipAddresses', [])
167
+ hits['sha1'].append(item['sha1'])
168
+ hits['domain'] += item.get('domains', [])
169
+
170
+ tmp = list()
171
+ for key, value in hits.items():
172
+ txt = {'types': type_map[key], 'values': list(set(value))}
173
+ tmp.append(txt)
174
+
175
+ log.debug("SSL Details: ending")
176
+
177
+ return tmp
178
+
179
+
180
+ def process_whois_details(instance, query):
181
+ """Process the detail from the WHOIS record."""
182
+ log.debug("WHOIS Details: starting")
183
+ tmp = list()
184
+ details = instance.get_whois_details(query=query, compact_record=True)
185
+ err = _has_error(details)
186
+ if err:
187
+ raise Exception("We hit an error, time to bail!")
188
+ if details.get('message') and details['message'].startswith('quota_exceeded'):
189
+ raise Exception("API quota exceeded.")
190
+ if details.get('contactEmail', None):
191
+ tmp.append({'types': ['whois-registrant-email'], 'values': [details.get('contactEmail')]})
192
+ phones = details['compact']['telephone']['raw']
193
+ tmp.append({'types': ['whois-registrant-phone'], 'values': phones})
194
+ names = details['compact']['name']['raw']
195
+ tmp.append({'types': ['whois-registrant-name'], 'values': names})
196
+ if details.get('registrar', None):
197
+ tmp.append({'types': ['whois-registrar'], 'values': [details.get('registrar')]})
198
+ if details.get('registered', None):
199
+ tmp.append({'types': ['whois-creation-date'], 'values': [details.get('registered')]})
200
+ log.debug("WHOIS Details: ending")
201
+
202
+ return tmp
203
+
204
+
205
+ def process_whois_search(instance, query, qtype):
206
+ """Process a WHOIS search for a specific field value."""
207
+ log.debug("WHOIS Search: starting")
208
+ if qtype in ['whois-registrant-email', 'email-src', 'email-dst', 'target-email']:
209
+ field_type = 'email'
210
+ if qtype in ['whois-registrant-phone']:
211
+ field_type = 'phone'
212
+ if qtype in ['whois-registrant-name']:
213
+ field_type = 'name'
214
+
215
+ domains = list()
216
+ search = instance.search_whois_by_field(field=field_type, query=query)
217
+ err = _has_error(search)
218
+ if err:
219
+ raise Exception("We hit an error, time to bail!")
220
+ if search.get('message') and search['message'].startswith('quota_exceeded'):
221
+ raise Exception("API quota exceeded.")
222
+ for item in search.get('results', []):
223
+ domain = item.get('domain', None)
224
+ if not domain:
225
+ continue
226
+ domains.append(domain)
227
+
228
+ tmp = [{'types': ['hostname', 'domain'], 'values': list(set(domains))}]
229
+ log.debug("WHOIS Search: ending")
230
+
231
+ return tmp
232
+
233
+
234
+ def process_passive_dns(instance, query):
235
+ """Process passive DNS data."""
236
+ log.debug("Passive DNS: starting")
237
+ tmp = list()
238
+ pdns = instance.get_unique_resolutions(query=query)
239
+ err = _has_error(pdns)
240
+ if err:
241
+ raise Exception("We hit an error, time to bail!")
242
+ if pdns.get('message') and pdns['message'].startswith('quota_exceeded'):
243
+ raise Exception("API quota exceeded.")
244
+ if is_ip(query):
245
+ tmp = [{'types': ['domain', 'hostname'], 'values': pdns.get('results', [])}]
246
+ else:
247
+ tmp = [{'types': ['ip-src', 'ip-dst'], 'values': pdns.get('results', [])}]
248
+ log.debug("Passive DNS: ending")
249
+
250
+ return tmp
251
+
252
+
253
+ def process_osint(instance, query):
254
+ """Process OSINT links."""
255
+ log.debug("OSINT: starting")
256
+ urls = list()
257
+ osint = instance.get_osint(query=query)
258
+ err = _has_error(osint)
259
+ if err:
260
+ raise Exception("We hit an error, time to bail!")
261
+ if osint.get('message') and osint['message'].startswith('quota_exceeded'):
262
+ raise Exception("API quota exceeded.")
263
+ for item in osint.get('results', []):
264
+ urls.append(item['sourceUrl'])
265
+
266
+ tmp = [{'types': ['link'], 'values': urls}]
267
+ log.debug("OSINT: ending")
268
+
269
+ return tmp
270
+
271
+
272
+ def process_malware(instance, query):
273
+ """Process malware samples."""
274
+ log.debug("Malware: starting")
275
+ content = {'hashes': list(), 'urls': list()}
276
+ malware = instance.get_malware(query=query)
277
+ err = _has_error(malware)
278
+ if err:
279
+ raise Exception("We hit an error, time to bail!")
280
+ if malware.get('message') and malware['message'].startswith('quota_exceeded'):
281
+ raise Exception("API quota exceeded.")
282
+ for item in malware.get('results', []):
283
+ content['hashes'].append(item['sample'])
284
+ content['urls'].append(item['sourceUrl'])
285
+
286
+ tmp = [{'types': ['link'], 'values': content['urls']}]
287
+ hashes = {'md5': list(), 'sha1': list(), 'sha256': list()}
288
+ for h in content['hashes']:
289
+ if len(h) == 32:
290
+ hashes['md5'].append(h)
291
+ elif len(h) == 41:
292
+ hashes['sha1'].append(h)
293
+ elif len(h) == 64:
294
+ hashes['sha256'].append(h)
295
+ tmp += [{'types': ['md5'], 'values': hashes['md5']}]
296
+ tmp += [{'types': ['sha1'], 'values': hashes['sha1']}]
297
+ tmp += [{'types': ['sha256'], 'values': hashes['sha256']}]
298
+ log.debug("Malware: ending")
299
+
300
+ return tmp
301
+
302
+
303
+ def handler(q=False):
304
+ if not q:
305
+ return q
306
+
307
+ request = json.loads(q)
308
+ profile = build_profile(request)
309
+ if not profile['success']:
310
+ log.error(misperrors['error'])
311
+ return misperrors
312
+
313
+ output = {'results': list()}
314
+
315
+ instances = dict()
316
+ for service in profile['playbook']['services']:
317
+ instances[service] = _generate_request_instance(
318
+ profile['config'], service)
319
+
320
+ play_type = profile['playbook']['name']
321
+ query = profile['value']
322
+ qtype = profile['type']
323
+ try:
324
+ if play_type == 'generic':
325
+ results = process_passive_dns(instances['dns'], query)
326
+ output['results'] += results
327
+ results = process_whois_details(instances['whois'], query)
328
+ output['results'] += results
329
+ results = process_ssl_history(instances['ssl'], query)
330
+ output['results'] += results
331
+ results = process_osint(instances['enrichment'], query)
332
+ output['results'] += results
333
+ results = process_malware(instances['enrichment'], query)
334
+ output['results'] += results
335
+ elif play_type == 'reverse-whois':
336
+ results = process_whois_search(instances['whois'], query, qtype)
337
+ output['results'] += results
338
+ elif play_type == 'ssl-history':
339
+ results = process_ssl_details(instances['ssl'], query)
340
+ output['results'] += results
341
+ results = process_ssl_history(instances['ssl'], query)
342
+ output['results'] += results
343
+ else:
344
+ log.error("Unsupported query pattern issued.")
345
+ except Exception as e:
346
+ misperrors['error'] = e.__str__()
347
+ return misperrors
348
+
349
+ return output
350
+
351
+
352
+ def introspection():
353
+ return mispattributes
354
+
355
+
356
+ def version():
357
+ moduleinfo['config'] = moduleconfig
358
+ return moduleinfo
@@ -0,0 +1,58 @@
1
+ import json
2
+ import binascii
3
+ import np
4
+ import pdftotext
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 PDF document.',
14
+ 'module-type': ['expansion'],
15
+ 'name': 'PDF Enrich',
16
+ 'logo': 'pdf.jpg',
17
+ 'requirements': ['pdftotext: Python library to extract text from PDF.'],
18
+ 'features': 'The module reads the text contained in a PDF 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 PDF 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
+ pdf_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
+ pdf_file = io.BytesIO(pdf_array)
42
+ try:
43
+ pdf_content = "\n\n".join(pdftotext.PDF(pdf_file))
44
+ return {'results': [{'types': ['freetext'], 'values': pdf_content, 'comment': "PDF-to-text from file " + filename}]}
45
+ except Exception as e:
46
+ print(e)
47
+ err = "Couldn't analyze file as PDF. Error was: " + str(e)
48
+ misperrors['error'] = err
49
+ return misperrors
50
+
51
+
52
+ def introspection():
53
+ return mispattributes
54
+
55
+
56
+ def version():
57
+ moduleinfo['config'] = moduleconfig
58
+ return moduleinfo
@@ -0,0 +1,65 @@
1
+ import json
2
+ import binascii
3
+ import np
4
+ from pptx import Presentation
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 .pptx document.',
14
+ 'module-type': ['expansion'],
15
+ 'name': 'PPTX Enrich',
16
+ 'logo': 'pptx.png',
17
+ 'requirements': ['pptx: Python library to read PowerPoint files.'],
18
+ 'features': 'The module reads the text contained in a .pptx 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 .pptx 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
+ pptx_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
+ ppt_content = ""
42
+ ppt_file = io.BytesIO(pptx_array)
43
+ try:
44
+ ppt = Presentation(ppt_file)
45
+ for slide in ppt.slides:
46
+ for shape in slide.shapes:
47
+ if hasattr(shape, "text"):
48
+ print(shape.text)
49
+ ppt_content = ppt_content + "\n" + shape.text
50
+ return {'results': [{'types': ['freetext'], 'values': ppt_content, 'comment': ".pptx-to-text from file " + filename},
51
+ {'types': ['text'], 'values': ppt_content, 'comment': ".pptx-to-text from file " + filename}]}
52
+ except Exception as e:
53
+ print(e)
54
+ err = "Couldn't analyze file as .pptx. Error was: " + str(e)
55
+ misperrors['error'] = err
56
+ return misperrors
57
+
58
+
59
+ def introspection():
60
+ return mispattributes
61
+
62
+
63
+ def version():
64
+ moduleinfo['config'] = moduleconfig
65
+ return moduleinfo