diff --git a/README.md b/README.md index a7f05c9..66bea3c 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ For more information: [Extending MISP with Python modules](https://www.circl.lu/ * [hashdd](misp_modules/modules/expansion/hashdd.py) - a hover module to check file hashes against [hashdd.com](http://www.hashdd.com) including NSLR dataset. * [IPASN](misp_modules/modules/expansion/ipasn.py) - a hover and expansion to get the BGP ASN of an IP address. * [iprep](misp_modules/modules/expansion/iprep.py) - an expansion module to get IP reputation from packetmail.net. +* [macaddress.io](misp_modules/modules/expansion/macaddress_io.py) - a hover module to retrieve vendor details and other information regarding a given MAC address or an OUI. [MAC address Vendor Lookup](https://macaddress.io) * [onyphe](misp_modules/modules/expansion/onyphe.py) - a modules to process queries on Onyphe. * [onyphe_full](misp_modules/modules/expansion/onyphe_full.py) - a modules to process full queries on Onyphe. * [OTX](misp_modules/modules/expansion/otx.py) - an expansion module for [OTX](https://otx.alienvault.com/). diff --git a/REQUIREMENTS b/REQUIREMENTS index 29af57b..6ab46cc 100644 --- a/REQUIREMENTS +++ b/REQUIREMENTS @@ -24,3 +24,5 @@ oauth2 yara sigmatools stix2-patterns +maclookup +vulners \ No newline at end of file diff --git a/misp_modules/modules/expansion/__init__.py b/misp_modules/modules/expansion/__init__.py index c6e81a7..fce9343 100644 --- a/misp_modules/modules/expansion/__init__.py +++ b/misp_modules/modules/expansion/__init__.py @@ -1,3 +1,3 @@ from . import _vmray -__all__ = ['vmray_submit', 'asn_history', 'circl_passivedns', 'circl_passivessl', 'countrycode', 'cve', 'dns', 'domaintools', 'eupi', 'farsight_passivedns', 'ipasn', 'passivetotal', 'sourcecache', 'virustotal', 'whois', 'shodan', 'reversedns', 'geoip_country', 'wiki', 'iprep', 'threatminer', 'otx', 'threatcrowd', 'vulndb', 'crowdstrike_falcon', 'yara_syntax_validator', 'hashdd', 'onyphe', 'onyphe_full', 'rbl', 'xforceexchange', 'sigma_syntax_validator', 'stix2_pattern_syntax_validator', 'sigma_queries', 'dbl_spamhaus'] +__all__ = ['vmray_submit', 'asn_history', 'circl_passivedns', 'circl_passivessl', 'countrycode', 'cve', 'dns', 'domaintools', 'eupi', 'farsight_passivedns', 'ipasn', 'passivetotal', 'sourcecache', 'virustotal', 'whois', 'shodan', 'reversedns', 'geoip_country', 'wiki', 'iprep', 'threatminer', 'otx', 'threatcrowd', 'vulndb', 'crowdstrike_falcon', 'yara_syntax_validator', 'hashdd', 'onyphe', 'onyphe_full', 'rbl', 'xforceexchange', 'sigma_syntax_validator', 'stix2_pattern_syntax_validator', 'sigma_queries', 'dbl_spamhaus', 'vulners'] diff --git a/misp_modules/modules/expansion/macaddress_io.py b/misp_modules/modules/expansion/macaddress_io.py new file mode 100644 index 0000000..14e1134 --- /dev/null +++ b/misp_modules/modules/expansion/macaddress_io.py @@ -0,0 +1,119 @@ +import json + +from maclookup import ApiClient, exceptions + +misperrors = { + 'error': 'Error' +} + +mispattributes = { + 'input': ['mac-address'], +} + +moduleinfo = { + 'version': '1.0', + 'author': 'CodeLine OY - macaddress.io', + 'description': 'MISP hover module for macaddress.io', + 'module-type': ['hover'] +} + +moduleconfig = ['api_key'] + + +def handler(q=False): + if q is False: + return False + + request = json.loads(q) + + if request.get('mac-address'): + mac_address = request['mac-address'] + else: + return False + + if request['config'].get('api_key'): + api_key = request['config'].get('api_key') + + else: + misperrors['error'] = 'Authorization required' + return misperrors + + api_client = ApiClient(api_key) + + try: + response = api_client.get(mac_address) + + except exceptions.EmptyResponseException: + misperrors['error'] = 'Empty response' + return misperrors + + except exceptions.UnparsableResponseException: + misperrors['error'] = 'Unparsable response' + return misperrors + + except exceptions.ServerErrorException: + misperrors['error'] = 'Internal server error' + return misperrors + + except exceptions.UnknownOutputFormatException: + misperrors['error'] = 'Unknown output' + return misperrors + + except exceptions.AuthorizationRequiredException: + misperrors['error'] = 'Authorization required' + return misperrors + + except exceptions.AccessDeniedException: + misperrors['error'] = 'Access denied' + return misperrors + + except exceptions.InvalidMacOrOuiException: + misperrors['error'] = 'Invalid MAC or OUI' + return misperrors + + except exceptions.NotEnoughCreditsException: + misperrors['error'] = 'Not enough credits' + return misperrors + + except Exception: + misperrors['error'] = 'Unknown error' + return misperrors + + results = { + 'results': [ + {'types': ['text'], 'values': + { + 'Valid MAC address': "True" if response.mac_address_details.is_valid else "False", + + 'Transmission type': response.mac_address_details.transmission_type, + 'Administration type': response.mac_address_details.administration_type, + + 'OUI': response.vendor_details.oui, + 'Vendor details are hidden': "True" if response.vendor_details.is_private else "False", + + 'Company name': response.vendor_details.company_name, + 'Company\'s address': response.vendor_details.company_address, + 'County code': response.vendor_details.country_code, + + 'Block found': "True" if response.block_details.block_found else "False", + 'The left border of the range': response.block_details.border_left, + 'The right border of the range': response.block_details.border_right, + 'The total number of MAC addresses in this range': response.block_details.block_size, + 'Assignment block size': response.block_details.assignment_block_size, + 'Date when the range was allocated': response.block_details.date_created, + 'Date when the range was last updated': response.block_details.date_updated + } + } + ] + } + + return results + + +def introspection(): + return mispattributes + + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo diff --git a/misp_modules/modules/expansion/vulners.py b/misp_modules/modules/expansion/vulners.py new file mode 100644 index 0000000..49cb9aa --- /dev/null +++ b/misp_modules/modules/expansion/vulners.py @@ -0,0 +1,65 @@ +import json +import requests +import vulners + +misperrors = {'error': 'Error'} +mispattributes = {'input': ['vulnerability'], 'output': ['text']} +moduleinfo = {'version': '0.1', 'author': 'Igor Ivanov', 'description': 'An expansion hover module to expand information about CVE id using Vulners API.', 'module-type': ['hover']} + +# Get API key from https://vulners.com/userinfo +moduleconfig = ["apikey"] + + +def handler(q=False): + if q is False: + return False + request = json.loads(q) + if not request.get('vulnerability'): + misperrors['error'] = 'Vulnerability id missing' + return misperrors + + ai_summary = '' + exploit_summary = '' + vuln_summary = '' + + key = request['config'].get('apikey') + vulners_api = vulners.Vulners(api_key=key) + vulnerability = request.get('vulnerability') + vulners_document = vulners_api.document(vulnerability) + + # Get AI scoring from the document if it's already calculated + # There is no need to call AI Scoring method + if 'score' in vulners_document.get('enchantments', {}): + vulners_ai_score = vulners_document['enchantments']['score']['value'] + else: + vulners_ai_score = None + + vulners_exploits = vulners_api.searchExploit(vulnerability) + + if vulners_document: + vuln_summary += vulners_document.get('description') + else: + vuln_summary += 'Non existing CVE' + + if vulners_ai_score: + ai_summary += 'Vulners AI Score is ' + str(vulners_ai_score[0]) + " " + + if vulners_exploits: + exploit_summary += " || " + str(len(vulners_exploits[0])) + " Public exploits available:\n " + for exploit in vulners_exploits[0]: + exploit_summary += exploit['title'] + " " + exploit['href'] + "\n " + exploit_summary += "|| Vulnerability Description: " + vuln_summary + + summary = ai_summary + exploit_summary + vuln_summary + + r = {'results': [{'types': mispattributes['output'], 'values': summary}]} + return r + + +def introspection(): + return mispattributes + + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo