dissect.target 3.16.dev43__py3-none-any.whl → 3.16.dev44__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.
@@ -17,6 +17,7 @@ from dissect.target.helpers.fsutil import open_decompress
17
17
  from dissect.target.helpers.record import TargetRecordDescriptor, UnixUserRecord
18
18
  from dissect.target.plugin import OperatingSystem, export
19
19
  from dissect.target.plugins.os.unix.linux._os import LinuxPlugin
20
+ from dissect.target.plugins.os.unix.linux.fortios._keys import KERNEL_KEY_MAP
20
21
  from dissect.target.target import Target
21
22
 
22
23
  try:
@@ -92,12 +93,14 @@ class FortiOSPlugin(LinuxPlugin):
92
93
  except ReadError:
93
94
  # The rootfs.gz file could be encrypted.
94
95
  try:
95
- rfs_fh = decrypt_rootfs(rootfs.open(), get_kernel_hash(sysvol))
96
+ kernel_hash = get_kernel_hash(sysvol)
97
+ key, iv = key_iv_for_kernel_hash(kernel_hash)
98
+ rfs_fh = decrypt_rootfs(rootfs.open(), key, iv)
96
99
  vfs = TarFilesystem(rfs_fh, tarinfo=cpio.CpioInfo)
97
100
  except RuntimeError:
98
101
  target.log.warning("Could not decrypt rootfs.gz. Missing `pycryptodome` dependency.")
99
102
  except ValueError as e:
100
- target.log.warning("Could not decrypt rootfs.gz. Unsupported kernel version.")
103
+ target.log.warning("Could not decrypt rootfs.gz. Unknown kernel hash (%s).", kernel_hash)
101
104
  target.log.debug("", exc_info=e)
102
105
  except ReadError as e:
103
106
  target.log.warning("Could not mount rootfs.gz. It could be corrupt.")
@@ -457,58 +460,60 @@ def decrypt_password(input: str) -> str:
457
460
  return "ENC:" + input
458
461
 
459
462
 
460
- def decrypt_rootfs(fh: BinaryIO, kernel_hash: str) -> BinaryIO:
461
- """Attempt to decrypt an encrypted ``rootfs.gz`` file.
463
+ def key_iv_for_kernel_hash(kernel_hash: str) -> tuple[bytes, bytes]:
464
+ """Return decryption key and IV for a specific sha256 kernel hash.
465
+
466
+ The decryption key and IV are used to decrypt the ``rootfs.gz`` file.
467
+
468
+ Args:
469
+ kernel_hash: SHA256 hash of the kernel file.
470
+
471
+ Returns:
472
+ Tuple with decryption key and IV.
473
+
474
+ Raises:
475
+ ValueError: When no decryption keys are available for the given kernel hash.
476
+ """
477
+
478
+ key = bytes.fromhex(KERNEL_KEY_MAP.get(kernel_hash, ""))
479
+ if len(key) == 32:
480
+ # FortiOS 7.4.x uses a KDF to derive the key and IV
481
+ return _kdf_7_4_x(key)
482
+ elif len(key) == 48:
483
+ # FortiOS 7.0.13 and 7.0.14 uses a static key and IV
484
+ return key[:32], key[32:]
485
+ raise ValueError(f"No known decryption keys for kernel hash: {kernel_hash}")
486
+
487
+
488
+ def decrypt_rootfs(fh: BinaryIO, key: bytes, iv: bytes) -> BinaryIO:
489
+ """Attempt to decrypt an encrypted ``rootfs.gz`` file with given key and IV.
462
490
 
463
491
  FortiOS releases as of 7.4.1 / 2023-08-31, have ChaCha20 encrypted ``rootfs.gz`` files.
464
492
  This function attempts to decrypt a ``rootfs.gz`` file using a static key and IV
465
493
  which can be found in the kernel.
466
494
 
467
- Currently supported versions (each release has a new key):
468
- - FortiGate VM 7.0.13
469
- - FortiGate VM 7.0.14
470
- - FortiGate VM 7.4.1
471
- - FortiGate VM 7.4.2
472
- - FortiGate VM 7.4.3
495
+ Known keys can be found in the ``_keys.py`` file.
473
496
 
474
497
  Resources:
475
498
  - https://docs.fortinet.com/document/fortimanager/7.4.2/release-notes/519207/special-notices
476
499
  - Reversing kernel (fgt_verifier_iv, fgt_verifier_decrypt, fgt_verifier_initrd)
