dissect.target 3.20.dev6__py3-none-any.whl → 3.20.dev8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -144,7 +144,6 @@ EmptyRecord = RecordDescriptor(
144
144
  )
145
145
 
146
146
  COMMON_INTERFACE_ELEMENTS = [
147
- ("string", "source"),
148
147
  ("string", "name"),
149
148
  ("string", "type"),
150
149
  ("boolean", "enabled"),
@@ -152,6 +151,7 @@ COMMON_INTERFACE_ELEMENTS = [
152
151
  ("net.ipaddress[]", "dns"),
153
152
  ("net.ipaddress[]", "ip"),
154
153
  ("net.ipaddress[]", "gateway"),
154
+ ("string", "source"),
155
155
  ]
156
156
 
157
157
 
@@ -4,7 +4,7 @@ import json
4
4
  import logging
5
5
  import re
6
6
  from pathlib import Path
7
- from typing import Iterator, Optional
7
+ from typing import Iterator
8
8
 
9
9
  from dissect.cstruct import cstruct
10
10
  from dissect.util import ts
@@ -128,12 +128,17 @@ class DockerPlugin(Plugin):
128
128
  for data_root in self.installs:
129
129
  images_path = data_root.joinpath("image/overlay2/repositories.json")
130
130
 
131
- if images_path.exists():
132
- repositories = json.loads(images_path.read_text()).get("Repositories")
133
- else:
131
+ if not images_path.exists():
134
132
  self.target.log.debug("No docker images found, file %s does not exist.", images_path)
135
133
  continue
136
134
 
135
+ try:
136
+ repositories = json.loads(images_path.read_text()).get("Repositories", {})
137
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
138
+ self.target.log.warning("Unable to parse JSON in: %s", images_path)
139
+ self.target.log.debug("", exc_info=e)
140
+ continue
141
+
137
142
  for name, tags in repositories.items():
138
143
  for tag, hash in tags.items():
139
144
  image_metadata_path = data_root.joinpath(
@@ -142,8 +147,12 @@ class DockerPlugin(Plugin):
142
147
  created = None
143
148
 
144
149
  if image_metadata_path.exists():
145
- image_metadata = json.loads(image_metadata_path.read_text())
146
- created = convert_timestamp(image_metadata.get("created"))
150
+ try:
151
+ image_metadata = json.loads(image_metadata_path.read_text())
152
+ created = convert_timestamp(image_metadata.get("created"))
153
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
154
+ self.target.log.warning("Unable to parse JSON in: %s", image_metadata_path)
155
+ self.target.log.debug("", exc_info=e)
147
156
 
148
157
  yield DockerImageRecord(
149
158
  name=name,
@@ -160,47 +169,51 @@ class DockerPlugin(Plugin):
160
169
 
161
170
  for data_root in self.installs:
162
171
  for config_path in data_root.joinpath("containers").glob("**/config.v2.json"):
163
- config = json.loads(config_path.read_text())
172
+ try:
173
+ config = json.loads(config_path.read_text())
174
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
175
+ self.target.log.warning("Unable to parse JSON in file: %s", config_path)
176
+ self.target.log.debug("", exc_info=e)
177
+ continue
178
+
164
179
  container_id = config.get("ID")
165
180
 
166
181
  # determine state
167
- running = config.get("State").get("Running")
182
+ running = config.get("State", {}).get("Running")
168
183
  if running:
169
- ports = config.get("NetworkSettings").get("Ports", {})
170
- pid = config.get("Pid")
171
- else:
172
- ports = config.get("Config").get("ExposedPorts", {})
173
- pid = None
184
+ ports = config.get("NetworkSettings", {}).get("Ports", {})
185
+
186
+ if not running or not ports:
187
+ ports = config.get("Config", {}).get("ExposedPorts", {})
174
188
 
175
189
  # parse volumes
176
190
  volumes = []
177
- if mount_points := config.get("MountPoints"):
178
- for mp in mount_points:
179
- mount_point = mount_points[mp]
191
+ if mount_points := config.get("MountPoints", {}):
192
+ for mount_point in mount_points.values():
180
193
  volumes.append(f"{mount_point.get('Source')}:{mount_point.get('Destination')}")
181
194
 
182
195
  # determine mount point
183
196
  mount_path = None
184
- if config.get("Driver") == "overlay2":
197
+ if container_id and config.get("Driver") == "overlay2":
185
198
  mount_path = data_root.joinpath("image/overlay2/layerdb/mounts", container_id)
186
199
  if not mount_path.exists():
187
- self.target.log.warning("Overlay2 mount path for container %s does not exist!", container_id)
200
+ self.target.log.warning("Overlay2 mount path does not exist for container: %s", container_id)
188
201
 
189
202
  else:
190
- self.target.log.warning("Encountered unsupported container filesystem %s", config.get("Driver"))
203
+ self.target.log.warning("Encountered unsupported container filesystem: %s", config.get("Driver"))
191
204
 
192
205
  yield DockerContainerRecord(
193
206
  container_id=container_id,
194
- image=config.get("Config").get("Image"),
195
- image_id=config.get("Image").split(":")[-1],
196
- command=config.get("Config").get("Cmd"),
207
+ image=config.get("Config", {}).get("Image"),
208
+ image_id=config.get("Image", "").split(":")[-1],
209
+ command=f"{config.get('Path', '')} {' '.join(config.get('Args', []))}".strip(),
197
210
  created=convert_timestamp(config.get("Created")),
198
211
  running=running,
199
- pid=pid,
200
- started=convert_timestamp(config.get("State").get("StartedAt")),
201
- finished=convert_timestamp(config.get("State").get("FinishedAt")),
212
+ pid=config.get("State", {}).get("Pid"),
213
+ started=convert_timestamp(config.get("State", {}).get("StartedAt")),
214
+ finished=convert_timestamp(config.get("State", {}).get("FinishedAt")),
202
215
  ports=convert_ports(ports),
203
- names=config.get("Name").replace("/", "", 1),
216
+ names=config.get("Name", "").replace("/", "", 1),
204
217
  volumes=volumes,
205
218
  mount_path=mount_path,
206
219
  config_path=config_path,
@@ -288,19 +301,19 @@ class DockerPlugin(Plugin):
288
301
  for line in open_decompress(path, "rt"):
289
302
  try:
290
303
  entry = json.loads(line)
291
- except json.JSONDecodeError as e:
292
- self.target.log.warning("Could not decode JSON line in file %s", path)
304
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
305
+ self.target.log.warning("Could not decode JSON line in file: %s", path)
293
306
  self.target.log.debug("", exc_info=e)
294
307
  continue
295
308
  yield entry
296
309
 
297
310
 
298
- def get_data_path(path: Path) -> Optional[str]:
311
+ def get_data_path(path: Path) -> str | None:
299
312
  """Returns the configured Docker daemon data-root path."""
300
313
  try:
301
314
  config = json.loads(path.open("rt").read())
302
- except json.JSONDecodeError as e:
303
- log.warning("Could not read JSON file '%s'", path)
315
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
316
+ log.warning("Could not read JSON file: %s", path)
304
317
  log.debug(exc_info=e)
305
318
 
306
319
  return config.get("data-root")
@@ -341,7 +354,7 @@ def find_installs(target: Target) -> Iterator[Path]:
341
354
  yield data_root_path
342
355
 
343
356
 
344
- def convert_timestamp(timestamp: str) -> str:
357
+ def convert_timestamp(timestamp: str | None) -> str:
345
358
  """Docker sometimes uses (unpadded) 9 digit nanosecond precision
346
359
  in their timestamp logs, eg. "2022-12-19T13:37:00.123456789Z".
347
360
 
@@ -350,6 +363,9 @@ def convert_timestamp(timestamp: str) -> str:
350
363
  compatbility with the 6 digit %f microsecond directive.
351
364
  """
352
365
 
366
+ if not timestamp:
367
+ return
368
+
353
369
  timestamp_nanoseconds_plus_postfix = timestamp[19:]
354
370
  match = RE_DOCKER_NS.match(timestamp_nanoseconds_plus_postfix)
355
371
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.20.dev6
3
+ Version: 3.20.dev8
4
4
  Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -61,7 +61,7 @@ dissect/target/helpers/mui.py,sha256=i-7XoHbu4WO2fYapK9yGAMW04rFlgRispknc1KQIS5Q
61
61
  dissect/target/helpers/network_managers.py,sha256=ByBSe2K3c8hgQC6dokcf-hHdmPcD8PmrOj0xs1C3yhs,25743
62
62
  dissect/target/helpers/polypath.py,sha256=h8p7m_OCNiQljGwoZh5Aflr9H2ot6CZr6WKq1OSw58o,2175
63
63
  dissect/target/helpers/protobuf.py,sha256=b4DsnqrRLrefcDjx7rQno-_LBcwtJXxuKf5RdOegzfE,1537
64
- dissect/target/helpers/record.py,sha256=euNDDZi29fo8ENN1gsPycB38OMn35clLM9_K-srZ5E0,5852
64
+ dissect/target/helpers/record.py,sha256=vbsZBUQ5sxsWGaGUJk2yHV5miXvK9HfZgVarM5Cmqto,5852
65
65
  dissect/target/helpers/record_modifier.py,sha256=O_Jj7zOi891HIyAYjxxe6LFPYETHdMa5lNjo4NA_T_w,3969
66
66
  dissect/target/helpers/regutil.py,sha256=kX-sSZbW8Qkg29Dn_9zYbaQrwLumrr4Y8zJ1EhHXIAM,27337
67
67
  dissect/target/helpers/shell_application_ids.py,sha256=hYxrP-YtHK7ZM0ectJFHfoMB8QUXLbYNKmKXMWLZRlA,38132
@@ -127,7 +127,7 @@ dissect/target/plugins/apps/browser/edge.py,sha256=tuuIbm4s8nNstA6nIOEfU0LG0jt20
127
127
  dissect/target/plugins/apps/browser/firefox.py,sha256=mZBBagFfIdiz9kUyK4Hi989I4g3CWrClBbmpaGMRKxg,32472
128
128
  dissect/target/plugins/apps/browser/iexplore.py,sha256=g_xw0toaiyjevxO8g9XPCOqc-CXZp39FVquRhPFGdTE,8801
129
129
  dissect/target/plugins/apps/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- dissect/target/plugins/apps/container/docker.py,sha256=KxQRbKGgxkf3YFBMa7fjeJ7qo8qjFys7zEmfQhDTnLw,15305
130
+ dissect/target/plugins/apps/container/docker.py,sha256=LTsZplaECSfO1Ysp_Y-9WsnNocsreu_iHO8fbSif3g0,16221
131
131
  dissect/target/plugins/apps/remoteaccess/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  dissect/target/plugins/apps/remoteaccess/anydesk.py,sha256=IdijK3F6ppaB_IgKL-xDljlEbb8l9S2U0xSWKqK9xRs,4294
133
133
  dissect/target/plugins/apps/remoteaccess/remoteaccess.py,sha256=DWXkRDVUpFr1icK2fYwSXdZD204Xz0yRuO7rcJOwIwc,825
@@ -363,10 +363,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
363
363
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
364
364
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
365
365
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
366
- dissect.target-3.20.dev6.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
367
- dissect.target-3.20.dev6.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
368
- dissect.target-3.20.dev6.dist-info/METADATA,sha256=fpn-GHvIaUQ8kWFx0kTIwF9A0-q43fdFymwUWjX-AXQ,12896
369
- dissect.target-3.20.dev6.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
370
- dissect.target-3.20.dev6.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
371
- dissect.target-3.20.dev6.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
372
- dissect.target-3.20.dev6.dist-info/RECORD,,
366
+ dissect.target-3.20.dev8.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
367
+ dissect.target-3.20.dev8.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
368
+ dissect.target-3.20.dev8.dist-info/METADATA,sha256=VtQsgGmXH9A74YcDFwgv69F90Mk9mrD0-VQTWRKvFQU,12896
369
+ dissect.target-3.20.dev8.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
370
+ dissect.target-3.20.dev8.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
371
+ dissect.target-3.20.dev8.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
372
+ dissect.target-3.20.dev8.dist-info/RECORD,,