sandbox-cli 0.2.26__tar.gz → 0.2.28__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.
Files changed (36) hide show
  1. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/.gitignore +1 -0
  2. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/PKG-INFO +4 -5
  3. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/README.md +2 -3
  4. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/pyproject.toml +2 -2
  5. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/scanner/__init__.py +21 -4
  6. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/console.py +0 -1
  7. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/internal/config.py +7 -0
  8. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/downloader/__init__.py +12 -10
  9. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/scanner/rescan.py +1 -1
  10. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/LICENSE +0 -0
  11. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/NOTICE +0 -0
  12. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/__main__.py +0 -0
  13. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/__init__.py +0 -0
  14. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/downloader.py +0 -0
  15. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/images.py +0 -0
  16. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/reporter.py +0 -0
  17. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/rules/__init__.py +0 -0
  18. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/cli/unpack.py +0 -0
  19. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/internal/__init__.py +0 -0
  20. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/internal/helpers.py +0 -0
  21. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/models/__init__.py +0 -0
  22. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/models/detections.py +0 -0
  23. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/__init__.py +0 -0
  24. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/compiler/__init__.py +0 -0
  25. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/compiler/abc.py +0 -0
  26. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/compiler/docker.py +0 -0
  27. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/compiler/ssh.py +0 -0
  28. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/extractors.py +0 -0
  29. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/merge_dll_hooks.py +0 -0
  30. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/scanner/__init__.py +0 -0
  31. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/scanner/advanced.py +0 -0
  32. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/unpack/__init__.py +0 -0
  33. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/unpack/plugins/__init__.py +0 -0
  34. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/unpack/plugins/abc.py +0 -0
  35. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/unpack/plugins/correlation.py +0 -0
  36. {sandbox_cli-0.2.26 → sandbox_cli-0.2.28}/sandbox_cli/utils/unpack/plugins/sort_by_plugins.py +0 -0
@@ -127,6 +127,7 @@ venv/
127
127
  ENV/
128
128
  env.bak/
129
129
  venv.bak/
130
+ .nix-venv
130
131
 
131
132
  # Spyder project settings
132
133
  .spyderproject
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sandbox-cli
3
- Version: 0.2.26
3
+ Version: 0.2.28
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
@@ -16,7 +16,7 @@ Requires-Dist: asyncssh>=2.19.0
16
16
  Requires-Dist: cryptography>=44.0.0
17
17
  Requires-Dist: cyclopts>=3.9.0
18
18
  Requires-Dist: docker>=7.1.0
19
- Requires-Dist: ptsandbox
19
+ Requires-Dist: ptsandbox>=5.0.0
20
20
  Requires-Dist: pyzipper>=0.3.6
21
21
  Requires-Dist: rich>=13.9.4
22
22
  Requires-Dist: zstandard>=0.23.0
@@ -55,9 +55,8 @@ pip install sandbox-cli
55
55
 
56
56
  NixOS:
57
57
 
58
- ```
59
- Add inputs.sandbox-cli.overlays.default to your nixpkgs overlay
60
- TBA: ...
58
+ ```sh
59
+ nix shell 'github:Security-Experts-Community/sandbox-cli'
61
60
  ```
62
61
 
63
62
  ### Config
@@ -31,9 +31,8 @@ pip install sandbox-cli
31
31
 
32
32
  NixOS:
33
33
 
34
- ```
35
- Add inputs.sandbox-cli.overlays.default to your nixpkgs overlay
36
- TBA: ...
34
+ ```sh
35
+ nix shell 'github:Security-Experts-Community/sandbox-cli'
37
36
  ```
38
37
 
