sandbox-cli 0.2.26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sandbox_cli/__main__.py +28 -0
- sandbox_cli/cli/__init__.py +46 -0
- sandbox_cli/cli/downloader.py +308 -0
- sandbox_cli/cli/images.py +45 -0
- sandbox_cli/cli/reporter.py +146 -0
- sandbox_cli/cli/rules/__init__.py +83 -0
- sandbox_cli/cli/scanner/__init__.py +681 -0
- sandbox_cli/cli/unpack.py +50 -0
- sandbox_cli/console.py +24 -0
- sandbox_cli/internal/__init__.py +0 -0
- sandbox_cli/internal/config.py +143 -0
- sandbox_cli/internal/helpers.py +32 -0
- sandbox_cli/models/__init__.py +0 -0
- sandbox_cli/models/detections.py +91 -0
- sandbox_cli/utils/__init__.py +0 -0
- sandbox_cli/utils/compiler/__init__.py +60 -0
- sandbox_cli/utils/compiler/abc.py +51 -0
- sandbox_cli/utils/compiler/docker.py +136 -0
- sandbox_cli/utils/compiler/ssh.py +203 -0
- sandbox_cli/utils/downloader/__init__.py +178 -0
- sandbox_cli/utils/extractors.py +66 -0
- sandbox_cli/utils/merge_dll_hooks.py +84 -0
- sandbox_cli/utils/scanner/__init__.py +310 -0
- sandbox_cli/utils/scanner/advanced.py +360 -0
- sandbox_cli/utils/scanner/rescan.py +258 -0
- sandbox_cli/utils/unpack/__init__.py +96 -0
- sandbox_cli/utils/unpack/plugins/__init__.py +0 -0
- sandbox_cli/utils/unpack/plugins/abc.py +18 -0
- sandbox_cli/utils/unpack/plugins/correlation.py +52 -0
- sandbox_cli/utils/unpack/plugins/sort_by_plugins.py +30 -0
- sandbox_cli-0.2.26.dist-info/METADATA +139 -0
- sandbox_cli-0.2.26.dist-info/RECORD +36 -0
- sandbox_cli-0.2.26.dist-info/WHEEL +4 -0
- sandbox_cli-0.2.26.dist-info/entry_points.txt +2 -0
- sandbox_cli-0.2.26.dist-info/licenses/LICENSE +21 -0
- sandbox_cli-0.2.26.dist-info/licenses/NOTICE +322 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated, Any
|
|
5
|
+
|
|
6
|
+
from cyclopts import App, Parameter, Token, validators
|
|
7
|
+
from ptsandbox.models import VNCMode
|
|
8
|
+
|
|
9
|
+
from sandbox_cli.console import console
|
|
10
|
+
from sandbox_cli.internal.config import VMImage, settings
|
|
11
|
+
from sandbox_cli.internal.helpers import validate_key
|
|
12
|
+
from sandbox_cli.utils.scanner import scan_internal
|
|
13
|
+
from sandbox_cli.utils.scanner.advanced import scan_internal_advanced
|
|
14
|
+
from sandbox_cli.utils.scanner.rescan import rescan_internal
|
|
15
|
+
|
|
16
|
+
DELIMETER = "\n"
|
|
17
|
+
|
|
18
|
+
scanner = App(
|
|
19
|
+
name="scanner",
|
|
20
|
+
help="Scan with the sandbox.",
|
|
21
|
+
help_format="markdown",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def image_converter(_: Any, tokens: Sequence[Token]) -> set[VMImage | str]:
|
|
26
|
+
images: set[VMImage | str] = set()
|
|
27
|
+
for token in tokens:
|
|
28
|
+
try:
|
|
29
|
+
images.add(VMImage(token.value))
|
|
30
|
+
except ValueError:
|
|
31
|
+
# maybe it is custom image?
|
|
32
|
+
images.add(token.value)
|
|
33
|
+
|
|
34
|
+
return images
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@scanner.command(name="re-scan")
|
|
38
|
+
async def re_scan(
|
|
39
|
+
traces: Annotated[
|
|
40
|
+
list[Path],
|
|
41
|
+
Parameter(
|
|
42
|
+
help="Path to folder with **drakvuf-trace.log.zst and tcpdump.pcap** or **sandbox_logs.zip**",
|
|
43
|
+
),
|
|
44
|
+
],
|
|
45
|
+
/,
|
|
46
|
+
*,
|
|
47
|
+
rules_dir: Annotated[
|
|
48
|
+
Path | None,
|
|
49
|
+
Parameter(
|
|
50
|
+
name=["--rules", "-r"],
|
|
51
|
+
help="The path to the folder with the rules or the default rules from the sandbox",
|
|
52
|
+
),
|
|
53
|
+
] = None,
|
|
54
|
+
out_dir: Annotated[
|
|
55
|
+
Path,
|
|
56
|
+
Parameter(
|
|
57
|
+
name=["--out", "-o"],
|
|
58
|
+
help="The path where to save the results",
|
|
59
|
+
),
|
|
60
|
+
] = Path("./sandbox"),
|
|
61
|
+
key: Annotated[
|
|
62
|
+
str,
|
|
63
|
+
Parameter(
|
|
64
|
+
name=["--key", "-k"],
|
|
65
|
+
help=f"The key to access the sandbox **{'**,**'.join(x.name for x in settings.sandbox_keys)}**",
|
|
66
|
+
validator=validate_key,
|
|
67
|
+
group="Sandbox Options",
|
|
68
|
+
),
|
|
69
|
+
] = settings.sandbox_keys[0].name,
|
|
70
|
+
is_local: Annotated[
|
|
71
|
+
bool,
|
|
72
|
+
Parameter(
|
|
73
|
+
name=["--local", "-l"],
|
|
74
|
+
negative="",
|
|
75
|
+
help="The rules will be compiled locally using Docker (unix only)",
|
|
76
|
+
),
|
|
77
|
+
] = False,
|
|
78
|
+
unpack: Annotated[
|
|
79
|
+
bool,
|
|
80
|
+
Parameter(
|
|
81
|
+
name=["--unpack", "-U"],
|
|
82
|
+
help="Unpack downloaded files",
|
|
83
|
+
negative="",
|
|
84
|
+
),
|
|
85
|
+
] = False,
|
|
86
|
+
debug: Annotated[
|
|
87
|
+
bool,
|
|
88
|
+
Parameter(
|
|
89
|
+
name=["--debug", "-d"],
|
|
90
|
+
help="Download debug artifacts",
|
|
91
|
+
negative="",
|
|
92
|
+
group="Download options",
|
|
93
|
+
),
|
|
94
|
+
] = False,
|
|
95
|
+
) -> None:
|
|
96
|
+
"""
|
|
97
|
+
Send traces to re-scan.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
out_dir.mkdir(exist_ok=True, parents=True)
|
|
101
|
+
out_dir = out_dir.expanduser().resolve()
|
|
102
|
+
|
|
103
|
+
# sanity check for traces
|
|
104
|
+
is_ok = True
|
|
105
|
+
for trace in traces:
|
|
106
|
+
trace = trace.expanduser().resolve()
|
|
107
|
+
if not trace.exists():
|
|
108
|
+
console.log(f"{str(trace)} doesn't exists", style="bold red")
|
|
109
|
+
is_ok = False
|
|
110
|
+
|
|
111
|
+
if not is_ok:
|
|
112
|
+
sys.exit(1)
|
|
113
|
+
|
|
114
|
+
await rescan_internal(
|
|
115
|
+
traces=traces,
|
|
116
|
+
rules_dir=rules_dir,
|
|
117
|
+
out_dir=out_dir,
|
|
118
|
+
key_name=key,
|
|
119
|
+
is_local=is_local,
|
|
120
|
+
unpack=unpack,
|
|
121
|
+
debug=debug,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@scanner.command(name="scan")
|
|
126
|
+
async def scan(
|
|
127
|
+
files: Annotated[
|
|
128
|
+
list[Path],
|
|
129
|
+
Parameter(
|
|
130
|
+
help="Path to the files or folders to scan",
|
|
131
|
+
),
|
|
132
|
+
],
|
|
133
|
+
/,
|
|
134
|
+
*,
|
|
135
|
+
rules_dir: Annotated[
|
|
136
|
+
Path | None,
|
|
137
|
+
Parameter(
|
|
138
|
+
name=["--rules", "-r"],
|
|
139
|
+
help="The path to the folder with the rules or the default rules from the sandbox",
|
|
140
|
+
),
|
|
141
|
+
] = None,
|
|
142
|
+
out_dir: Annotated[
|
|
143
|
+
Path,
|
|
144
|
+
Parameter(
|
|
145
|
+
name=["--out", "-o"],
|
|
146
|
+
help="The path where to save the results",
|
|
147
|
+
),
|
|
148
|
+
] = Path("./sandbox"),
|
|
149
|
+
images: Annotated[
|
|
150
|
+
set[VMImage] | None,
|
|
151
|
+
Parameter(
|
|
152
|
+
name=["--image", "-i"],
|
|
153
|
+
help=f"The name of the image to scan (*don't mix different platforms*) {DELIMETER}{DELIMETER.join(f'* {x}' for x in VMImage._value2member_map_.keys())}{DELIMETER * 2}",
|
|
154
|
+
negative="",
|
|
155
|
+
group="Sandbox Options",
|
|
156
|
+
show_choices=False,
|
|
157
|
+
converter=image_converter,
|
|
158
|
+
),
|
|
159
|
+
] = None,
|
|
160
|
+
key: Annotated[
|
|
161
|
+
str,
|
|
162
|
+
Parameter(
|
|
163
|
+
name=["--key", "-k"],
|
|
164
|
+
help=f"The key to access the sandbox **{'**,**'.join(x.name for x in settings.sandbox_keys)}**",
|
|
165
|
+
validator=validate_key,
|
|
166
|
+
group="Sandbox Options",
|
|
167
|
+
),
|
|
168
|
+
] = settings.sandbox_keys[0].name,
|
|
169
|
+
is_local: Annotated[
|
|
170
|
+
bool,
|
|
171
|
+
Parameter(
|
|
172
|
+
name=["--local", "-l"],
|
|
173
|
+
negative="",
|
|
174
|
+
help="The rules will be compiled locally using Docker (unix only)",
|
|
175
|
+
),
|
|
176
|
+
] = False,
|
|
177
|
+
unpack: Annotated[
|
|
178
|
+
bool,
|
|
179
|
+
Parameter(
|
|
180
|
+
name=["--unpack", "-U"],
|
|
181
|
+
help="Unpack downloaded files",
|
|
182
|
+
negative="",
|
|
183
|
+
),
|
|
184
|
+
] = False,
|
|
185
|
+
upload_timeout: Annotated[
|
|
186
|
+
int,
|
|
187
|
+
Parameter(
|
|
188
|
+
name=["--upload-timeout", "-T"],
|
|
189
|
+
help="Upload timeout in seconds (increase if upload big files)",
|
|
190
|
+
validator=validators.Number(gt=0),
|
|
191
|
+
),
|
|
192
|
+
] = 300,
|
|
193
|
+
fake_name: Annotated[
|
|
194
|
+
str | None,
|
|
195
|
+
Parameter(
|
|
196
|
+
name=["--name", "-n"],
|
|
197
|
+
help="Fake name for the sandbox (if specified more than one files will be applied to all files)",
|
|
198
|
+
group="Sandbox Options",
|
|
199
|
+
),
|
|
200
|
+
] = None,
|
|
201
|
+
analysis_duration: Annotated[
|
|
202
|
+
int,
|
|
203
|
+
Parameter(
|
|
204
|
+
name=["--timeout", "-t"],
|
|
205
|
+
help="Analysis duration in seconds",
|
|
206
|
+
validator=validators.Number(gt=0, lt=3600),
|
|
207
|
+
group="Sandbox Options",
|
|
208
|
+
),
|
|
209
|
+
] = settings.default_duration,
|
|
210
|
+
syscall_hooks: Annotated[
|
|
211
|
+
Path | None,
|
|
212
|
+
Parameter(
|
|
213
|
+
name=["--syscall-hooks", "-s"],
|
|
214
|
+
help="Path to files with syscall hooks (file with syscall names splitted by newline)",
|
|
215
|
+
group="Sandbox Options",
|
|
216
|
+
),
|
|
217
|
+
] = None,
|
|
218
|
+
dll_hooks_dir: Annotated[
|
|
219
|
+
Path | None,
|
|
220
|
+
Parameter(
|
|
221
|
+
name=["--dll-hooks-dir", "-dll"],
|
|
222
|
+
help="Path to directory with dll hooks",
|
|
223
|
+
group="Sandbox Options",
|
|
224
|
+
),
|
|
225
|
+
] = None,
|
|
226
|
+
custom_command: Annotated[
|
|
227
|
+
str | None,
|
|
228
|
+
Parameter(
|
|
229
|
+
name="--cmd",
|
|
230
|
+
help="Command line for file execution `rundll32.exe {file},#1`",
|
|
231
|
+
group="Sandbox Options",
|
|
232
|
+
),
|
|
233
|
+
] = None,
|
|
234
|
+
all: Annotated[
|
|
235
|
+
bool,
|
|
236
|
+
Parameter(
|
|
237
|
+
name=["--all", "-a"],
|
|
238
|
+
help="Download all artifacts",
|
|
239
|
+
negative="",
|
|
240
|
+
group="Download options",
|
|
241
|
+
),
|
|
242
|
+
] = False,
|
|
243
|
+
debug: Annotated[
|
|
244
|
+
bool,
|
|
245
|
+
Parameter(
|
|
246
|
+
name=["--debug", "-d"],
|
|
247
|
+
help="Download debug artifacts",
|
|
248
|
+
negative="",
|
|
249
|
+
group="Download options",
|
|
250
|
+
),
|
|
251
|
+
] = False,
|
|
252
|
+
artifacts: Annotated[
|
|
253
|
+
bool,
|
|
254
|
+
Parameter(
|
|
255
|
+
name=["--artifacts", "-A"],
|
|
256
|
+
help="Download artifacts",
|
|
257
|
+
negative="",
|
|
258
|
+
group="Download options",
|
|
259
|
+
),
|
|
260
|
+
] = False,
|
|
261
|
+
download_files: Annotated[
|
|
262
|
+
bool,
|
|
263
|
+
Parameter(
|
|
264
|
+
name=["--files", "-f"],
|
|
265
|
+
help="Download files",
|
|
266
|
+
negative="",
|
|
267
|
+
group="Download options",
|
|
268
|
+
),
|
|
269
|
+
] = False,
|
|
270
|
+
crashdumps: Annotated[
|
|
271
|
+
bool,
|
|
272
|
+
Parameter(
|
|
273
|
+
name=["--crashdumps", "-c"],
|
|
274
|
+
help="Download crashdumps (maybe be more 1GB)",
|
|
275
|
+
negative="",
|
|
276
|
+
group="Download options",
|
|
277
|
+
),
|
|
278
|
+
] = False,
|
|
279
|
+
procdumps: Annotated[
|
|
280
|
+
bool,
|
|
281
|
+
Parameter(
|
|
282
|
+
name=["--procdumps", "-p"],
|
|
283
|
+
help="Download procdumps",
|
|
284
|
+
negative="",
|
|
285
|
+
group="Download options",
|
|
286
|
+
),
|
|
287
|
+
] = False,
|
|
288
|
+
decompress: Annotated[
|
|
289
|
+
bool,
|
|
290
|
+
Parameter(
|
|
291
|
+
name=["--decompress", "-D"],
|
|
292
|
+
help="Decompress downloaded files",
|
|
293
|
+
negative="",
|
|
294
|
+
),
|
|
295
|
+
] = False,
|
|
296
|
+
) -> None:
|
|
297
|
+
"""
|
|
298
|
+
Send files to scan with the sandbox.
|
|
299
|
+
|
|
300
|
+
If you want to scan a folder, you can specify the path to the folder
|
|
301
|
+
|
|
302
|
+
Amount of simultaneous scans is limited by the sandbox settings (usually 8)
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
console.warning('Deprecated option, not particularly supported. Use "scan-new" instead')
|
|
306
|
+
|
|
307
|
+
# some path preparations
|
|
308
|
+
out_dir.mkdir(exist_ok=True, parents=True)
|
|
309
|
+
out_dir = out_dir.expanduser().resolve()
|
|
310
|
+
|
|
311
|
+
if images is None:
|
|
312
|
+
images = {settings.default_image}
|
|
313
|
+
|
|
314
|
+
# parse files options
|
|
315
|
+
is_ok = True
|
|
316
|
+
files_for_analysis: list[Path] = []
|
|
317
|
+
for file in files:
|
|
318
|
+
file = file.expanduser().resolve()
|
|
319
|
+
|
|
320
|
+
if not file.exists():
|
|
321
|
+
console.error(f"{str(file)} doesn't exists")
|
|
322
|
+
is_ok = False
|
|
323
|
+
|
|
324
|
+
if file.is_dir():
|
|
325
|
+
files_for_analysis.extend(file.glob("**/*"))
|
|
326
|
+
continue
|
|
327
|
+
|
|
328
|
+
files_for_analysis.append(file)
|
|
329
|
+
|
|
330
|
+
if not is_ok:
|
|
331
|
+
sys.exit(1)
|
|
332
|
+
|
|
333
|
+
if len(files_for_analysis) == 0:
|
|
334
|
+
console.error("Nothing to scan")
|
|
335
|
+
sys.exit(1)
|
|
336
|
+
|
|
337
|
+
await scan_internal(
|
|
338
|
+
files=files_for_analysis,
|
|
339
|
+
scan_images=images,
|
|
340
|
+
rules_dir=rules_dir,
|
|
341
|
+
out_dir=out_dir,
|
|
342
|
+
key_name=key,
|
|
343
|
+
is_local=is_local,
|
|
344
|
+
analysis_duration=analysis_duration,
|
|
345
|
+
syscall_hooks=syscall_hooks,
|
|
346
|
+
custom_command=custom_command,
|
|
347
|
+
dll_hooks_dir=dll_hooks_dir,
|
|
348
|
+
fake_name=fake_name,
|
|
349
|
+
unpack=unpack,
|
|
350
|
+
upload_timeout=upload_timeout,
|
|
351
|
+
all=all,
|
|
352
|
+
debug=debug,
|
|
353
|
+
artifacts=artifacts,
|
|
354
|
+
download_files=download_files,
|
|
355
|
+
crashdumps=crashdumps,
|
|
356
|
+
procdumps=procdumps,
|
|
357
|
+
decompress=decompress,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
@scanner.command(name="scan-new")
|
|
362
|
+
async def scan_new(
|
|
363
|
+
files: Annotated[
|
|
364
|
+
list[Path],
|
|
365
|
+
Parameter(
|
|
366
|
+
help="Path to the files or folders to scan",
|
|
367
|
+
),
|
|
368
|
+
],
|
|
369
|
+
/,
|
|
370
|
+
*,
|
|
371
|
+
rules_dir: Annotated[
|
|
372
|
+
Path | None,
|
|
373
|
+
Parameter(
|
|
374
|
+
name=["--rules", "-r"],
|
|
375
|
+
help="The path to the folder with the rules or the default rules from the sandbox",
|
|
376
|
+
),
|
|
377
|
+
] = None,
|
|
378
|
+
out_dir: Annotated[
|
|
379
|
+
Path,
|
|
380
|
+
Parameter(
|
|
381
|
+
name=["--out", "-o"],
|
|
382
|
+
help="The path where to save the results",
|
|
383
|
+
),
|
|
384
|
+
] = Path("./sandbox"),
|
|
385
|
+
images: Annotated[
|
|
386
|
+
set[VMImage | str] | None,
|
|
387
|
+
Parameter(
|
|
388
|
+
name=["--image", "-i"],
|
|
389
|
+
help=f"The name of the image to scan (*don't mix different platforms*) {DELIMETER}{DELIMETER.join(f'* {x}' for x in VMImage._value2member_map_.keys())}{DELIMETER * 2}",
|
|
390
|
+
negative="",
|
|
391
|
+
group="Sandbox Options",
|
|
392
|
+
show_choices=False,
|
|
393
|
+
converter=image_converter,
|
|
394
|
+
),
|
|
395
|
+
] = None,
|
|
396
|
+
key: Annotated[
|
|
397
|
+
str,
|
|
398
|
+
Parameter(
|
|
399
|
+
name=["--key", "-k"],
|
|
400
|
+
help=f"The key to access the sandbox **{'**,**'.join(x.name for x in settings.sandbox_keys)}**",
|
|
401
|
+
validator=validate_key,
|
|
402
|
+
group="Sandbox Options",
|
|
403
|
+
),
|
|
404
|
+
] = settings.sandbox_keys[0].name,
|
|
405
|
+
is_local: Annotated[
|
|
406
|
+
bool,
|
|
407
|
+
Parameter(
|
|
408
|
+
name=["--local", "-l"],
|
|
409
|
+
negative="",
|
|
410
|
+
help="The rules will be compiled locally using Docker (unix only)",
|
|
411
|
+
),
|
|
412
|
+
] = False,
|
|
413
|
+
upload_timeout: Annotated[
|
|
414
|
+
int,
|
|
415
|
+
Parameter(
|
|
416
|
+
name=["--upload-timeout", "-T"],
|
|
417
|
+
help="Upload timeout in seconds (increase if upload big files)",
|
|
418
|
+
validator=validators.Number(gt=0),
|
|
419
|
+
),
|
|
420
|
+
] = 300,
|
|
421
|
+
fake_name: Annotated[
|
|
422
|
+
str | None,
|
|
423
|
+
Parameter(
|
|
424
|
+
name=["--name", "-n"],
|
|
425
|
+
help="Fake name for the sandbox (if specified more than one file will be applied to all files)",
|
|
426
|
+
group="Sandbox Options",
|
|
427
|
+
),
|
|
428
|
+
] = None,
|
|
429
|
+
analysis_duration: Annotated[
|
|
430
|
+
int,
|
|
431
|
+
Parameter(
|
|
432
|
+
name=["--timeout", "-t"],
|
|
433
|
+
help="Analysis duration in seconds",
|
|
434
|
+
validator=validators.Number(gt=0, lt=3600),
|
|
435
|
+
group="Sandbox Options",
|
|
436
|
+
),
|
|
437
|
+
] = settings.default_duration,
|
|
438
|
+
syscall_hooks: Annotated[
|
|
439
|
+
Path | None,
|
|
440
|
+
Parameter(
|
|
441
|
+
name=["--syscall-hooks", "-s"],
|
|
442
|
+
help="Path to files with syscall hooks (file with syscall names splitted by newline)",
|
|
443
|
+
group="Sandbox Options",
|
|
444
|
+
),
|
|
445
|
+
] = None,
|
|
446
|
+
dll_hooks_dir: Annotated[
|
|
447
|
+
Path | None,
|
|
448
|
+
Parameter(
|
|
449
|
+
name=["--dll-hooks-dir", "-dll"],
|
|
450
|
+
help="Path to directory with dll hooks",
|
|
451
|
+
group="Sandbox Options",
|
|
452
|
+
),
|
|
453
|
+
] = None,
|
|
454
|
+
custom_command: Annotated[
|
|
455
|
+
str | None,
|
|
456
|
+
Parameter(
|
|
457
|
+
name="--cmd",
|
|
458
|
+
help="Command line for file execution _rundll32.exe {file},#1_",
|
|
459
|
+
group="Sandbox Options",
|
|
460
|
+
),
|
|
461
|
+
] = None,
|
|
462
|
+
unpack: Annotated[
|
|
463
|
+
bool,
|
|
464
|
+
Parameter(
|
|
465
|
+
name=["--unpack", "-U"],
|
|
466
|
+
help="Unpack downloaded files",
|
|
467
|
+
negative="",
|
|
468
|
+
),
|
|
469
|
+
] = False,
|
|
470
|
+
priority: Annotated[
|
|
471
|
+
int,
|
|
472
|
+
Parameter(
|
|
473
|
+
name=["--priority", "-pr"],
|
|
474
|
+
help="Priority of the scan (1-4)",
|
|
475
|
+
validator=validators.Number(gte=1, lte=4),
|
|
476
|
+
group="Sandbox Options",
|
|
477
|
+
),
|
|
478
|
+
] = 3,
|
|
479
|
+
procdump_new_processes_on_finish: Annotated[
|
|
480
|
+
bool,
|
|
481
|
+
Parameter(
|
|
482
|
+
name=["--procdump-new-processes-on-finish", "-P"],
|
|
483
|
+
help="Collect dumps for all created and not finished processes",
|
|
484
|
+
group="Sandbox Options",
|
|
485
|
+
negative="",
|
|
486
|
+
),
|
|
487
|
+
] = False,
|
|
488
|
+
bootkitmon: Annotated[
|
|
489
|
+
bool,
|
|
490
|
+
Parameter(
|
|
491
|
+
name=["--bootkitmon", "-b"],
|
|
492
|
+
help="Enable bootkitmon",
|
|
493
|
+
group="Sandbox Options",
|
|
494
|
+
negative="",
|
|
495
|
+
),
|
|
496
|
+
] = False,
|
|
497
|
+
bootkitmon_duration: Annotated[
|
|
498
|
+
int,
|
|
499
|
+
Parameter(
|
|
500
|
+
name=["--bootkitmon-duration", "-bd"],
|
|
501
|
+
help="Bootkitmon duration in seconds",
|
|
502
|
+
validator=validators.Number(gt=0),
|
|
503
|
+
group="Sandbox Options",
|
|
504
|
+
negative="",
|
|
505
|
+
),
|
|
506
|
+
] = 60,
|
|
507
|
+
mitm_disabled: Annotated[
|
|
508
|
+
bool,
|
|
509
|
+
Parameter(
|
|
510
|
+
name=["--mitm-disabled", "-M"],
|
|
511
|
+
help="Disable MITM",
|
|
512
|
+
group="Sandbox Options",
|
|
513
|
+
negative="",
|
|
514
|
+
),
|
|
515
|
+
] = False,
|
|
516
|
+
disable_clicker: Annotated[
|
|
517
|
+
bool,
|
|
518
|
+
Parameter(
|
|
519
|
+
name=["--disable-clicker", "-dc"],
|
|
520
|
+
help="Disable clicker",
|
|
521
|
+
group="Sandbox Options",
|
|
522
|
+
negative="",
|
|
523
|
+
),
|
|
524
|
+
] = False,
|
|
525
|
+
skip_sample_run: Annotated[
|
|
526
|
+
bool,
|
|
527
|
+
Parameter(
|
|
528
|
+
name=["--skip-sample-run", "-S"],
|
|
529
|
+
help="Skip sample run",
|
|
530
|
+
group="Sandbox Options",
|
|
531
|
+
negative="",
|
|
532
|
+
),
|
|
533
|
+
] = False,
|
|
534
|
+
vnc_mode: Annotated[
|
|
535
|
+
VNCMode,
|
|
536
|
+
Parameter(
|
|
537
|
+
name=["--vnc-mode", "-V"],
|
|
538
|
+
help="VNC mode",
|
|
539
|
+
group="Sandbox Options",
|
|
540
|
+
),
|
|
541
|
+
] = VNCMode.DISABLED,
|
|
542
|
+
extra_files: Annotated[
|
|
543
|
+
list[Path] | None,
|
|
544
|
+
Parameter(
|
|
545
|
+
name=["--extra-files", "-e"],
|
|
546
|
+
help="Extra files to upload",
|
|
547
|
+
group="Sandbox Options",
|
|
548
|
+
negative="",
|
|
549
|
+
),
|
|
550
|
+
] = None,
|
|
551
|
+
all: Annotated[
|
|
552
|
+
bool,
|
|
553
|
+
Parameter(
|
|
554
|
+
name=["--all", "-a"],
|
|
555
|
+
help="Download all artifacts",
|
|
556
|
+
negative="",
|
|
557
|
+
group="Download options",
|
|
558
|
+
),
|
|
559
|
+
] = False,
|
|
560
|
+
debug: Annotated[
|
|
561
|
+
bool,
|
|
562
|
+
Parameter(
|
|
563
|
+
name=["--debug", "-d"],
|
|
564
|
+
help="Download debug artifacts",
|
|
565
|
+
negative="",
|
|
566
|
+
group="Download options",
|
|
567
|
+
),
|
|
568
|
+
] = False,
|
|
569
|
+
artifacts: Annotated[
|
|
570
|
+
bool,
|
|
571
|
+
Parameter(
|
|
572
|
+
name=["--artifacts", "-A"],
|
|
573
|
+
help="Download artifacts",
|
|
574
|
+
negative="",
|
|
575
|
+
group="Download options",
|
|
576
|
+
),
|
|
577
|
+
] = False,
|
|
578
|
+
download_files: Annotated[
|
|
579
|
+
bool,
|
|
580
|
+
Parameter(
|
|
581
|
+
name=["--files", "-f"],
|
|
582
|
+
help="Download files",
|
|
583
|
+
negative="",
|
|
584
|
+
group="Download options",
|
|
585
|
+
),
|
|
586
|
+
] = False,
|
|
587
|
+
crashdumps: Annotated[
|
|
588
|
+
bool,
|
|
589
|
+
Parameter(
|
|
590
|
+
name=["--crashdumps", "-c"],
|
|
591
|
+
help="Download crashdumps (maybe be more 1GB)",
|
|
592
|
+
negative="",
|
|
593
|
+
group="Download options",
|
|
594
|
+
),
|
|
595
|
+
] = False,
|
|
596
|
+
procdumps: Annotated[
|
|
597
|
+
bool,
|
|
598
|
+
Parameter(
|
|
599
|
+
name=["--procdumps", "-p"],
|
|
600
|
+
help="Download procdumps",
|
|
601
|
+
negative="",
|
|
602
|
+
group="Download options",
|
|
603
|
+
),
|
|
604
|
+
] = False,
|
|
605
|
+
decompress: Annotated[
|
|
606
|
+
bool,
|
|
607
|
+
Parameter(
|
|
608
|
+
name=["--decompress", "-D"],
|
|
609
|
+
help="Decompress downloaded files",
|
|
610
|
+
negative="",
|
|
611
|
+
),
|
|
612
|
+
] = False,
|
|
613
|
+
) -> None:
|
|
614
|
+
"""
|
|
615
|
+
Send files to scan with the sandbox (advanced scan).
|
|
616
|
+
"""
|
|
617
|
+
|
|
618
|
+
# some path preparations
|
|
619
|
+
out_dir.mkdir(exist_ok=True, parents=True)
|
|
620
|
+
out_dir = out_dir.expanduser().resolve()
|
|
621
|
+
|
|
622
|
+
if images is None:
|
|
623
|
+
images = {settings.default_image}
|
|
624
|
+
|
|
625
|
+
if extra_files is None:
|
|
626
|
+
extra_files = []
|
|
627
|
+
|
|
628
|
+
# parse files options
|
|
629
|
+
is_ok = True
|
|
630
|
+
files_for_analysis: list[Path] = []
|
|
631
|
+
for file in files:
|
|
632
|
+
file = file.expanduser().resolve()
|
|
633
|
+
|
|
634
|
+
if not file.exists():
|
|
635
|
+
console.error(f"{str(file)} doesn't exists")
|
|
636
|
+
is_ok = False
|
|
637
|
+
|
|
638
|
+
if file.is_dir():
|
|
639
|
+
files_for_analysis.extend(file.glob("**/*"))
|
|
640
|
+
continue
|
|
641
|
+
|
|
642
|
+
files_for_analysis.append(file)
|
|
643
|
+
|
|
644
|
+
if not is_ok:
|
|
645
|
+
sys.exit(1)
|
|
646
|
+
|
|
647
|
+
if len(files_for_analysis) == 0:
|
|
648
|
+
console.error("Nothing to scan")
|
|
649
|
+
sys.exit(1)
|
|
650
|
+
|
|
651
|
+
await scan_internal_advanced(
|
|
652
|
+
files=files_for_analysis,
|
|
653
|
+
scan_images=images,
|
|
654
|
+
rules_dir=rules_dir,
|
|
655
|
+
out_dir=out_dir,
|
|
656
|
+
key_name=key,
|
|
657
|
+
is_local=is_local,
|
|
658
|
+
analysis_duration=analysis_duration,
|
|
659
|
+
syscall_hooks=syscall_hooks,
|
|
660
|
+
custom_command=custom_command,
|
|
661
|
+
dll_hooks_dir=dll_hooks_dir,
|
|
662
|
+
fake_name=fake_name,
|
|
663
|
+
unpack=unpack,
|
|
664
|
+
priority=priority,
|
|
665
|
+
procdump_new_processes_on_finish=procdump_new_processes_on_finish,
|
|
666
|
+
bootkitmon=bootkitmon,
|
|
667
|
+
bootkitmon_duration=bootkitmon_duration,
|
|
668
|
+
mitm_disabled=mitm_disabled,
|
|
669
|
+
disable_clicker=disable_clicker,
|
|
670
|
+
skip_sample_run=skip_sample_run,
|
|
671
|
+
vnc_mode=vnc_mode,
|
|
672
|
+
extra_files=extra_files,
|
|
673
|
+
upload_timeout=upload_timeout,
|
|
674
|
+
all=all,
|
|
675
|
+
debug=debug,
|
|
676
|
+
artifacts=artifacts,
|
|
677
|
+
download_files=download_files,
|
|
678
|
+
crashdumps=crashdumps,
|
|
679
|
+
procdumps=procdumps,
|
|
680
|
+
decompress=decompress,
|
|
681
|
+
)
|