From 7c05a8acef6e7b5d72d90521e7e1df0308f97172 Mon Sep 17 00:00:00 2001 From: Koen Van Impe Date: Wed, 16 Nov 2016 22:13:58 +0100 Subject: [PATCH] Submit malware samples _submit now includes malware samples (zipped content from misp) _import checks when no vti_results are returned + bugfix --- .../modules/expansion/vmray_submit.py | 35 ++++++++++++++----- .../modules/import_mod/vmray_import.py | 35 +++++++++++++------ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/misp_modules/modules/expansion/vmray_submit.py b/misp_modules/modules/expansion/vmray_submit.py index 9ab4e059..4359ee26 100644 --- a/misp_modules/modules/expansion/vmray_submit.py +++ b/misp_modules/modules/expansion/vmray_submit.py @@ -14,17 +14,20 @@ TODO: import json import re import base64 - +import io import sys import os +import zipfile + + base_dir = os.path.dirname(__file__) or '.' sys.path.append(base_dir) from vmray_rest_api import VMRayRESTAPI, VMRayRESTAPIError -import io + misperrors = {'error': 'Error'} -mispattributes = {'input': ['attachment'], 'output': ['text', 'sha1', 'sha256', 'md5', 'link']} -moduleinfo = {'version': '0.1', 'author': 'Koen Van Impe', +mispattributes = {'input': ['attachment', 'malware-sample'], 'output': ['text', 'sha1', 'sha256', 'md5', 'link']} +moduleinfo = {'version': '0.2', 'author': 'Koen Van Impe', 'description': 'Submit a sample to VMRay', 'module-type': ['expansion']} moduleconfig = ['apikey', 'url', 'shareable', 'do_not_reanalyze', 'do_not_include_vmrayjobids'] @@ -39,11 +42,25 @@ def handler(q=False): if q is False: return False request = json.loads(q) - try: data = request.get("data") - attachment = request.get("attachment") - data = base64.b64decode(data) + if 'malware-sample' in request: + # malicious samples are encrypted with zip (password infected) and then base64 encoded + 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: + # All attachments get base64 encoded + sample_filename = request.get("attachment") + data = base64.b64decode(data) + + else: + misperrors['error'] = "No malware sample or attachment supplied" + return misperrors except: misperrors['error'] = "Unable to process submited sample data" return misperrors @@ -78,10 +95,10 @@ def handler(q=False): do_not_include_vmrayjobids = False include_vmrayjobids = not do_not_include_vmrayjobids - if data and attachment: + if data and sample_filename: args = {} args["shareable"] = shareable - args["sample_file"] = {'data': io.BytesIO( data ) , 'filename': attachment } + args["sample_file"] = {'data': io.BytesIO( data ) , 'filename': sample_filename } args["reanalyze"] = reanalyze try: diff --git a/misp_modules/modules/import_mod/vmray_import.py b/misp_modules/modules/import_mod/vmray_import.py index 397bd397..df79da79 100644 --- a/misp_modules/modules/import_mod/vmray_import.py +++ b/misp_modules/modules/import_mod/vmray_import.py @@ -90,6 +90,7 @@ def handler(q=False): # Get all information on the sample, returns a set of finished analyze jobs data = vmrayGetInfoAnalysis(api, sample_id) if data["data"]: + vti_patterns_found = False for analysis in data["data"]: analysis_id = analysis["analysis_id"] @@ -99,17 +100,25 @@ def handler(q=False): if analysis_data: p = vmrayVtiPatterns(analysis_data["vti_patterns"]) - if p: - if include_analysisid: - url1 = "https://cloud.vmray.com/user/analysis/view?from_sample_id=%u" % sample_id - url2 = "&id=%u" % analysis_id - url3 = "&sub=%2Freport%2Foverview.html" - p["results"].append({ "values": url1 + url2 + url3, "types": "link" }) + if p and len(p["results"]) > 0: + vti_patterns_found = True vmray_results = {'results': vmray_results["results"] + p["results"] } + if include_analysisid: + a_id = {'results': []} + url1 = "https://cloud.vmray.com/user/analysis/view?from_sample_id=%u" % sample_id + url2 = "&id=%u" % analysis_id + url3 = "&sub=%2Freport%2Foverview.html" + a_id["results"].append({ "values": url1 + url2 + url3, "types": "link" }) + vmray_results = {'results': vmray_results["results"] + a_id["results"] } + # Clean up (remove doubles) - vmray_results = vmrayCleanup(vmray_results) - return vmray_results + if vti_patterns_found: + vmray_results = vmrayCleanup(vmray_results) + return vmray_results + else: + misperrors['error'] = "No vti_results returned or jobs not finished" + return misperrors else: misperrors['error'] = "Unable to fetch sample id %u" % (sample_id) return misperrors @@ -179,6 +188,8 @@ def vmrayVtiPatterns(vti_patterns): content = vmrayGeneric(pattern) elif only_network_info == False and pattern["category"] == "_process" and pattern["operation"] == "_install_ipc_endpoint": content = vmrayGeneric(pattern, "mutex", 1) + elif only_network_info == False and pattern["category"] == "_process" and pattern["operation"] == "_crashed_process": + content = vmrayGeneric(pattern) elif only_network_info == False and pattern["category"] == "_anti_analysis" and pattern["operation"] == "_delay_execution": content = vmrayGeneric(pattern) @@ -247,9 +258,11 @@ def vmrayGeneric(el, attr = "", attrpos = 1): if content: if attr: content_split = content.split("\"") - content_split[attrpos] = vmraySanitizeInput(content_split[attrpos]) - r["values"].append(content_split[attrpos]) - r["types"] = [attr] + # Attributes are between open " and close "; so use > + if len(content_split) > attrpos: + content_split[attrpos] = vmraySanitizeInput(content_split[attrpos]) + r["values"].append(content_split[attrpos]) + r["types"] = [attr] # Adding the value also as text to get the extra description, # but this is pretty useless for "url"