dissect.target 3.16.dev43__py3-none-any.whl → 3.16.dev44__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,