sandbox-cli 0.2.36__tar.gz → 0.2.38__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.36 → sandbox_cli-0.2.38}/PKG-INFO +2 -1
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/pyproject.toml +10 -8
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/__init__.py +2 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/downloader.py +5 -6
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/rules/__init__.py +2 -2
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/downloader/__init__.py +0 -1
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/scanner/advanced.py +17 -4
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/scanner/rescan.py +8 -2
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/unpack/__init__.py +10 -3
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/unpack/plugins/correlation.py +0 -2
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/unpack/plugins/sort_by_plugins.py +0 -2
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/.gitignore +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/LICENSE +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/NOTICE +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/README.md +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/__main__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/images.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/reporter.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/scanner/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/cli/unpack.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/console.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/internal/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/internal/config.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/internal/helpers.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/models/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/models/detections.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/models/sandbox_arguments.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/compiler/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/compiler/abc.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/compiler/docker.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/compiler/ssh.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/extractors.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/merge_dll_hooks.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/scanner/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/sandbox_cli/utils/unpack/plugins/__init__.py +0 -0
- {sandbox_cli-0.2.36 → sandbox_cli-0.2.38}/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.38
|
|
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
|
|
@@ -13,6 +13,7 @@ License-File: NOTICE
|
|
|
13
13
|
Requires-Python: >=3.11
|
|
14
14
|
Requires-Dist: aiofiles>=24.1.0
|
|
15
15
|
Requires-Dist: asyncssh>=2.21.0
|
|
16
|
+
Requires-Dist: colorama>=0.4.6
|
|
16
17
|
Requires-Dist: cryptography>=45.0.4
|
|
17
18
|
Requires-Dist: cyclopts>=3.22.5
|
|
18
19
|
Requires-Dist: docker>=7.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sandbox-cli"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.38"
|
|
4
4
|
description = "Command line tool for interaction with sandboxes"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -10,6 +10,7 @@ authors = [{ name = "Alexey Kolesnikov" }]
|
|
|
10
10
|
dependencies = [
|
|
11
11
|
"aiofiles>=24.1.0",
|
|
12
12
|
"asyncssh>=2.21.0",
|
|
13
|
+
"colorama>=0.4.6",
|
|
13
14
|
"cryptography>=45.0.4",
|
|
14
15
|
"cyclopts>=3.22.5",
|
|
15
16
|
"docker>=7.1.0",
|
|
@@ -86,13 +87,14 @@ ignore_missing_imports = true
|
|
|
86
87
|
|
|
87
88
|
[tool.ruff]
|
|
88
89
|
lint.select = [
|
|
89
|
-
"E",
|
|
90
|
-
"W",
|
|
91
|
-
"F",
|
|
92
|
-
"I",
|
|
93
|
-
"B",
|
|
94
|
-
"C4",
|
|
95
|
-
"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
|
|
96
98
|
]
|
|
97
99
|
lint.ignore = [
|
|
98
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(),
|
|
@@ -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(
|
|
@@ -8,7 +8,12 @@ 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
18
|
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, TimeElapsedColumn
|
|
14
19
|
|
|
@@ -133,7 +138,7 @@ async def _prepare_sandbox_new_scan(
|
|
|
133
138
|
)
|
|
134
139
|
|
|
135
140
|
# some enabled options by default
|
|
136
|
-
#
|
|
141
|
+
# all debug options available in library
|
|
137
142
|
sandbox_options.debug_options["save_debug_files"] = True
|
|
138
143
|
sandbox_options.debug_options["extract_crashdumps"] = True
|
|
139
144
|
|
|
@@ -276,8 +281,13 @@ async def scan_internal_advanced(
|
|
|
276
281
|
description=f"Waiting [yellow]{file_path.name}[/]",
|
|
277
282
|
url=formatted_link,
|
|
278
283
|
)
|
|
279
|
-
|
|
280
|
-
|
|
284
|
+
try:
|
|
285
|
+
if not (awaited_report := await sandbox.wait_for_report(scan_result, wait_time)):
|
|
286
|
+
console.error(f"{final_output} • scan failed")
|
|
287
|
+
progress.remove_task(task_id)
|
|
288
|
+
return
|
|
289
|
+
except SandboxWaitTimeoutException:
|
|
290
|
+
console.error(f"{final_output} • got timeout while waiting")
|
|
281
291
|
progress.remove_task(task_id)
|
|
282
292
|
return
|
|
283
293
|
|
|
@@ -378,3 +388,6 @@ async def scan_internal_advanced(
|
|
|
378
388
|
|
|
379
389
|
await asyncio.gather(*tasks)
|
|
380
390
|
await sandbox.api.session.close()
|
|
391
|
+
|
|
392
|
+
# clear last line
|
|
393
|
+
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.36 → sandbox_cli-0.2.38}/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
|
|
File without changes
|
|
File without changes
|