39
38
  ### Config
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sandbox-cli"
3
- version = "0.2.26"
3
+ version = "0.2.28"
4
4
  description = "Command line tool for interaction with sandboxes"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -13,7 +13,7 @@ dependencies = [
13
13
  "cryptography>=44.0.0",
14
14
  "cyclopts>=3.9.0",
15
15
  "docker>=7.1.0",
16
- "ptsandbox",
16
+ "ptsandbox>=5.0.0",
17
17
  "pyzipper>=0.3.6",
18
18
  "rich>=13.9.4",
19
19
  "zstandard>=0.23.0",
@@ -7,7 +7,7 @@ from cyclopts import App, Parameter, Token, validators
7
7
  from ptsandbox.models import VNCMode
8
8
 
9
9
  from sandbox_cli.console import console
10
- from sandbox_cli.internal.config import VMImage, settings
10
+ from sandbox_cli.internal.config import Platform, VMImage, settings
11
11
  from sandbox_cli.internal.helpers import validate_key
12
12
  from sandbox_cli.utils.scanner import scan_internal
13
13
  from sandbox_cli.utils.scanner.advanced import scan_internal_advanced
@@ -34,6 +34,20 @@ def image_converter(_: Any, tokens: Sequence[Token]) -> set[VMImage | str]:
34
34
  return images
35
35
 
36
36
 
37
+ def rules_path_resolver(_: Any, tokens: Sequence[Token]) -> Path | None:
38
+ path: Path | None = None
39
+ for token in tokens:
40
+ if token.value in {Platform.LINUX, Platform.WINDOWS}:
41
+ if not settings.rules_path:
42
+ console.error("You can't use aliases without specifying the path in the config")
43
+ sys.exit(1)
44
+
45
+ path = settings.rules_path / token.value
46
+ break
47
+
48
+ return path
49
+
50
+
37
51
  @scanner.command(name="re-scan")
38
52
  async def re_scan(
39
53
  traces: Annotated[
@@ -48,7 +62,8 @@ async def re_scan(
48
62
  Path | None,
49
63
  Parameter(
50
64
  name=["--rules", "-r"],
51
- help="The path to the folder with the rules or the default rules from the sandbox",
65
+ help="The path to the folder with the rules or the default rules from the sandbox or platform alias (windows, linux)",
66
+ converter=rules_path_resolver,
52
67
  ),
53
68
  ] = None,
54
69
  out_dir: Annotated[
@@ -136,7 +151,8 @@ async def scan(
136
151
  Path | None,
137
152
  Parameter(
138
153
  name=["--rules", "-r"],
139
- help="The path to the folder with the rules or the default rules from the sandbox",
154
+ help="The path to the folder with the rules or the default rules from the sandbox or platform alias (windows, linux)",
155
+ converter=rules_path_resolver,
140
156
  ),
141
157
  ] = None,
142
158
  out_dir: Annotated[
@@ -372,7 +388,8 @@ async def scan_new(
372
388
  Path | None,
373
389
  Parameter(
374
390
  name=["--rules", "-r"],
375
- help="The path to the folder with the rules or the default rules from the sandbox",
391
+ help="The path to the folder with the rules or the default rules from the sandbox or platform alias (windows, linux)",
392
+ converter=rules_path_resolver,
376
393
  ),
377
394
  ] = None,
378
395
  out_dir: Annotated[
@@ -21,4 +21,3 @@ class SandboxConsole(Console):
21
21
 
22
22
 
23
23
  console = SandboxConsole(color_system="auto", emoji=True)
24
- console = SandboxConsole(color_system="auto", emoji=True)
@@ -44,6 +44,11 @@ class VMImage(str, Enum):
44
44
  return str(self.value)
45
45
 
46
46
 
47
+ class Platform(str, Enum):
48
+ LINUX = "linux"
49
+ WINDOWS = "windows"
50
+
51
+
47
52
  class Settings(BaseModel):
48
53
  class Docker(BaseModel):
49
54
  username: str = ""
@@ -113,9 +118,11 @@ class Settings(BaseModel):
113
118
  passwords: list[str] = ["infected", "311138", "password", "12345678", "P@ssw0rd!"]
114
119
  docker: Docker = Docker()
115
120
  sandbox: list[Sandbox] = []
121
+ rules_path: Path | None = Field(default=None, alias="rules-path")
116
122
 
117
123
  def model_post_init(self, __context: Any) -> None:
118
124
  self.sandbox_keys = [x.sandbox_key for x in self.sandbox]
125
+ self.rules_path = Path(self.rules_path) if self.rules_path else None
119
126
 
120
127
 
121
128
  def load_config(path: Path) -> Settings:
@@ -25,6 +25,7 @@ semaphore = asyncio.Semaphore(value=12)
25
25
  async def _save_artifact(
26
26
  scan_id: UUID,
27
27
  sandbox: Sandbox,
28
+ out_dir: Path,
28
29
  path: Path,
29
30
  file_uri: str,
30
31
  decompress: bool = False,
@@ -38,7 +39,7 @@ async def _save_artifact(
38
39
  return
39
40
 
40
41
  # sanitize path
41
- path = Path(str(path).replace(" ", "_"))
42
+ path = out_dir / Path(str(path).replace(" ", "_"))
42
43
  task_id: TaskID = None # type: ignore
43
44
 
44
45
  async with semaphore:
@@ -100,11 +101,12 @@ async def download(
100
101
  ) -> None:
101
102
  tasks: list[Coroutine[Any, Any, None]] = []
102
103
 
103
- def add_task(path: Path, file_uri: str, decompress: bool = False) -> None:
104
+ def add_task(out_dir: Path, path: Path, file_uri: str, decompress: bool = False) -> None:
104
105
  tasks.append(
105
106
  _save_artifact(
106
107
  scan_id=report.scan_id,
107
108
  sandbox=sandbox,
109
+ out_dir=out_dir,
108
110
  path=path,
109
111
  file_uri=file_uri,
110
112
  progress=progress,
@@ -134,16 +136,16 @@ async def download(
134
136
  LogType.EVENT_RAW,
135
137
  LogType.NETWORK,
136
138
  }:
137
- add_task(out_dir / log.file_name, log.file_uri)
139
+ add_task(out_dir, log.file_name, log.file_uri)
138
140
 
139
141
  if (all or video) and log.type == LogType.SCREENSHOT:
140
- add_task(out_dir / log.file_name, log.file_uri)
142
+ add_task(out_dir, log.file_name, log.file_uri)
141
143
 
142
144
  if (all or crashdumps) and log.file_name in {"crashdump.bin", "crashdump.metadata"}:
143
- add_task(out_dir / "crashdumps" / log.file_name, log.file_uri)
145
+ add_task(out_dir / "crashdumps", log.file_name, log.file_uri)
144
146
 
145
147
  if (all or debug) and log.type in {LogType.DEBUG, LogType.GRAPH}:
146
- add_task(out_dir / "debug" / log.file_name, log.file_uri)
148
+ add_task(out_dir / "debug", log.file_name, log.file_uri)
147
149
 
148
150
  if artifacts or files or procdumps or all:
149
151
  if not sandbox_result.details:
@@ -161,14 +163,14 @@ async def download(
161
163
 
162
164
  if artifact.type == ArtifactType.FILE and (files or artifacts or all):
163
165
  add_task(
164
- out_dir / "artifacts" / artifact.file_info.file_path.removeprefix("/"),
166
+ out_dir / "artifacts",
167
+ artifact.file_info.file_path.removeprefix("/"),
165
168
  artifact.file_info.file_uri,
166
169
  )
167
170
  if artifact.type == ArtifactType.PROCESS_DUMP and (procdumps or artifacts or all):
168
171
  add_task(
169
- out_dir
170
- / "process_dump"
171
- / artifact.file_info.details.process_dump.process_name.removeprefix("/"), # type: ignore
172
+ out_dir / "process_dump",
173
+ artifact.file_info.details.process_dump.process_name.removeprefix("/"), # type: ignore
172
174
  artifact.file_info.file_uri,
173
175
  decompress=decompress,
174
176
  )
@@ -202,7 +202,7 @@ async def rescan_internal(
202
202
  drakvuf_trace = trace / "drakvuf-trace.log.zst"
203
203
  if not drakvuf_trace.exists():
204
204
  console.error(
205
- f"drakvuf-trace.log.gz or drakvuf-trace.log.zst doesn't exists in {trace.expanduser().resolve()}"
205
+ f"drakvuf-trace.log.gz or drakvuf-trace.log.zst doesn't exist in {trace.expanduser().resolve()}"
206
206
  )
207
207
  sys.exit(1)
208
208
 
File without changes
File without changes