mirror of https://github.com/MISP/misp-modules
				
				
				
			
		
			
				
	
	
		
			134 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
import json
 | 
						|
import requests
 | 
						|
from . import check_input_attribute, standard_error_message
 | 
						|
from pymisp import MISPEvent, MISPObject
 | 
						|
 | 
						|
misperrors = {'error': 'Error'}
 | 
						|
mispattributes = {'input': ['cpe'], 'format': 'misp_standard'}
 | 
						|
moduleinfo = {
 | 
						|
    'version': '2',
 | 
						|
    'author': 'Christian Studer',
 | 
						|
    'description': 'An expansion module to enrich a CPE attribute with its related vulnerabilities.',
 | 
						|
    'module-type': ['expansion', 'hover']
 | 
						|
}
 | 
						|
moduleconfig = ["custom_API_URL", "limit"]
 | 
						|
cveapi_url = 'https://cvepremium.circl.lu/api/query'
 | 
						|
DEFAULT_LIMIT = 10
 | 
						|
 | 
						|
 | 
						|
class VulnerabilitiesParser():
 | 
						|
    def __init__(self, attribute):
 | 
						|
        self.attribute = attribute
 | 
						|
        self.misp_event = MISPEvent()
 | 
						|
        self.misp_event.add_attribute(**attribute)
 | 
						|
        self.vulnerability_mapping = {
 | 
						|
            'id': {
 | 
						|
                'type': 'vulnerability',
 | 
						|
                'object_relation': 'id'
 | 
						|
            },
 | 
						|
            'summary': {
 | 
						|
                'type': 'text',
 | 
						|
                'object_relation': 'summary'
 | 
						|
            },
 | 
						|
            'vulnerable_configuration': {
 | 
						|
                'type': 'cpe',
 | 
						|
                'object_relation': 'vulnerable-configuration'
 | 
						|
            },
 | 
						|
            'vulnerable_configuration_cpe_2_2': {
 | 
						|
                'type': 'cpe',
 | 
						|
                'object_relation': 'vulnerable-configuration'
 | 
						|
            },
 | 
						|
            'Modified': {
 | 
						|
                'type': 'datetime',
 | 
						|
                'object_relation': 'modified'
 | 
						|
            },
 | 
						|
            'Published': {
 | 
						|
                'type': 'datetime',
 | 
						|
                'object_relation': 'published'
 | 
						|
            },
 | 
						|
            'references': {
 | 
						|
                'type': 'link',
 | 
						|
                'object_relation': 'references'
 | 
						|
            },
 | 
						|
            'cvss': {
 | 
						|
                'type': 'float',
 | 
						|
                'object_relation': 'cvss-score'
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    def parse_vulnerabilities(self, vulnerabilities):
 | 
						|
        for vulnerability in vulnerabilities:
 | 
						|
            vulnerability_object = MISPObject('vulnerability')
 | 
						|
            for feature in ('id', 'summary', 'Modified', 'Published', 'cvss'):
 | 
						|
                if vulnerability.get(feature):
 | 
						|
                    attribute = {'value': vulnerability[feature]}
 | 
						|
                    attribute.update(self.vulnerability_mapping[feature])
 | 
						|
                    vulnerability_object.add_attribute(**attribute)
 | 
						|
            if vulnerability.get('Published'):
 | 
						|
                vulnerability_object.add_attribute(**{
 | 
						|
                    'type': 'text',
 | 
						|
                    'object_relation': 'state',
 | 
						|
                    'value': 'Published'
 | 
						|
                })
 | 
						|
            for feature in ('references', 'vulnerable_configuration', 'vulnerable_configuration_cpe_2_2'):
 | 
						|
                if vulnerability.get(feature):
 | 
						|
                    for value in vulnerability[feature]:
 | 
						|
                        if isinstance(value, dict):
 | 
						|
                            value = value['title']
 | 
						|
                        attribute = {'value': value}
 | 
						|
                        attribute.update(self.vulnerability_mapping[feature])
 | 
						|
                        vulnerability_object.add_attribute(**attribute)
 | 
						|
            vulnerability_object.add_reference(self.attribute['uuid'], 'related-to')
 | 
						|
            self.misp_event.add_object(vulnerability_object)
 | 
						|
 | 
						|
    def get_result(self):
 | 
						|
        event = json.loads(self.misp_event.to_json())
 | 
						|
        results = {key: event[key] for key in ('Attribute', 'Object')}
 | 
						|
        return {'results': results}
 | 
						|
 | 
						|
 | 
						|
def check_url(url):
 | 
						|
    return url if url.endswith('/') else f"{url}/"
 | 
						|
 | 
						|
 | 
						|
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') != 'cpe':
 | 
						|
        return {'error': 'Wrong input attribute type.'}
 | 
						|
    config = request['config']
 | 
						|
    url = check_url(config['custom_API_URL']) if config.get('custom_API_URL') else cveapi_url
 | 
						|
    limit = int(config['limit']) if config.get('limit') else DEFAULT_LIMIT
 | 
						|
    params = {
 | 
						|
        "retrieve": "cves",
 | 
						|
        "dict_filter": {
 | 
						|
            "vulnerable_configuration": attribute['value']
 | 
						|
        },
 | 
						|
        "limit": limit,
 | 
						|
        "sort": "cvss",
 | 
						|
        "sort_dir": "DESC"
 | 
						|
    }
 | 
						|
    response = requests.post(url, json=params)
 | 
						|
    if response.status_code == 200:
 | 
						|
        vulnerabilities = response.json()['data']
 | 
						|
        if not vulnerabilities:
 | 
						|
            return {'error': 'No related vulnerability for this CPE.'}
 | 
						|
    else:
 | 
						|
        return {'error': 'API not accessible.'}
 | 
						|
    parser = VulnerabilitiesParser(attribute)
 | 
						|
    parser.parse_vulnerabilities(vulnerabilities)
 | 
						|
    return parser.get_result()
 | 
						|
 | 
						|
 | 
						|
def introspection():
 | 
						|
    return mispattributes
 | 
						|
 | 
						|
 | 
						|
def version():
 | 
						|
    moduleinfo['config'] = moduleconfig
 | 
						|
    return moduleinfo
 |