From db7dbd6ed550eb0f88934c3644cf7d8bdd28bc51 Mon Sep 17 00:00:00 2001 From: Codelinefi-admin Date: Thu, 13 Sep 2018 17:02:49 +0300 Subject: [PATCH 1/6] macaddress.io hover module added --- README.md | 1 + REQUIREMENTS | 1 + .../modules/expansion/macaddress_io.py | 119 ++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 misp_modules/modules/expansion/macaddress_io.py diff --git a/README.md b/README.md index ad4b098..af32bc0 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..c004afe 100644 --- a/REQUIREMENTS +++ b/REQUIREMENTS @@ -24,3 +24,4 @@ oauth2 yara sigmatools stix2-patterns +maclookup 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 From 5dc05bfafcd6d1a6028472791d14d87f5eaf8b6a Mon Sep 17 00:00:00 2001 From: Igor Ivanov Date: Tue, 18 Sep 2018 11:18:55 +0200 Subject: [PATCH 2/6] initial Vulners module PoC --- REQUIREMENTS | 1 + misp_modules/modules/expansion/vulners.py | 39 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 misp_modules/modules/expansion/vulners.py diff --git a/REQUIREMENTS b/REQUIREMENTS index c004afe..6ab46cc 100644 --- a/REQUIREMENTS +++ b/REQUIREMENTS @@ -25,3 +25,4 @@ yara sigmatools stix2-patterns maclookup +vulners \ No newline at end of file diff --git a/misp_modules/modules/expansion/vulners.py b/misp_modules/modules/expansion/vulners.py new file mode 100644 index 0000000..70b5d12 --- /dev/null +++ b/misp_modules/modules/expansion/vulners.py @@ -0,0 +1,39 @@ +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 + + key = q["config"]["apikey"] + vulners_api = vulners.Vulners(api_key=key) + vulners_document = vulners_api.document("CVE-2017-14174") + if vulners_document: + summary = vulners_document.get('description') + else: + summary = 'Non existing CVE' + + r = {'results': [{'types': mispattributes['output'], 'values': summary}]} + return r + + +def introspection(): + return mispattributes + + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo From 8d7d37746450d653e23398ab77a802789e225324 Mon Sep 17 00:00:00 2001 From: Igor Ivanov Date: Tue, 18 Sep 2018 12:11:47 +0200 Subject: [PATCH 3/6] added exploit information --- misp_modules/modules/expansion/__init__.py | 2 +- misp_modules/modules/expansion/vulners.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) 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/vulners.py b/misp_modules/modules/expansion/vulners.py index 70b5d12..7d1b54b 100644 --- a/misp_modules/modules/expansion/vulners.py +++ b/misp_modules/modules/expansion/vulners.py @@ -18,14 +18,21 @@ def handler(q=False): misperrors['error'] = 'Vulnerability id missing' return misperrors - key = q["config"]["apikey"] + key = request['config'].get('apikey') vulners_api = vulners.Vulners(api_key=key) - vulners_document = vulners_api.document("CVE-2017-14174") + vulners_document = vulners_api.document(request.get('vulnerability')) + vulners_exploits = vulners_api.searchExploit(request.get('vulnerability')) if vulners_document: summary = vulners_document.get('description') else: summary = 'Non existing CVE' + if vulners_exploits: + for exploit in vulners_exploits[0]: + exploit_summary += exploit['title'] + " " + exploit['href'] + "\n" + summary += vulners_exploits[1] + " Public exploits available:\n " + exploit_summary + + r = {'results': [{'types': mispattributes['output'], 'values': summary}]} return r From 3e9589d0f44d8ef500e91b05e9568ee7c71cac44 Mon Sep 17 00:00:00 2001 From: Igor Ivanov Date: Tue, 18 Sep 2018 14:38:49 +0200 Subject: [PATCH 4/6] code cleanup and formatting --- misp_modules/modules/expansion/vulners.py | 28 ++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/misp_modules/modules/expansion/vulners.py b/misp_modules/modules/expansion/vulners.py index 7d1b54b..c7d48de 100644 --- a/misp_modules/modules/expansion/vulners.py +++ b/misp_modules/modules/expansion/vulners.py @@ -18,21 +18,33 @@ def handler(q=False): 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) - vulners_document = vulners_api.document(request.get('vulnerability')) - vulners_exploits = vulners_api.searchExploit(request.get('vulnerability')) + vulnerability = request.get('vulnerability') + vulners_document = vulners_api.document(vulnerability) + vulners_exploits = vulners_api.searchExploit(vulnerability) + vulners_ai_score = vulners_api.aiScore(vulnerability) + if vulners_document: - summary = vulners_document.get('description') + vuln_summary += vulners_document.get('description') else: - summary = 'Non existing CVE' + 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" - summary += vulners_exploits[1] + " Public exploits available:\n " + exploit_summary - - + 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 From 007723109d559b46fdcfc395a191e5888651a3a3 Mon Sep 17 00:00:00 2001 From: Igor Ivanov Date: Tue, 18 Sep 2018 15:56:15 +0200 Subject: [PATCH 5/6] HotFix: Vulners AI score --- misp_modules/modules/expansion/vulners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misp_modules/modules/expansion/vulners.py b/misp_modules/modules/expansion/vulners.py index c7d48de..2be0a9f 100644 --- a/misp_modules/modules/expansion/vulners.py +++ b/misp_modules/modules/expansion/vulners.py @@ -27,7 +27,7 @@ def handler(q=False): vulnerability = request.get('vulnerability') vulners_document = vulners_api.document(vulnerability) vulners_exploits = vulners_api.searchExploit(vulnerability) - vulners_ai_score = vulners_api.aiScore(vulnerability) + vulners_ai_score = vulners_api.aiScore(vulners_document.get('description')) if vulners_document: vuln_summary += vulners_document.get('description') From f1325f431629f222451bc1ac521f9339853b263d Mon Sep 17 00:00:00 2001 From: isox Date: Tue, 18 Sep 2018 18:36:12 +0300 Subject: [PATCH 6/6] Fixed getting of the Vulners AI score. --- misp_modules/modules/expansion/vulners.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/misp_modules/modules/expansion/vulners.py b/misp_modules/modules/expansion/vulners.py index c7d48de..49cb9aa 100644 --- a/misp_modules/modules/expansion/vulners.py +++ b/misp_modules/modules/expansion/vulners.py @@ -26,8 +26,15 @@ def handler(q=False): 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) - vulners_ai_score = vulners_api.aiScore(vulnerability) if vulners_document: vuln_summary += vulners_document.get('description')