forked from MISP/misp-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vmray_submit.py
151 lines (120 loc) · 5.5 KB
/
vmray_submit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python3
'''
Submit sample to VMRay.
Requires "vmray_rest_api"
The expansion module vmray_submit and import module vmray_import are a two step
process to import data from VMRay.
You can automate this by setting the PyMISP example script 'vmray_automation'
as a cron job
'''
import json
import base64
from distutils.util import strtobool
import io
import zipfile
from _vmray.rest_api import VMRayRESTAPI
misperrors = {'error': 'Error'}
mispattributes = {'input': ['attachment', 'malware-sample'], 'output': ['text', 'sha1', 'sha256', 'md5', 'link']}
moduleinfo = {'version': '0.3', '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 Exception:
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")
try:
shareable = bool(strtobool(shareable)) # Do we want the sample to be shared?
reanalyze = not bool(strtobool(do_not_reanalyze)) # Always reanalyze the sample?
include_vmrayjobids = not bool(strtobool(do_not_include_vmrayjobids)) # Include the references to VMRay job IDs
except ValueError:
misperrors["error"] = "Error while processing settings. Please double-check your values."
return misperrors
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"] and "Submission not stored" not in vmraydata["errors"][0]["error_msg"]:
misperrors['error'] = "VMRay: %s" % vmraydata["errors"][0]["error_msg"]
return misperrors
else:
return vmrayProcess(vmraydata)
except Exception:
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:
sample = vmraydata["samples"][0]
jobs = vmraydata["jobs"]
# Result received?
if sample:
r = {'results': []}
r['results'].append({'types': 'md5', 'values': sample['sample_md5hash']})
r['results'].append({'types': 'sha1', 'values': sample['sample_sha1hash']})
r['results'].append({'types': 'sha256', 'values': sample['sample_sha256hash']})
r['results'].append({'types': 'text', 'values': 'VMRay Sample ID: %s' % sample['sample_id'], 'tags': 'workflow:state="incomplete"'})
r['results'].append({'types': 'link', 'values': sample['sample_webif_url']})
# Include data from different jobs
if include_vmrayjobids and len(jobs) > 0:
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 Exception:
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