sandbox-cli 0.2.37__tar.gz → 0.2.39__tar.gz
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-0.2.37 → sandbox_cli-0.2.39}/PKG-INFO +1 -1
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/pyproject.toml +9 -8
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/__init__.py +2 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/downloader.py +5 -6
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/reporter.py +9 -1
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/rules/__init__.py +2 -2
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/downloader/__init__.py +14 -3
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/extractors.py +9 -11
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/scanner/advanced.py +59 -26
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/scanner/rescan.py +8 -2
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/__init__.py +10 -3
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/plugins/correlation.py +0 -2
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/plugins/sort_by_plugins.py +0 -2
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/.gitignore +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/LICENSE +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/NOTICE +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/README.md +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/__main__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/images.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/scanner/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/cli/unpack.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/console.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/internal/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/internal/config.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/internal/helpers.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/models/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/models/detections.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/models/sandbox_arguments.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/compiler/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/compiler/abc.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/compiler/docker.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/compiler/ssh.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/merge_dll_hooks.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/scanner/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/plugins/__init__.py +0 -0
- {sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/plugins/abc.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sandbox-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.39
|
|
4
4
|
Summary: Command line tool for interaction with sandboxes
|
|
5
5
|
Project-URL: Homepage, https://github.com/Security-Experts-Community/sandbox-cli
|
|
6
6
|
Project-URL: Documentation, https://security-experts-community.github.io/sandbox-cli
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sandbox-cli"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.39"
|
|
4
4
|
description = "Command line tool for interaction with sandboxes"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -87,13 +87,14 @@ ignore_missing_imports = true
|
|
|
87
87
|
|
|
88
88
|
[tool.ruff]
|
|
89
89
|
lint.select = [
|
|
90
|
-
"E",
|
|
91
|
-
"W",
|
|
92
|
-
"F",
|
|
93
|
-
"I",
|
|
94
|
-
"B",
|
|
95
|
-
"C4",
|
|
96
|
-
"UP",
|
|
90
|
+
"E", # pycodestyle errors
|
|
91
|
+
"W", # pycodestyle warnings
|
|
92
|
+
"F", # pyflakes
|
|
93
|
+
"I", # isort
|
|
94
|
+
"B", # flake8-bugbear
|
|
95
|
+
"C4", # flake8-comprehensions
|
|
96
|
+
"UP", # pyupgrade
|
|
97
|
+
"F401", # unused-imports
|
|
97
98
|
]
|
|
98
99
|
lint.ignore = [
|
|
99
100
|
"E501", # line too long, handled by black
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Register all commands here
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from colorama import init
|
|
5
6
|
from cyclopts import App
|
|
6
7
|
|
|
7
8
|
from sandbox_cli.cli.reporter import generate_report, open_browser
|
|
@@ -9,6 +10,7 @@ from sandbox_cli.cli.unpack import unpack_logs
|
|
|
9
10
|
from sandbox_cli.console import console
|
|
10
11
|
from sandbox_cli.internal.config import configpath, settings
|
|
11
12
|
|
|
13
|
+
init() # colorama stuff for working on windows
|
|
12
14
|
|
|
13
15
|
def get_version() -> str:
|
|
14
16
|
import importlib.metadata
|
|
@@ -11,12 +11,10 @@ from uuid import UUID
|
|
|
11
11
|
import aiofiles
|
|
12
12
|
import aiohttp
|
|
13
13
|
import aiohttp.client_exceptions
|
|
14
|
-
import orjson
|
|
15
|
-
from colorama import init
|
|
16
14
|
from cyclopts import Parameter
|
|
17
15
|
from ptsandbox import Sandbox
|
|
18
16
|
from ptsandbox.models import Artifact, SandboxBaseTaskResponse
|
|
19
|
-
from rich.progress import Progress, SpinnerColumn,
|
|
17
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
|
20
18
|
|
|
21
19
|
from sandbox_cli.console import console
|
|
22
20
|
from sandbox_cli.internal.config import settings
|
|
@@ -51,12 +49,12 @@ def get_key_and_task(key: str, task: str) -> tuple[Sandbox, UUID] | tuple[None,
|
|
|
51
49
|
|
|
52
50
|
async def download_command(
|
|
53
51
|
tasks_id: Annotated[
|
|
54
|
-
list[str],
|
|
52
|
+
list[str] | None,
|
|
55
53
|
Parameter(
|
|
56
54
|
help="Links to tasks or task ids",
|
|
57
55
|
negative="",
|
|
58
56
|
),
|
|
59
|
-
] =
|
|
57
|
+
] = None,
|
|
60
58
|
/,
|
|
61
59
|
*,
|
|
62
60
|
key: Annotated[
|
|
@@ -184,7 +182,8 @@ async def download_command(
|
|
|
184
182
|
Download any artifact from the sandbox.
|
|
185
183
|
"""
|
|
186
184
|
|
|
187
|
-
|
|
185
|
+
if tasks_id is None:
|
|
186
|
+
tasks_id = []
|
|
188
187
|
|
|
189
188
|
progress = Progress(
|
|
190
189
|
SpinnerColumn(),
|
|
@@ -53,6 +53,14 @@ def generate_report(
|
|
|
53
53
|
negative="",
|
|
54
54
|
),
|
|
55
55
|
] = False,
|
|
56
|
+
suspicious: Annotated[
|
|
57
|
+
bool,
|
|
58
|
+
Parameter(
|
|
59
|
+
name=["--supicious", "-s"],
|
|
60
|
+
help="Include suspicious detects",
|
|
61
|
+
negative="",
|
|
62
|
+
),
|
|
63
|
+
] = False,
|
|
56
64
|
) -> None:
|
|
57
65
|
"""
|
|
58
66
|
Generate short report from sandbox scans.
|
|
@@ -118,7 +126,7 @@ def generate_report(
|
|
|
118
126
|
{
|
|
119
127
|
"sample": report.artifacts[0].file_info.file_path, # type: ignore
|
|
120
128
|
"image": image,
|
|
121
|
-
"verdict": delimeter.join(extract_verdict_from_trace(corr_trace)),
|
|
129
|
+
"verdict": delimeter.join(extract_verdict_from_trace(corr_trace, suspicious)),
|
|
122
130
|
"static": delimeter.join(extract_static(report)),
|
|
123
131
|
"memory": delimeter.join(extract_memory(report)),
|
|
124
132
|
"network": delimeter.join(extract_network_from_trace(corr_trace)),
|
|
@@ -15,7 +15,6 @@ rules = App(
|
|
|
15
15
|
|
|
16
16
|
@rules.command(name="compile")
|
|
17
17
|
async def compile_rules(
|
|
18
|
-
*,
|
|
19
18
|
rules: Annotated[
|
|
20
19
|
Path,
|
|
21
20
|
Parameter(
|
|
@@ -24,6 +23,7 @@ async def compile_rules(
|
|
|
24
23
|
validator=validators.Path(exists=True),
|
|
25
24
|
),
|
|
26
25
|
],
|
|
26
|
+
/,
|
|
27
27
|
out: Annotated[
|
|
28
28
|
Path,
|
|
29
29
|
Parameter(
|
|
@@ -57,7 +57,6 @@ async def compile_rules(
|
|
|
57
57
|
|
|
58
58
|
@rules.command(name="test")
|
|
59
59
|
async def test_rules(
|
|
60
|
-
*,
|
|
61
60
|
rules: Annotated[
|
|
62
61
|
Path,
|
|
63
62
|
Parameter(
|
|
@@ -66,6 +65,7 @@ async def test_rules(
|
|
|
66
65
|
validator=validators.Path(exists=True),
|
|
67
66
|
),
|
|
68
67
|
],
|
|
68
|
+
/,
|
|
69
69
|
is_local: Annotated[
|
|
70
70
|
bool,
|
|
71
71
|
Parameter(
|
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
|
6
6
|
from uuid import UUID
|
|
7
7
|
|
|
8
8
|
import aiofiles
|
|
9
|
+
import aiohttp
|
|
9
10
|
import zstandard
|
|
10
11
|
from ptsandbox import Sandbox
|
|
11
12
|
from ptsandbox.models import (
|
|
@@ -18,7 +19,6 @@ from rich.markup import escape
|
|
|
18
19
|
from rich.progress import Progress, TaskID
|
|
19
20
|
|
|
20
21
|
from sandbox_cli.console import console
|
|
21
|
-
from sandbox_cli.internal.config import settings
|
|
22
22
|
|
|
23
23
|
semaphore = asyncio.Semaphore(value=16)
|
|
24
24
|
|
|
@@ -66,13 +66,20 @@ async def _save_artifact(
|
|
|
66
66
|
else:
|
|
67
67
|
task_id = progress.add_task(rf"\[[green1]{scan_id}[/]] {escape(path.name)}")
|
|
68
68
|
try:
|
|
69
|
-
|
|
69
|
+
# a 5-minute timeout for downloading large files
|
|
70
|
+
downloaded_data = await sandbox.get_file(uri, read_timeout=300)
|
|
70
71
|
except SandboxFileNotFoundException:
|
|
71
72
|
console.warning(f"File {path.name} not found in storage: {uri=} {scan_id=}")
|
|
72
73
|
if progress:
|
|
73
74
|
progress.stop_task(task_id)
|
|
74
75
|
progress.update(task_id=task_id, visible=False)
|
|
75
76
|
return
|
|
77
|
+
except aiohttp.SocketTimeoutError as e:
|
|
78
|
+
if progress:
|
|
79
|
+
progress.stop_task(task_id)
|
|
80
|
+
progress.update(task_id=task_id, visible=False)
|
|
81
|
+
|
|
82
|
+
raise e
|
|
76
83
|
|
|
77
84
|
if decompress:
|
|
78
85
|
try:
|
|
@@ -139,7 +146,11 @@ async def download(
|
|
|
139
146
|
if sandbox_result.details.sandbox is None:
|
|
140
147
|
continue
|
|
141
148
|
|
|
142
|
-
if
|
|
149
|
+
if (
|
|
150
|
+
sandbox_result.details.sandbox.image
|
|
151
|
+
and (image_id := sandbox_result.details.sandbox.image.image_id)
|
|
152
|
+
and out_dir.parts[-1] != image_id
|
|
153
|
+
):
|
|
143
154
|
output = out_dir / image_id
|
|
144
155
|
else:
|
|
145
156
|
output = out_dir
|
|
@@ -4,18 +4,16 @@ from ptsandbox.models import ArtifactType, EngineSubsystem, SandboxBaseTaskRespo
|
|
|
4
4
|
from sandbox_cli.models.detections import Detections
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def extract_verdict_from_trace(trace: bytes) ->
|
|
8
|
-
non_generics: set[str] = set()
|
|
9
|
-
generics: set[str] = set()
|
|
10
|
-
|
|
7
|
+
def extract_verdict_from_trace(trace: bytes, suspicious: bool = False) -> list[str]:
|
|
11
8
|
d = Detections(trace)
|
|
12
|
-
for detect in d.malware
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
malware_detects: list[str] = list({detect.name for detect in d.malware})
|
|
10
|
+
suspicious_detects: set[str] = set()
|
|
11
|
+
if suspicious:
|
|
12
|
+
for detect in d.suspicious:
|
|
13
|
+
suspicious_detects.add(detect.name)
|
|
14
|
+
|
|
15
|
+
# malware detects always on top
|
|
16
|
+
return malware_detects + sorted(suspicious_detects)
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
def extract_network_from_trace(trace: bytes) -> set[str]:
|
|
@@ -8,9 +8,21 @@ import aiofiles
|
|
|
8
8
|
import aiohttp
|
|
9
9
|
import aiohttp.client_exceptions
|
|
10
10
|
from ptsandbox import Sandbox, SandboxKey
|
|
11
|
-
from ptsandbox.models import
|
|
11
|
+
from ptsandbox.models import (
|
|
12
|
+
SandboxOptionsAdvanced,
|
|
13
|
+
SandboxUploadException,
|
|
14
|
+
SandboxWaitTimeoutException,
|
|
15
|
+
VNCMode,
|
|
16
|
+
)
|
|
12
17
|
from rich.markup import escape
|
|
13
|
-
from rich.progress import
|
|
18
|
+
from rich.progress import (
|
|
19
|
+
Progress,
|
|
20
|
+
SpinnerColumn,
|
|
21
|
+
Task,
|
|
22
|
+
TaskID,
|
|
23
|
+
TextColumn,
|
|
24
|
+
TimeElapsedColumn,
|
|
25
|
+
)
|
|
14
26
|
|
|
15
27
|
from sandbox_cli.console import console
|
|
16
28
|
from sandbox_cli.internal.config import VMImage, settings
|
|
@@ -64,6 +76,13 @@ async def _get_compiled_rules(progress: Progress, rules_dir: Path | None, is_loc
|
|
|
64
76
|
return result
|
|
65
77
|
|
|
66
78
|
|
|
79
|
+
def get_elapsed_time(task: Task) -> str:
|
|
80
|
+
hours = int(task.elapsed) // 3600
|
|
81
|
+
minutes = (int(task.elapsed) % 3600) // 60
|
|
82
|
+
seconds = int(task.elapsed) % 60
|
|
83
|
+
return f"[yellow]{hours}:{minutes:02d}:{seconds:02d}[/]"
|
|
84
|
+
|
|
85
|
+
|
|
67
86
|
async def _prepare_sandbox_new_scan(
|
|
68
87
|
progress: Progress,
|
|
69
88
|
scan_images: set[VMImage | str],
|
|
@@ -133,7 +152,7 @@ async def _prepare_sandbox_new_scan(
|
|
|
133
152
|
)
|
|
134
153
|
|
|
135
154
|
# some enabled options by default
|
|
136
|
-
#
|
|
155
|
+
# all debug options available in library
|
|
137
156
|
sandbox_options.debug_options["save_debug_files"] = True
|
|
138
157
|
sandbox_options.debug_options["extract_crashdumps"] = True
|
|
139
158
|
|
|
@@ -241,6 +260,7 @@ async def scan_internal_advanced(
|
|
|
241
260
|
|
|
242
261
|
async with sandbox_sem:
|
|
243
262
|
task_id = progress.add_task(description="Creating task", idx=idx, image=formatted_image, url="...")
|
|
263
|
+
task = progress.tasks[task_id]
|
|
244
264
|
|
|
245
265
|
wait_time = sandbox_options.analysis_duration * 4 + (300 if sandbox_options.analysis_duration < 80 else 120)
|
|
246
266
|
|
|
@@ -261,7 +281,7 @@ async def scan_internal_advanced(
|
|
|
261
281
|
progress.remove_task(task_id)
|
|
262
282
|
return
|
|
263
283
|
except aiohttp.client_exceptions.ClientResponseError as e:
|
|
264
|
-
console.error(f"{image_string} • [yellow]{file_path.name}[/] • {e}")
|
|
284
|
+
console.error(f"{image_string} • [yellow]{file_path.name}[/] • {e} • {get_elapsed_time(task)}")
|
|
265
285
|
progress.remove_task(task_id)
|
|
266
286
|
return
|
|
267
287
|
|
|
@@ -276,8 +296,13 @@ async def scan_internal_advanced(
|
|
|
276
296
|
description=f"Waiting [yellow]{file_path.name}[/]",
|
|
277
297
|
url=formatted_link,
|
|
278
298
|
)
|
|
279
|
-
|
|
280
|
-
|
|
299
|
+
try:
|
|
300
|
+
if not (awaited_report := await sandbox.wait_for_report(scan_result, wait_time)):
|
|
301
|
+
console.error(f"{final_output} • scan failed • {get_elapsed_time(task)}")
|
|
302
|
+
progress.remove_task(task_id)
|
|
303
|
+
return
|
|
304
|
+
except SandboxWaitTimeoutException:
|
|
305
|
+
console.error(f"{final_output} • got timeout while waiting • {get_elapsed_time(task)}")
|
|
281
306
|
progress.remove_task(task_id)
|
|
282
307
|
return
|
|
283
308
|
|
|
@@ -287,32 +312,37 @@ async def scan_internal_advanced(
|
|
|
287
312
|
(out_dir / settings.report_name).write_text(scan_result.model_dump_json(indent=4), encoding="utf-8")
|
|
288
313
|
|
|
289
314
|
if not (long_report := scan_result.get_long_report()):
|
|
290
|
-
console.error(f"{final_output} • full report not available")
|
|
315
|
+
console.error(f"{final_output} • full report not available • {get_elapsed_time(task)}")
|
|
291
316
|
progress.remove_task(task_id)
|
|
292
317
|
return
|
|
293
318
|
|
|
294
319
|
progress.update(task_id=task_id, description="Downloading results...")
|
|
295
320
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
321
|
+
try:
|
|
322
|
+
await download(
|
|
323
|
+
long_report,
|
|
324
|
+
sandbox,
|
|
325
|
+
out_dir,
|
|
326
|
+
all=all,
|
|
327
|
+
artifacts=artifacts,
|
|
328
|
+
crashdumps=crashdumps,
|
|
329
|
+
debug=debug,
|
|
330
|
+
decompress=decompress,
|
|
331
|
+
files=download_files,
|
|
332
|
+
logs=True, # by default download logs
|
|
333
|
+
procdumps=procdumps,
|
|
334
|
+
progress=progress,
|
|
335
|
+
video=True, # by default download video
|
|
336
|
+
idx=idx,
|
|
337
|
+
image=formatted_image,
|
|
338
|
+
link=formatted_link,
|
|
339
|
+
)
|
|
340
|
+
except aiohttp.SocketTimeoutError:
|
|
341
|
+
console.error(f"{final_output} • got timeout while downloading results • {get_elapsed_time(task)}")
|
|
342
|
+
progress.remove_task(task_id)
|
|
343
|
+
return
|
|
314
344
|
|
|
315
|
-
console.done(final_output)
|
|
345
|
+
console.done(f"{final_output} • {get_elapsed_time(task)}")
|
|
316
346
|
|
|
317
347
|
progress.remove_task(task_id)
|
|
318
348
|
|
|
@@ -378,3 +408,6 @@ async def scan_internal_advanced(
|
|
|
378
408
|
|
|
379
409
|
await asyncio.gather(*tasks)
|
|
380
410
|
await sandbox.api.session.close()
|
|
411
|
+
|
|
412
|
+
# clear last line
|
|
413
|
+
sys.stdout.write("\033[F\033[K")
|
|
@@ -13,6 +13,7 @@ from ptsandbox.models import (
|
|
|
13
13
|
SandboxBaseScanTaskRequest,
|
|
14
14
|
SandboxKey,
|
|
15
15
|
SandboxUploadException,
|
|
16
|
+
SandboxWaitTimeoutException,
|
|
16
17
|
)
|
|
17
18
|
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, TimeElapsedColumn
|
|
18
19
|
|
|
@@ -157,8 +158,13 @@ async def rescan_internal(
|
|
|
157
158
|
description=f"Waiting for full report for [yellow]{trace.name}[/]",
|
|
158
159
|
url=formatted_link,
|
|
159
160
|
)
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
try:
|
|
162
|
+
if not (awaited_report := await sandbox.wait_for_report(rescan_result, timeout)):
|
|
163
|
+
console.error(f"Rescan failed for [yellow]{trace.name}[/] • {formatted_link} • {rescan_result}")
|
|
164
|
+
progress.remove_task(task_id)
|
|
165
|
+
return
|
|
166
|
+
except SandboxWaitTimeoutException:
|
|
167
|
+
console.error(f"{final_output} • got timeout while waiting")
|
|
162
168
|
progress.remove_task(task_id)
|
|
163
169
|
return
|
|
164
170
|
|
|
@@ -80,17 +80,24 @@ class Unpack:
|
|
|
80
80
|
def run(self) -> None:
|
|
81
81
|
if Path(self.trace / "drakvuf-trace.log.gz").exists():
|
|
82
82
|
self.logs["drakvuf-trace"] = Path(self.trace / "drakvuf-trace.log.gz")
|
|
83
|
-
|
|
83
|
+
elif Path(self.trace / "drakvuf-trace.log.zst").exists():
|
|
84
84
|
self.logs["drakvuf-trace"] = Path(self.trace / "drakvuf-trace.log.zst")
|
|
85
85
|
|
|
86
86
|
self._extract_logs()
|
|
87
87
|
self._create_dirs()
|
|
88
88
|
self._move_files()
|
|
89
89
|
|
|
90
|
-
#
|
|
90
|
+
# run plugins
|
|
91
91
|
for plugin in self.plugins:
|
|
92
92
|
plugin.run()
|
|
93
93
|
|
|
94
|
-
#
|
|
94
|
+
# remove files
|
|
95
95
|
for log in self.logs.values():
|
|
96
|
+
# drakvuf trace not found
|
|
97
|
+
if log == Path(""):
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
if not log.exists():
|
|
101
|
+
continue
|
|
102
|
+
|
|
96
103
|
log.unlink(missing_ok=True)
|
|
@@ -3,7 +3,6 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
import orjson
|
|
5
5
|
|
|
6
|
-
from sandbox_cli.console import console
|
|
7
6
|
from sandbox_cli.models.detections import DetectionType
|
|
8
7
|
from sandbox_cli.utils.unpack.plugins.abc import BasePlugin
|
|
9
8
|
|
|
@@ -13,7 +12,6 @@ class CorrelatedRules(BasePlugin):
|
|
|
13
12
|
base_path = self.trace / "correlated"
|
|
14
13
|
file = Path(base_path / "events-correlated.log")
|
|
15
14
|
if not file.exists():
|
|
16
|
-
console.warning(f"{file} not exist")
|
|
17
15
|
return
|
|
18
16
|
|
|
19
17
|
with open(file, errors="ignore", encoding="utf-8") as fd:
|
{sandbox_cli-0.2.37 → sandbox_cli-0.2.39}/sandbox_cli/utils/unpack/plugins/sort_by_plugins.py
RENAMED
|
@@ -3,7 +3,6 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
import orjson
|
|
5
5
|
|
|
6
|
-
from sandbox_cli.console import console
|
|
7
6
|
from sandbox_cli.utils.unpack.plugins.abc import BasePlugin
|
|
8
7
|
|
|
9
8
|
|
|
@@ -12,7 +11,6 @@ class SortByPlugins(BasePlugin):
|
|
|
12
11
|
base_path = self.trace / "normalized"
|
|
13
12
|
file = Path(base_path / "events-normalized.log")
|
|
14
13
|
if not file.exists():
|
|
15
|
-
console.warning(f"{file} not exist")
|
|
16
14
|
return
|
|
17
15
|
|
|
18
16
|
with open(file, errors="ignore", encoding="utf-8") as fd:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|