forked from MISP/misp-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vmray_submit.py
164 lines (131 loc) · 5.77 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
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/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
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 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")
# 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 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:
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'], 'tags': 'workflow:state="incomplete"'})
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 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