mirror of https://github.com/MISP/misp-modules
				
				
				
			
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
| #!/usr/bin/env python3
 | |
| 
 | |
| '''
 | |
| Submit sample to  VMRay.
 | |
| 
 | |
| Submit a sample to VMRay
 | |
| 
 | |
| TODO:
 | |
|  # Deal with archive submissions
 | |
| 
 | |
| '''
 | |
| 
 | |
| import json
 | |
| import base64
 | |
| 
 | |
| import io
 | |
| import zipfile
 | |
| 
 | |
| from ._vmray.vmray_rest_api import VMRayRESTAPI
 | |
| 
 | |
| misperrors = {'error': 'Error'}
 | |
| 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']
 | |
| 
 | |
| 
 | |
| include_vmrayjobids = False
 | |
| 
 | |
| 
 | |
| def handler(q=False):
 | |
|     global include_vmrayjobids
 | |
| 
 | |
|     if q is False:
 | |
|         return False
 | |
|     request = json.loads(q)
 | |
| 
 | |
|     try:
 | |
|         data = request.get("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
 | |
| 
 | |
|     if (request["config"].get("apikey") is None) or (request["config"].get("url") is None):
 | |
|         misperrors["error"] = "Missing API key or server URL (hint: try cloud.vmray.com)"
 | |
|         return misperrors
 | |
| 
 | |
|     api = VMRayRESTAPI(request["config"].get("url"), request["config"].get("apikey"), False)
 | |
| 
 | |
|     shareable = request["config"].get("shareable")
 | |
|     do_not_reanalyze = request["config"].get("do_not_reanalyze")
 | |
|     do_not_include_vmrayjobids = request["config"].get("do_not_include_vmrayjobids")
 | |
| 
 | |
|     # Do we want the sample to be shared?
 | |
|     if shareable == "True":
 | |
|         shareable = True
 | |
|     else:
 | |
|         shareable = False
 | |
| 
 | |
|     # Always reanalyze the sample?
 | |
|     if do_not_reanalyze == "True":
 | |
|         do_not_reanalyze = True
 | |
|     else:
 | |
|         do_not_reanalyze = False
 | |
|     reanalyze = not do_not_reanalyze
 | |
| 
 | |
|     # Include the references to VMRay job IDs
 | |
|     if do_not_include_vmrayjobids == "True":
 | |
|         do_not_include_vmrayjobids = True
 | |
|     else:
 | |
|         do_not_include_vmrayjobids = False
 | |
|     include_vmrayjobids = not do_not_include_vmrayjobids
 | |
| 
 | |
|     if data and sample_filename:
 | |
|         args = {}
 | |
|         args["shareable"] = shareable
 | |
|         args["sample_file"] = {'data': io.BytesIO(data), 'filename': sample_filename}
 | |
|         args["reanalyze"] = reanalyze
 | |
| 
 | |
|         try:
 | |
|             vmraydata = vmraySubmit(api, args)
 | |
|             if vmraydata["errors"]:
 | |
|                 misperrors['error'] = "VMRay: %s" % vmraydata["errors"][0]["error_msg"]
 | |
|                 return misperrors
 | |
|             else:
 | |
|                 return vmrayProcess(vmraydata)
 | |
|         except:
 | |
|             misperrors['error'] = "Problem when calling API."
 | |
|             return misperrors
 | |
|     else:
 | |
|         misperrors['error'] = "No sample data or filename."
 | |
|         return misperrors
 | |
| 
 | |
| 
 | |
| def introspection():
 | |
|     return mispattributes
 | |
| 
 | |
| 
 | |
| def version():
 | |
|     moduleinfo['config'] = moduleconfig
 | |
|     return moduleinfo
 | |
| 
 | |
| 
 | |
| def vmrayProcess(vmraydata):
 | |
|     ''' Process the JSON file returned by vmray'''
 | |
|     if vmraydata:
 | |
|         try:
 | |
|             submissions = vmraydata["submissions"][0]
 | |
|             jobs = vmraydata["jobs"]
 | |
| 
 | |
|             # Result received?
 | |
|             if submissions and jobs:
 | |
|                 r = {'results': []}
 | |
|                 r["results"].append({"types": "md5", "values": submissions["submission_sample_md5"]})
 | |
|                 r["results"].append({"types": "sha1", "values": submissions["submission_sample_sha1"]})
 | |
|                 r["results"].append({"types": "sha256", "values": submissions["submission_sample_sha256"]})
 | |
|                 r["results"].append({"types": "text", "values": "VMRay Sample ID: %s" % submissions["submission_sample_id"]})
 | |
|                 r["results"].append({"types": "text", "values": "VMRay Submission ID: %s" % submissions["submission_id"]})
 | |
|                 r["results"].append({"types": "text", "values": "VMRay Submission Sample IP: %s" % submissions["submission_ip_ip"]})
 | |
|                 r["results"].append({"types": "link", "values": submissions["submission_webif_url"]})
 | |
| 
 | |
|                 # Include data from different jobs
 | |
|                 if include_vmrayjobids:
 | |
|                     for job in jobs:
 | |
|                         job_id = job["job_id"]
 | |
|                         job_vm_name = job["job_vm_name"]
 | |
|                         job_configuration_name = job["job_configuration_name"]
 | |
|                         r["results"].append({"types": "text", "values": "VMRay Job ID %s (%s - %s)" % (job_id, job_vm_name, job_configuration_name)})
 | |
|                 return r
 | |
|             else:
 | |
|                 misperrors['error'] = "No valid results returned."
 | |
|                 return misperrors
 | |
|         except:
 | |
|             misperrors['error'] = "No valid submission data returned."
 | |
|             return misperrors
 | |
|     else:
 | |
|         misperrors['error'] = "Unable to parse results."
 | |
|         return misperrors
 | |
| 
 | |
| 
 | |
| def vmraySubmit(api, args):
 | |
|     ''' Submit the sample to VMRay'''
 | |
|     vmraydata = api.call("POST", "/rest/sample/submit", args)
 | |
|     return vmraydata
 |