mirror of https://github.com/MISP/misp-modules
142 lines
4.0 KiB
Python
142 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Copyright 2022 Google Inc. All Rights Reserved.
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Creates a VT Collection with indicators present in a given event."""
|
|
|
|
import base64
|
|
import json
|
|
import requests
|
|
|
|
misperrors = {
|
|
'error': 'Error'
|
|
}
|
|
|
|
mispattributes = {
|
|
'input': [
|
|
'hostname',
|
|
'domain',
|
|
'ip-src',
|
|
'ip-dst',
|
|
'md5',
|
|
'sha1',
|
|
'sha256',
|
|
'url'
|
|
],
|
|
'format': 'misp_standard',
|
|
'responseType': 'application/txt',
|
|
'outputFileExtension': 'txt',
|
|
}
|
|
|
|
moduleinfo = {
|
|
'version': '1.0',
|
|
'author': 'VirusTotal',
|
|
'description': 'Creates a VT Collection from an event iocs.',
|
|
'module-type': ['export'],
|
|
'name': 'VirusTotal Collections Export',
|
|
'logo': 'virustotal.png',
|
|
'requirements': ['An access to the VirusTotal API (apikey).'],
|
|
'features': 'This export module which takes advantage of a new endpoint in VT APIv3 to create VT Collections from IOCs contained in a MISP event. With this module users will be able to create a collection just using the Download as... button.',
|
|
'references': ['https://www.virustotal.com/', 'https://blog.virustotal.com/2021/11/introducing-virustotal-collections.html'],
|
|
'input': 'A domain, hash (md5, sha1, sha256 or sha512), hostname, url or IP address attribute.',
|
|
'output': 'A VirusTotal collection in VT.',
|
|
}
|
|
|
|
moduleconfig = [
|
|
'vt_api_key',
|
|
'proxy_host',
|
|
'proxy_port',
|
|
'proxy_username',
|
|
'proxy_password'
|
|
]
|
|
|
|
|
|
class VTError(Exception):
|
|
"Exception class to map vt api response errors."
|
|
pass
|
|
|
|
|
|
def create_collection(api_key, event_data):
|
|
headers = {
|
|
'x-apikey': api_key,
|
|
'content-type': 'application/json',
|
|
'x-tool': 'MISPModuleVirusTotalCollectionExport',
|
|
}
|
|
|
|
response = requests.post('https://www.virustotal.com/api/v3/integrations/misp/collections',
|
|
headers=headers,
|
|
json=event_data)
|
|
|
|
uuid = event_data['Event']['uuid']
|
|
response_data = response.json()
|
|
|
|
if response.status_code == 200:
|
|
col_id = response_data['data']['id']
|
|
return f'{uuid}: https://www.virustotal.com/gui/collection/{col_id}/iocs'
|
|
|
|
error = response_data['error']['message']
|
|
if response.status_code == 400:
|
|
return f'{uuid}: {error}'
|
|
else:
|
|
misperrors['error'] = error
|
|
raise VTError(error)
|
|
|
|
|
|
def normalize_misp_data(data):
|
|
normalized_data = {'Event': data.pop('Event', {})}
|
|
for attr_key in data:
|
|
if isinstance(data[attr_key], list) or isinstance(data[attr_key], dict):
|
|
if attr_key == 'EventTag':
|
|
normalized_data['Event']['Tag'] = [tag['Tag'] for tag in data[attr_key]]
|
|
else:
|
|
normalized_data['Event'][attr_key] = data[attr_key]
|
|
|
|
return normalized_data
|
|
|
|
|
|
def handler(q=False):
|
|
request = json.loads(q)
|
|
|
|
if not request.get('config') or not request['config'].get('vt_api_key'):
|
|
misperrors['error'] = 'A VirusTotal api key is required for this module.'
|
|
return misperrors
|
|
|
|
config = request['config']
|
|
data = request['data']
|
|
responses = []
|
|
|
|
try:
|
|
for event_data in data:
|
|
normalized_event = normalize_misp_data(event_data)
|
|
responses.append(create_collection(config.get('vt_api_key'),
|
|
normalized_event))
|
|
|
|
output = '\n'.join(responses)
|
|
return {
|
|
"response": [],
|
|
"data": str(base64.b64encode(bytes(output, 'utf-8')), 'utf-8'),
|
|
}
|
|
except VTError:
|
|
return misperrors
|
|
|
|
|
|
|
|
def introspection():
|
|
return mispattributes
|
|
|
|
|
|
def version():
|
|
moduleinfo['config'] = moduleconfig
|
|
return moduleinfo
|