From e3472136f055214abf2ee49878fb3ee31160851d Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:49:35 -0700 Subject: [PATCH 1/8] VirusTotal Upload Module to push malware samples to VirusTotal --- .../modules/expansion/virustotal_upload.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 misp_modules/modules/expansion/virustotal_upload.py diff --git a/misp_modules/modules/expansion/virustotal_upload.py b/misp_modules/modules/expansion/virustotal_upload.py new file mode 100644 index 00000000..3d0a2874 --- /dev/null +++ b/misp_modules/modules/expansion/virustotal_upload.py @@ -0,0 +1,79 @@ +import json +import sys +import base64 +import io +import zipfile +import requests +import hashlib + +misperrors = {'error': 'Error'} +mispattributes = {'input': ['attachment', 'malware-sample'], 'output': ['link']} +moduleinfo = { + 'version': '1', + 'author': 'Karen Yousefi', + 'description': 'Module to push malware samples to VirusTotal', + 'module-type': ['expansion'], + 'name': 'VirusTotal Upload', + 'requirements': ['requests library'], +} + +moduleconfig = ['virustotal_apikey'] + +def handler(q=False): + if q is False: + return False + request = json.loads(q) + + try: + data = request.get("data") + if 'malware-sample' in request: + sample_filename = request.get("malware-sample").split("|", 1)[0] + data = base64.b64decode(data) + fl = io.BytesIO(data) + zf = zipfile.ZipFile(fl) + sample_hashname = zf.namelist()[0] + data = zf.read(sample_hashname, b"infected") + zf.close() + elif 'attachment' in request: + sample_filename = request.get("attachment") + data = base64.b64decode(data) + else: + misperrors['error'] = "No malware sample or attachment supplied" + return misperrors + except Exception: + misperrors['error'] = "Unable to process submitted sample data" + return misperrors + + if request["config"].get("virustotal_apikey") is None: + misperrors["error"] = "Missing VirusTotal API key" + return misperrors + + virustotal_apikey = request["config"].get("virustotal_apikey") + + try: + url = "https://www.virustotal.com/api/v3/files" + headers = { + "accept": "application/json", + "x-apikey": virustotal_apikey, + } + files = {"file": (sample_filename, data)} + response = requests.post(url, headers=headers, files=files) + response.raise_for_status() + + # Calculate SHA256 of the file + sha256 = hashlib.sha256(data).hexdigest() + + virustotal_link = f"https://www.virustotal.com/gui/file/{sha256}" + except Exception as e: + misperrors['error'] = f"Unable to send sample to VirusTotal: {str(e)}" + return misperrors + + r = {'results': [{'types': 'link', 'values': virustotal_link, 'comment': 'Link to VirusTotal analysis'}]} + return r + +def introspection(): + return mispattributes + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo From 1d5d0336c6b24a74582501567a18a381993d184a Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:50:33 -0700 Subject: [PATCH 2/8] MalShare Upload Module to push malware samples to MalShare --- .../modules/expansion/malshare_upload.py | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 misp_modules/modules/expansion/malshare_upload.py diff --git a/misp_modules/modules/expansion/malshare_upload.py b/misp_modules/modules/expansion/malshare_upload.py new file mode 100644 index 00000000..8f5fa16f --- /dev/null +++ b/misp_modules/modules/expansion/malshare_upload.py @@ -0,0 +1,94 @@ +import json +import sys +import base64 +import io +import zipfile +import requests +import hashlib +import re + +misperrors = {'error': 'Error'} +mispattributes = {'input': ['attachment', 'malware-sample'], 'output': ['link']} +moduleinfo = { + 'version': '1', + 'author': 'Karen Yousefi', + 'description': 'Module to push malware samples to MalShare', + 'module-type': ['expansion'], + 'name': 'MalShare Upload', + 'requirements': ['requests library'], +} + +moduleconfig = ['malshare_apikey'] + +def handler(q=False): + if q is False: + return False + request = json.loads(q) + + try: + data = request.get("data") + if 'malware-sample' in request: + sample_filename = request.get("malware-sample").split("|", 1)[0] + data = base64.b64decode(data) + fl = io.BytesIO(data) + zf = zipfile.ZipFile(fl) + sample_hashname = zf.namelist()[0] + data = zf.read(sample_hashname, b"infected") + zf.close() + elif 'attachment' in request: + sample_filename = request.get("attachment") + data = base64.b64decode(data) + else: + misperrors['error'] = "No malware sample or attachment supplied" + return misperrors + except Exception: + misperrors['error'] = "Unable to process submitted sample data" + return misperrors + + if request["config"].get("malshare_apikey") is None: + misperrors["error"] = "Missing MalShare API key" + return misperrors + + malshare_apikey = request["config"].get("malshare_apikey") + + try: + url = "https://malshare.com/api.php" + params = { + 'api_key': malshare_apikey, + 'action': 'upload' + } + files = {"upload": (sample_filename, data)} + response = requests.post(url, params=params, files=files) + response.raise_for_status() + + response_text = response.text.strip() + + # Calculate SHA256 of the file + sha256 = hashlib.sha256(data).hexdigest() + + if response_text.startswith("Success"): + # If upload was successful or file already exists + malshare_link = f"https://malshare.com/sample.php?action=detail&hash={sha256}" + elif "sample already exists" in response_text: + # If file already exists, extract SHA256 from response + match = re.search(r'([a-fA-F0-9]{64})', response_text) + if match: + sha256 = match.group(1) + malshare_link = f"https://malshare.com/sample.php?action=detail&hash={sha256}" + else: + # If there's any other error + raise Exception(f"Upload failed: {response_text}") + + except Exception as e: + misperrors['error'] = f"Unable to send sample to MalShare: {str(e)}" + return misperrors + + r = {'results': [{'types': 'link', 'values': malshare_link, 'comment': 'Link to MalShare analysis'}]} + return r + +def introspection(): + return mispattributes + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo From f7a45457277ef1690794a873abca746a69b5a88f Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:52:01 -0700 Subject: [PATCH 3/8] Add Triage Submit Module to submit samples to tria.ge --- .../modules/expansion/triage_submit.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 misp_modules/modules/expansion/triage_submit.py diff --git a/misp_modules/modules/expansion/triage_submit.py b/misp_modules/modules/expansion/triage_submit.py new file mode 100644 index 00000000..404fa442 --- /dev/null +++ b/misp_modules/modules/expansion/triage_submit.py @@ -0,0 +1,99 @@ +import json +import requests +import base64 +import io +import zipfile + +misperrors = {'error': 'Error'} +mispattributes = {'input': ['attachment', 'malware-sample', 'url'], 'output': ['link']} +moduleinfo = { + 'version': '1', + 'author': 'Karen Yousefi', + 'description': 'Module to submit samples to tria.ge', + 'module-type': ['expansion', 'hover'], + 'name': 'Triage Submit', +} + +moduleconfig = ['apikey', 'url_mode'] + +def handler(q=False): + if q is False: + return False + + request = json.loads(q) + + if request.get('config', {}).get('apikey') is None: + misperrors['error'] = 'tria.ge API key is missing' + return misperrors + + api_key = request['config']['apikey'] + url_mode = request['config'].get('url_mode', 'submit') # 'submit' or 'fetch' + base_url = 'https://tria.ge/api/v0/samples' + headers = { + 'Authorization': f'Bearer {api_key}' + } + + if 'attachment' in request: + data = request['data'] + filename = request['attachment'] + return submit_file(headers, base_url, data, filename) + elif 'malware-sample' in request: + data = request['data'] + filename = request['malware-sample'].split('|')[0] + return submit_file(headers, base_url, data, filename, is_malware_sample=True) + elif 'url' in request: + url = request['url'] + return submit_url(headers, base_url, url, url_mode) + else: + misperrors['error'] = 'Unsupported input type' + return misperrors + +def submit_file(headers, base_url, data, filename, is_malware_sample=False): + try: + if is_malware_sample: + file_data = base64.b64decode(data) + zip_file = zipfile.ZipFile(io.BytesIO(file_data)) + file_data = zip_file.read(zip_file.namelist()[0], pwd=b'infected') + else: + file_data = base64.b64decode(data) + + files = {'file': (filename, file_data)} + response = requests.post(base_url, headers=headers, files=files) + response.raise_for_status() + result = response.json() + + sample_id = result['id'] + sample_url = f'https://tria.ge/{sample_id}' + + return {'results': [{'types': 'link', 'values': sample_url, 'comment': 'Link to tria.ge analysis'}]} + + except Exception as e: + misperrors['error'] = f'Error submitting to tria.ge: {str(e)}' + return misperrors + +def submit_url(headers, base_url, url, mode): + try: + if mode == 'fetch': + data = {'kind': 'fetch', 'url': url} + else: # submit + data = {'kind': 'url', 'url': url} + + response = requests.post(base_url, headers=headers, json=data) + response.raise_for_status() + result = response.json() + + sample_id = result['id'] + sample_url = f'https://tria.ge/{sample_id}' + + return {'results': [{'types': 'link', 'values': sample_url, 'comment': f'Link to tria.ge analysis ({mode} mode)'}]} + + except Exception as e: + misperrors['error'] = f'Error submitting to tria.ge: {str(e)}' + return misperrors + +def introspection(): + return mispattributes + +def version(): + moduleinfo['config'] = moduleconfig + return moduleinfo \ No newline at end of file From 9106a44e8f34746a617ad3ae2d5702e99df9c425 Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:54:14 -0700 Subject: [PATCH 4/8] Update README.md Add: virustotal upload malshare upload triage submit --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9122efb4..1befb254 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ For further Information see the [license file](https://misp.github.io/misp-modul * [Lastline Submit](https://misp.github.io/misp-modules/expansion/#lastline-submit) - Deprecation notice: this module will be deprecated by December 2021, please use vmware_nsx module. Module to submit a file or URL to Lastline. * [Macaddress.io Lookup](https://misp.github.io/misp-modules/expansion/#macaddress.io-lookup) - MISP hover module for macaddress.io * [Macvendors Lookup](https://misp.github.io/misp-modules/expansion/#macvendors-lookup) - Module to access Macvendors API. +* [Malshare Upload](https://misp.github.io/misp-modules/expansion/#malshare-upload) - Module to push malware samples to malshare.com . * [Malware Bazaar Lookup](https://misp.github.io/misp-modules/expansion/#malware-bazaar-lookup) - Query Malware Bazaar to get additional information about the input hash. * [McAfee MVISION Insights Lookup](https://misp.github.io/misp-modules/expansion/#mcafee-mvision-insights-lookup) - Lookup McAfee MVISION Insights Details * [GeoIP Enrichment](https://misp.github.io/misp-modules/expansion/#geoip-enrichment) - A hover and expansion module to enrich an ip with geolocation and ASN information from an mmdb server instance, such as CIRCL's ip.circl.lu. @@ -124,12 +125,14 @@ For further Information see the [license file](https://misp.github.io/misp-modul * [ThreatCrowd Lookup](https://misp.github.io/misp-modules/expansion/#threatcrowd-lookup) - Module to get information from ThreatCrowd. * [ThreadFox Lookup](https://misp.github.io/misp-modules/expansion/#threadfox-lookup) - Module to search for an IOC on ThreatFox by abuse.ch. * [ThreatMiner Lookup](https://misp.github.io/misp-modules/expansion/#threatminer-lookup) - Module to get information from ThreatMiner. +* [Triage Submit](https://misp.github.io/misp-modules/expansion/#triage-submit) - Module to submit samples to tria.ge . * [TruSTAR Enrich](https://misp.github.io/misp-modules/expansion/#trustar-enrich) - Module to get enrich indicators with TruSTAR. * [URLhaus Lookup](https://misp.github.io/misp-modules/expansion/#urlhaus-lookup) - Query of the URLhaus API to get additional information about the input attribute. * [URLScan Lookup](https://misp.github.io/misp-modules/expansion/#urlscan-lookup) - An expansion module to query urlscan.io. * [VARIoT db Lookup](https://misp.github.io/misp-modules/expansion/#variot-db-lookup) - An expansion module to query the VARIoT db API for more information about a vulnerability. * [VirusTotal v3 Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-v3-lookup) - Enrich observables with the VirusTotal v3 API -* [VirusTotal Public API Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-public-api-lookup) - Enrich observables with the VirusTotal v3 public API +* [VirusTotal Public API Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-public-api-lookup) - Module to push malware samples to VirusTotal +* [VirusTotal Upload](https://misp.github.io/misp-modules/expansion/#virustotal-upload) - Module to push malware samples to VirusTotal v3 public API * [VMRay Submit](https://misp.github.io/misp-modules/expansion/#vmray-submit) - Module to submit a sample to VMRay. * [VMware NSX Defender Enrich](https://misp.github.io/misp-modules/expansion/#vmware-nsx-defender-enrich) - Module to enrich a file or URL with VMware NSX Defender. * [VulnDB Lookup](https://misp.github.io/misp-modules/expansion/#vulndb-lookup) - Module to query VulnDB (RiskBasedSecurity.com). @@ -183,5 +186,3 @@ For further Information see the [license file](https://misp.github.io/misp-modul * [Mattermost](https://misp.github.io/misp-modules/action_mod/#mattermost) - Simplistic module to send message to a Mattermost channel. * [Slack](https://misp.github.io/misp-modules/action_mod/#slack) - Simplistic module to send messages to a Slack channel. * [Test action](https://misp.github.io/misp-modules/action_mod/#test-action) - This module is merely a test, always returning true. Triggers on event publishing. - - From dce7fc1c18789452ae7b290a3e1e7cc3dfdfc2a5 Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 18:55:58 -0700 Subject: [PATCH 5/8] Update expansion.md Add: virustotal upload malshare upload triage submit --- documentation/mkdocs/expansion.md | 88 +++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/documentation/mkdocs/expansion.md b/documentation/mkdocs/expansion.md index 153fc1be..d92d914c 100644 --- a/documentation/mkdocs/expansion.md +++ b/documentation/mkdocs/expansion.md @@ -1561,6 +1561,29 @@ Module to access Macvendors API. ----- +#### [Malshare Upload](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/malshare_upload.py) + +Module to push malware samples to MalShare.com +[[source code](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/malshare_upload.py)] + +- **features**: +>The module requires a MalShare API key to upload files, and returns the link of the MalShare analysis. + +- **config**: +>api_key + +- **input**: +>Attachment or malware sample + +- **output**: +>Link attribute that points to the sample at the MalShare analysis instance. + +- **references**: +> - https://malshare.com/ +> - https://malshare.com/doc.php + +----- + #### [Malware Bazaar Lookup](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/malwarebazaar.py) Query Malware Bazaar to get additional information about the input hash. @@ -2454,6 +2477,42 @@ Module to get information from ThreatMiner. - **references**: >https://www.threatminer.org/ + + +----- + +#### [Triage Submit](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/triage_submit.py) + +Module to submit samples to tria.ge +[[source code](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/triage_submit.py)] + +- **features**: +> Upload files, and returns the link of the uploaded analysis. +> +>The module can submit URLs to retrieve and analyze them directly in the browser or fetch and execute files in the sandbox. + + +- **config**: +>apikey +> +>url_mode ( 'submit' or 'fetch' ) + +- **input**: +>A MISP attribute included in the following list: +>- Attachment +>- malware-sample +>- url + +- **output**: +>Link attribute that points to the sample at the Triage analysis instance. + +- **references**: +> - https://tria.ge/ +> - https://tria.ge/docs/cloud-api/submit/ + +- **requirements**: +>An access to the Triage API (apikey) + ----- #### [TruSTAR Enrich](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/trustar_enrich.py) @@ -2653,6 +2712,35 @@ Enrich observables with the VirusTotal v3 public API - **requirements**: >An access to the VirusTotal API (apikey) + +----- + +#### [VirusTotal Upload](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/virustotal_upload.py) + + + +Module to push malware samples to VirusTotal v3 public API +[[source code](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/virustotal_upload.py)] + +- **features**: +>The module requires a VirusTotal API key to Upload files, and returns the link of the uploaded analysis. + +- **config**: +> - apikey + +- **input**: +>Attachment or malware sample + +- **output**: +>Link attribute that points to the sample at the VirusTotal analysis instance. + +- **references**: +> - https://www.virustotal.com +> - https://docs.virustotal.com/reference/overview + +- **requirements**: +>An access to the VirusTotal API (apikey) + ----- #### [VMRay Submit](https://github.com/MISP/misp-modules/tree/main/misp_modules/modules/expansion/vmray_submit.py) From e16bdfe1ed08675cf47d6b67f9cef5b375576388 Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Fri, 16 Aug 2024 19:25:20 -0700 Subject: [PATCH 6/8] Update README.md fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1befb254..18fed18c 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ For further Information see the [license file](https://misp.github.io/misp-modul * [URLScan Lookup](https://misp.github.io/misp-modules/expansion/#urlscan-lookup) - An expansion module to query urlscan.io. * [VARIoT db Lookup](https://misp.github.io/misp-modules/expansion/#variot-db-lookup) - An expansion module to query the VARIoT db API for more information about a vulnerability. * [VirusTotal v3 Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-v3-lookup) - Enrich observables with the VirusTotal v3 API -* [VirusTotal Public API Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-public-api-lookup) - Module to push malware samples to VirusTotal +* [VirusTotal Public API Lookup](https://misp.github.io/misp-modules/expansion/#virustotal-public-api-lookup) - Enrich observables with the VirusTotal v3 public API * [VirusTotal Upload](https://misp.github.io/misp-modules/expansion/#virustotal-upload) - Module to push malware samples to VirusTotal v3 public API * [VMRay Submit](https://misp.github.io/misp-modules/expansion/#vmray-submit) - Module to submit a sample to VMRay. * [VMware NSX Defender Enrich](https://misp.github.io/misp-modules/expansion/#vmware-nsx-defender-enrich) - Module to enrich a file or URL with VMware NSX Defender. From 2247e90e427b717c7fb05eb337c6496fd4ecc230 Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Tue, 20 Aug 2024 03:20:27 +0330 Subject: [PATCH 7/8] Update __init__.py fix bug pr #682 --- misp_modules/modules/expansion/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misp_modules/modules/expansion/__init__.py b/misp_modules/modules/expansion/__init__.py index be74fdd6..d2c82dbd 100644 --- a/misp_modules/modules/expansion/__init__.py +++ b/misp_modules/modules/expansion/__init__.py @@ -23,7 +23,7 @@ __all__ = ['cuckoo_submit', 'vmray_submit', 'bgpranking', 'circl_passivedns', 'c 'extract_url_components', 'ipinfo', 'whoisfreaks', 'ip2locationio', 'stairwell', 'google_threat_intelligence', 'vulnerability_lookup', 'vysion', 'mcafee_insights_enrich', 'threatfox', 'yeti', 'abuseipdb', 'vmware_nsx', 'sigmf_expand', 'google_safe_browsing', - 'google_search'] + 'google_search', 'triage_submit', 'virustotal_upload', 'malshare_upload' ] minimum_required_fields = ('type', 'uuid', 'value') From dea91594aee952eb913d23d2bac596a9f66fa540 Mon Sep 17 00:00:00 2001 From: Karen Yousefi <38912491+karenyousefi@users.noreply.github.com> Date: Mon, 19 Aug 2024 23:25:44 -0700 Subject: [PATCH 8/8] Update __init__.py --- misp_modules/modules/expansion/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misp_modules/modules/expansion/__init__.py b/misp_modules/modules/expansion/__init__.py index d2c82dbd..fe61023d 100644 --- a/misp_modules/modules/expansion/__init__.py +++ b/misp_modules/modules/expansion/__init__.py @@ -23,7 +23,7 @@ __all__ = ['cuckoo_submit', 'vmray_submit', 'bgpranking', 'circl_passivedns', 'c 'extract_url_components', 'ipinfo', 'whoisfreaks', 'ip2locationio', 'stairwell', 'google_threat_intelligence', 'vulnerability_lookup', 'vysion', 'mcafee_insights_enrich', 'threatfox', 'yeti', 'abuseipdb', 'vmware_nsx', 'sigmf_expand', 'google_safe_browsing', - 'google_search', 'triage_submit', 'virustotal_upload', 'malshare_upload' ] + 'google_search', 'whois', 'triage_submit', 'virustotal_upload', 'malshare_upload' ] minimum_required_fields = ('type', 'uuid', 'value')