2022-10-18 23:59:50 +02:00
|
|
|
import json
|
|
|
|
import requests
|
|
|
|
from . import check_input_attribute, standard_error_message
|
2022-10-24 14:53:00 +02:00
|
|
|
from pymisp import MISPAttribute, MISPEvent, MISPObject
|
2022-10-18 23:59:50 +02:00
|
|
|
|
|
|
|
misperrors = {'error': 'Error'}
|
|
|
|
mispattributes = {'input': ['vulnerability'], 'format': 'misp_standard'}
|
|
|
|
moduleinfo = {'version': '1', 'author': 'Christian Studer',
|
|
|
|
'description': 'An expansion module to query variotdbs.pl',
|
|
|
|
'module-type': ['expansion', 'hover']}
|
|
|
|
moduleconfig = ['API_key']
|
|
|
|
variotdbs_url = 'https://www.variotdbs.pl/api'
|
|
|
|
|
|
|
|
|
|
|
|
class VariotdbsParser:
|
|
|
|
def __init__(self, attribute):
|
|
|
|
misp_attribute = MISPAttribute()
|
|
|
|
misp_attribute.from_dict(**attribute)
|
|
|
|
misp_event = MISPEvent()
|
|
|
|
misp_event.add_attribute(**misp_attribute)
|
|
|
|
self.__misp_attribute = misp_attribute
|
|
|
|
self.__misp_event = misp_event
|
2022-10-24 15:01:54 +02:00
|
|
|
self.__exploit_mapping = {
|
|
|
|
'credits': 'credit',
|
2022-10-26 11:35:59 +02:00
|
|
|
'description': 'description',
|
|
|
|
'exploit': 'exploit',
|
|
|
|
'title': 'title'
|
2022-10-24 15:01:54 +02:00
|
|
|
}
|
|
|
|
self.__exploit_multiple_mapping = {
|
|
|
|
'cve': {
|
|
|
|
'feature': 'cve_id',
|
|
|
|
'relation': 'cve-id'
|
|
|
|
},
|
|
|
|
'references': {
|
|
|
|
'feature': 'url',
|
|
|
|
'relation': 'reference'
|
|
|
|
}
|
|
|
|
}
|
2022-10-18 23:59:50 +02:00
|
|
|
self.__vulnerability_data_mapping = {
|
|
|
|
'credits': 'credit',
|
|
|
|
'description': 'description',
|
|
|
|
'title': 'summary'
|
|
|
|
}
|
|
|
|
self.__vulnerability_flat_mapping = {
|
|
|
|
'cve': 'id', 'id': 'id'
|
|
|
|
}
|
|
|
|
|
2022-10-24 15:01:54 +02:00
|
|
|
@property
|
|
|
|
def exploit_mapping(self) -> dict:
|
|
|
|
return self.__exploit_mapping
|
|
|
|
|
|
|
|
@property
|
|
|
|
def exploit_multiple_mapping(self) -> dict:
|
|
|
|
return self.__exploit_multiple_mapping
|
|
|
|
|
2022-10-18 23:59:50 +02:00
|
|
|
@property
|
|
|
|
def misp_attribute(self) -> MISPAttribute:
|
2022-10-24 14:53:00 +02:00
|
|
|
return self.__misp_attribute
|
2022-10-18 23:59:50 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def misp_event(self) -> MISPEvent:
|
|
|
|
return self.__misp_event
|
|
|
|
|
|
|
|
@property
|
|
|
|
def vulnerability_data_mapping(self) -> dict:
|
|
|
|
return self.__vulnerability_data_mapping
|
|
|
|
|
|
|
|
@property
|
|
|
|
def vulnerability_flat_mapping(self) -> dict:
|
|
|
|
return self.__vulnerability_flat_mapping
|
|
|
|
|
|
|
|
def get_results(self):
|
|
|
|
event = json.loads(self.misp_event.to_json())
|
|
|
|
results = {key: event[key] for key in ('Attribute', 'Object') if event.get(key)}
|
|
|
|
return {'results': results}
|
|
|
|
|
2022-10-24 15:01:54 +02:00
|
|
|
def parse_exploit_information(self, query_results):
|
2022-10-24 16:18:22 +02:00
|
|
|
for exploit in query_results:
|
2022-10-24 15:01:54 +02:00
|
|
|
exploit_object = MISPObject('exploit')
|
|
|
|
exploit_object.add_attribute('exploitdb-id', exploit['edb_id'])
|
|
|
|
for feature, relation in self.exploit_mapping.items():
|
|
|
|
if exploit.get(feature):
|
|
|
|
exploit_object.add_attribute(
|
|
|
|
relation,
|
|
|
|
exploit[feature]['data']
|
|
|
|
)
|
|
|
|
for feature, relation in self.exploit_multiple_mapping.items():
|
|
|
|
if exploit.get(feature):
|
|
|
|
for value in exploit[feature]['data']:
|
|
|
|
exploit_object.add_attribute(
|
|
|
|
relation['relation'],
|
|
|
|
value[relation['feature']]
|
|
|
|
)
|
|
|
|
exploit_object.add_reference(self.misp_attribute.uuid, 'related-to')
|
|
|
|
self.misp_event.add_object(exploit_object)
|
|
|
|
|
2022-10-18 23:59:50 +02:00
|
|
|
def parse_vulnerability_information(self, query_results):
|
|
|
|
vulnerability_object = MISPObject('vulnerability')
|
|
|
|
for feature, relation in self.vulnerability_flat_mapping.items():
|
|
|
|
if query_results.get(feature):
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
relation,
|
|
|
|
query_results[feature]
|
|
|
|
)
|
|
|
|
for feature, relation in self.vulnerability_data_mapping.items():
|
|
|
|
if query_results.get(feature, {}).get('data'):
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
relation,
|
|
|
|
query_results[feature]['data']
|
|
|
|
)
|
|
|
|
if query_results.get('configurations', {}).get('data'):
|
2022-10-24 14:53:00 +02:00
|
|
|
for configuration in query_results['configurations']['data']:
|
|
|
|
for node in configuration['nodes']:
|
|
|
|
for cpe_match in node['cpe_match']:
|
|
|
|
if cpe_match['vulnerable']:
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'vulnerable-configuration',
|
|
|
|
cpe_match['cpe23Uri']
|
|
|
|
)
|
2022-10-18 23:59:50 +02:00
|
|
|
if query_results.get('cvss', {}).get('data'):
|
|
|
|
cvss = {}
|
|
|
|
for cvss_data in query_results['cvss']['data']:
|
|
|
|
for cvss_v3 in cvss_data['cvssV3']:
|
|
|
|
cvss[float(cvss_v3['trust'])] = cvss_v3
|
|
|
|
if cvss:
|
|
|
|
cvss = cvss[max(cvss)]
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'cvss-score',
|
|
|
|
cvss['baseScore']
|
|
|
|
)
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'cvss-string',
|
|
|
|
cvss['vectorString']
|
|
|
|
)
|
|
|
|
if query_results.get('references', {}).get('data'):
|
|
|
|
for reference in query_results['references']['data']:
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'references',
|
|
|
|
reference['url']
|
|
|
|
)
|
|
|
|
if query_results.get('sources_release_date', {}).get('data'):
|
|
|
|
for release_date in query_results['sources_release_date']['data']:
|
|
|
|
if release_date['db'] != 'NVD':
|
|
|
|
continue
|
|
|
|
if release_date['id'] == self.misp_attribute.value:
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'published',
|
|
|
|
release_date['date']
|
|
|
|
)
|
|
|
|
break
|
|
|
|
if query_results.get('sources_update_date', {}).get('data'):
|
|
|
|
for update_date in query_results['sources_update_date']['data']:
|
|
|
|
if update_date['db'] != 'NVD':
|
|
|
|
continue
|
|
|
|
if update_date['id'] == self.misp_attribute.value:
|
|
|
|
vulnerability_object.add_attribute(
|
|
|
|
'modified',
|
|
|
|
update_date['date']
|
|
|
|
)
|
|
|
|
break
|
2022-10-21 14:18:47 +02:00
|
|
|
vulnerability_object.add_reference(self.misp_attribute.uuid, 'related-to')
|
2022-10-18 23:59:50 +02:00
|
|
|
self.misp_event.add_object(vulnerability_object)
|
|
|
|
|
|
|
|
|
|
|
|
def handler(q=False):
|
|
|
|
if q is False:
|
|
|
|
return False
|
|
|
|
request = json.loads(q)
|
|
|
|
if not request.get('attribute') or not check_input_attribute(request['attribute']):
|
|
|
|
return {'error': f'{standard_error_message}, which should contain at least a type, a value and an uuid.'}
|
|
|
|
attribute = request['attribute']
|
|
|
|
if attribute.get('type') != 'vulnerability':
|
|
|
|
return {'error': 'Vulnerability id missing.'}
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
if request.get('config', {}).get('API_key'):
|
|
|
|
headers['Authorization'] = f"Token {request['config']['API_key']}"
|
2022-10-24 14:53:00 +02:00
|
|
|
empty = True
|
|
|
|
parser = VariotdbsParser(attribute)
|
2022-10-18 23:59:50 +02:00
|
|
|
r = requests.get(f"{variotdbs_url}/vuln/{attribute['value']}/", headers=headers)
|
|
|
|
if r.status_code == 200:
|
2022-10-24 14:53:00 +02:00
|
|
|
vulnerability_results = r.json()
|
|
|
|
if vulnerability_results:
|
|
|
|
parser.parse_vulnerability_information(vulnerability_results)
|
|
|
|
empty = False
|
2022-10-18 23:59:50 +02:00
|
|
|
else:
|
2022-10-24 15:43:04 +02:00
|
|
|
if r.reason != 'Not Found':
|
2022-10-24 14:53:00 +02:00
|
|
|
return {'error': 'Error while querying the variotdbs API.'}
|
2022-10-24 15:01:54 +02:00
|
|
|
r = requests.get(f"{variotdbs_url}/exploits/?cve={attribute['value']}", headers=headers)
|
|
|
|
if r.status_code == 200:
|
|
|
|
exploit_results = r.json()
|
|
|
|
if exploit_results:
|
2022-10-24 16:18:22 +02:00
|
|
|
parser.parse_exploit_information(exploit_results['results'])
|
2022-10-24 15:01:54 +02:00
|
|
|
empty = False
|
2022-10-27 09:50:24 +02:00
|
|
|
if exploit_results['next'] is not None:
|
|
|
|
while(1):
|
|
|
|
exploit_results = requests.get(exploit_results['next'], headers=headers)
|
|
|
|
if exploit_results.status_code != 200:
|
|
|
|
break
|
|
|
|
exploit_results = exploit_results.json()
|
|
|
|
parser.parse_exploit_information(exploit_results['results'])
|
|
|
|
if exploit_results['next'] is None:
|
|
|
|
break
|
2022-10-24 15:01:54 +02:00
|
|
|
else:
|
|
|
|
return {'error': 'Error while querying the variotdbs API.'}
|
2022-10-24 14:53:00 +02:00
|
|
|
if empty:
|
|
|
|
return {'error': 'Empty results'}
|
2022-10-18 23:59:50 +02:00
|
|
|
return parser.get_results()
|
|
|
|
|
|
|
|
|
|
|
|
def introspection():
|
|
|
|
return mispattributes
|
|
|
|
|
|
|
|
|
|
|
|
def version():
|
|
|
|
moduleinfo['config'] = moduleconfig
|
2022-10-24 14:53:00 +02:00
|
|
|
return moduleinfo
|