500
+
501
+ Args:
502
+ fh: File-like object to the encrypted rootfs.gz file.
503
+ key: ChaCha20 key.
504
+ iv: ChaCha20 iv.
505
+
506
+ Returns:
507
+ File-like object to the decrypted rootfs.gz file.
508
+
509
+ Raises:
510
+ ValueError: When decryption failed.
511
+ RuntimeError: When PyCryptodome is not available.
477
512
  """
478
513
 
479
514
  if not HAS_PYCRYPTODOME:
480
515
  raise RuntimeError("PyCryptodome module not available")
481
516
 
482
- # SHA256 hashes of kernel files
483
- KERNEL_KEY_MAP = {
484
- # FortiGate VM 7.0.13
485
- "25cb2c8a419cde1f42d38fc6cbc95cf8b53db41096d0648015674d8220eba6bf": (
486
- bytes.fromhex("c87e13e1f7d21c1aca81dc13329c3a948d6e420d3a859f3958bd098747873d08"),
487
- bytes.fromhex("87486a24637e9a66f09ec182eee25594"),
488
- ),
489
- # FortiGate VM 7.0.14
490
- "67d4c913b1ceb7a62e2076ca835ebfdc67e65c7716fc604caa7552512f171197": (
491
- bytes.fromhex("9ba00c035bcaa97717d936f8268a973eb1dd64d19388153fad5f7849b8fdf0d8"),
492
- bytes.fromhex("9df4ba40dbddcf5ec9d2983681eb1940"),
493
- ),
494
- # FortiGate VM 7.4.1
495
- "a008b47327293e48502a121ee8709f243ad5da4e63d6f663c253db27bd01ea28": _kdf_7_4_x(
496
- "366486c0f2c6322ec23e4f33a98caa1b19d41c74bb4f25f6e8e2087b0655b30f"
497
- ),
498
- # FortiGate VM 7.4.2
499
- "c392cf83ab484e0b2419b2711b02cdc88a73db35634c10340037243394a586eb": _kdf_7_4_x(
500
- "480767be539de28ee773497fa731dd6368adc9946df61da8e1253fa402ba0302"
501
- ),
502
- # FortiGate VM 7.4.3
503
- "ba0450947e51844588b29bd302d2a1a3802f7718cf6840011c1b34f1c1f0bb89": _kdf_7_4_x(
504
- "4cf7a950b99cf29b0343e7ba6c609e49d9766f16c6d2f075f72ad400542f0765"
505
- ),
506
- }
507
-
508
- if not (key_data := KERNEL_KEY_MAP.get(kernel_hash)):
509
- raise ValueError("Failed to decrypt: Unknown kernel hash.")
510
-
511
- key, iv = key_data
512
517
  # First 8 bytes = counter, last 8 bytes = nonce
513
518
  # PyCryptodome interally divides this seek by 64 to get a (position, offset) tuple
514
519
  # We're interested in updating the position in the ChaCha20 internal state, so to make
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.16.dev43
3
+ Version: 3.16.dev44
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
@@ -223,7 +223,8 @@ dissect/target/plugins/os/unix/linux/debian/dpkg.py,sha256=DPBLQiHAF7ZS8IorRsGAi
223
223
  dissect/target/plugins/os/unix/linux/debian/vyos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
224
224
  dissect/target/plugins/os/unix/linux/debian/vyos/_os.py,sha256=q8qG2FLJhUbpjfwlNCmWAhFdTWMzSWUh7s7H8m4x7Fw,1741
225
225
  dissect/target/plugins/os/unix/linux/fortios/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
226
- dissect/target/plugins/os/unix/linux/fortios/_os.py,sha256=TK5Fcn0CORq-k_Cf3n5UvY1QHQFShry0HdgFALMEibc,19634
226
+ dissect/target/plugins/os/unix/linux/fortios/_keys.py,sha256=jDDHObfsUn9BGoIir9p4J_-rg9rI1rgoOfnL3R3lg4o,123358
227
+ dissect/target/plugins/os/unix/linux/fortios/_os.py,sha256=gFFzByku_3qpSrHpnqJv6xIbIe3V4iGXdUxxGD_-EFA,19435
227
228
  dissect/target/plugins/os/unix/linux/fortios/generic.py,sha256=tT4-lE0Z_DeDIN3zHrQbE8JB3cRJop1_TiEst-Au0bs,1230
228
229
  dissect/target/plugins/os/unix/linux/fortios/locale.py,sha256=VDdk60sqe2JTfftssO05C667-_BpI3kcqKOTVzO3ueU,5209
229
230
  dissect/target/plugins/os/unix/linux/redhat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -332,10 +333,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
332
333
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
333
334
  dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
334
335
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
335
- dissect.target-3.16.dev43.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
336
- dissect.target-3.16.dev43.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
337
- dissect.target-3.16.dev43.dist-info/METADATA,sha256=k_mmSMwlIKc86B11l-UAys9JHWtSfbicJtUob1FmEfE,11100
338
- dissect.target-3.16.dev43.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
339
- dissect.target-3.16.dev43.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
340
- dissect.target-3.16.dev43.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
341
- dissect.target-3.16.dev43.dist-info/RECORD,,
336
+ dissect.target-3.16.dev44.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
337
+ dissect.target-3.16.dev44.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
338
+ dissect.target-3.16.dev44.dist-info/METADATA,sha256=FVsQADibmaOBO3JcCbWI9r2XQ0uXQLKL-yeCztWemQM,11100
339
+ dissect.target-3.16.dev44.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
340
+ dissect.target-3.16.dev44.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
341
+ dissect.target-3.16.dev44.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
342
+ dissect.target-3.16.dev44.dist-info/RECORD,,