dissect.target 3.17.dev25__py3-none-any.whl → 3.17.dev26__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.
@@ -1,3 +1,4 @@
1
+ import base64
1
2
  import re
2
3
  from itertools import product
3
4
  from pathlib import Path
@@ -14,6 +15,7 @@ from dissect.target.plugins.apps.ssh.ssh import (
14
15
  PrivateKeyRecord,
15
16
  PublicKeyRecord,
16
17
  SSHPlugin,
18
+ calculate_fingerprints,
17
19
  )
18
20
 
19
21
 
@@ -143,12 +145,14 @@ class OpenSSHPlugin(SSHPlugin):
143
145
  continue
144
146
 
145
147
  key_type, public_key, comment = parse_ssh_public_key_file(file_path)
148
+ fingerprints = calculate_fingerprints(base64.b64decode(public_key))
146
149
 
147
150
  yield PublicKeyRecord(
148
151
  mtime_ts=file_path.stat().st_mtime,
149
152
  key_type=key_type,
150
153
  public_key=public_key,
151
154
  comment=comment,
155
+ fingerprint=fingerprints,
152
156
  path=file_path,
153
157
  _target=self.target,
154
158
  _user=user,
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from base64 import b64decode
2
3
  from datetime import datetime
3
4
  from pathlib import Path
4
5
  from typing import Iterator, Optional, Union
@@ -12,7 +13,11 @@ from dissect.target.helpers.fsutil import TargetPath, open_decompress
12
13
  from dissect.target.helpers.record import create_extended_descriptor
13
14
  from dissect.target.helpers.regutil import RegistryKey
14
15
  from dissect.target.plugin import export
15
- from dissect.target.plugins.apps.ssh.ssh import KnownHostRecord, SSHPlugin
16
+ from dissect.target.plugins.apps.ssh.ssh import (
17
+ KnownHostRecord,
18
+ SSHPlugin,
19
+ calculate_fingerprints,
20
+ )
16
21
  from dissect.target.plugins.general.users import UserDetails
17
22
 
18
23
  log = logging.getLogger(__name__)
@@ -96,12 +101,15 @@ class PuTTYPlugin(SSHPlugin):
96
101
  key_type, host = entry.name.split("@")
97
102
  port, host = host.split(":")
98
103
 
104
+ public_key, fingerprints = construct_public_key(key_type, entry.value)
105
+
99
106
  yield KnownHostRecord(
100
107
  mtime_ts=ssh_host_keys.ts,
101
108
  host=host,
102
109
  port=port,
103
110
  key_type=key_type,
104
- public_key=construct_public_key(key_type, entry.value),
111
+ public_key=public_key,
112
+ fingerprint=fingerprints,
105
113
  comment="",
106
114
  marker=None,
107
115
  path=windows_path(ssh_host_keys.path),
@@ -121,12 +129,15 @@ class PuTTYPlugin(SSHPlugin):
121
129
  key_type, host = parts[0].split("@")
122
130
  port, host = host.split(":")
123
131
 
132
+ public_key, fingerprints = construct_public_key(key_type, parts[1])
133
+
124
134
  yield KnownHostRecord(
125
135
  mtime_ts=ts,
126
136
  host=host,
127
137
  port=port,
128
138
  key_type=key_type,
129
- public_key=construct_public_key(key_type, parts[1]),
139
+ public_key=public_key,
140
+ fingerprint=fingerprints,
130
141
  comment="",
131
142
  marker=None,
132
143
  path=posix_path(ssh_host_keys_path),
@@ -197,8 +208,8 @@ def parse_host_user(host: str, user: str) -> tuple[str, str]:
197
208
  return host, user
198
209
 
199
210
 
200
- def construct_public_key(key_type: str, iv: str) -> str:
201
- """Returns OpenSSH format public key calculated from PuTTY SshHostKeys format.
211
+ def construct_public_key(key_type: str, iv: str) -> tuple[str, tuple[str, str, str]]:
212
+ """Returns OpenSSH format public key calculated from PuTTY SshHostKeys format and set of fingerprints.
202
213
 
203
214
  PuTTY stores raw public key components instead of OpenSSH-formatted public keys
204
215
  or fingerprints. With RSA public keys the exponent and modulus are stored.
@@ -206,9 +217,7 @@ def construct_public_key(key_type: str, iv: str) -> str:
206
217
 
207
218
  Currently supports ``ssh-ed25519``, ``ecdsa-sha2-nistp256`` and ``rsa2`` key types.
208
219
 
209
- NOTE:
210
- - Sha256 fingerprints of the reconstructed public keys are currently not generated.
211
- - More key types could be supported in the future.
220
+ NOTE: More key types could be supported in the future.
212
221
 
213
222
  Resources:
214
223
  - https://github.com/github/putty/blob/master/contrib/kh2reg.py
@@ -217,20 +226,33 @@ def construct_public_key(key_type: str, iv: str) -> str:
217
226
  - https://github.com/mkorthof/reg2kh
218
227
  """
219
228
 
229
+ if not isinstance(key_type, str) or not isinstance(iv, str):
230
+ raise ValueError("Invalid key_type or iv")
231
+
232
+ key = None
233
+
220
234
  if key_type == "ssh-ed25519":
221
235
  x, y = iv.split(",")
222
236
  key = ECC.construct(curve="ed25519", point_x=int(x, 16), point_y=int(y, 16))
223
- return key.public_key().export_key(format="OpenSSH").split()[-1]
224
237
 
225
238
  if key_type == "ecdsa-sha2-nistp256":
226
239
  _, x, y = iv.split(",")
227
240
  key = ECC.construct(curve="NIST P-256", point_x=int(x, 16), point_y=int(y, 16))
228
- return key.public_key().export_key(format="OpenSSH").split()[-1]
229
241
 
230
242
  if key_type == "rsa2":
231
243
  exponent, modulus = iv.split(",")
232
244
  key = RSA.construct((int(modulus, 16), int(exponent, 16)))
233
- return key.public_key().export_key(format="OpenSSH").decode("utf-8").split()[-1]
234
245
 
235
- log.warning("Could not reconstruct public key: type %s not implemented.", key_type)
236
- return iv
246
+ if key is None:
247
+ log.warning("Could not reconstruct public key: type %s not implemented", key_type)
248
+ return iv, (None, None, None)
249
+
250
+ openssh_public_key = key.public_key().export_key(format="OpenSSH")
251
+
252
+ if isinstance(openssh_public_key, bytes):
253
+ # RSA's export_key() returns bytes
254
+ openssh_public_key = openssh_public_key.decode()
255
+
256
+ key_part = openssh_public_key.split()[-1]
257
+ fingerprints = calculate_fingerprints(b64decode(key_part))
258
+ return key_part, fingerprints
@@ -1,3 +1,6 @@
1
+ import base64
2
+ from hashlib import md5, sha1, sha256
3
+
1
4
  from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
2
5
  from dissect.target.helpers.record import create_extended_descriptor
3
6
  from dissect.target.plugin import NamespacePlugin
@@ -29,6 +32,7 @@ KnownHostRecord = OpenSSHUserRecordDescriptor(
29
32
  ("varint", "port"),
30
33
  ("string", "public_key"),
31
34
  ("string", "marker"),
35
+ ("digest", "fingerprint"),
32
36
  ],
33
37
  )
34
38
 
@@ -50,9 +54,45 @@ PublicKeyRecord = OpenSSHUserRecordDescriptor(
50
54
  ("datetime", "mtime_ts"),
51
55
  *COMMON_ELLEMENTS,
52
56
  ("string", "public_key"),
57
+ ("digest", "fingerprint"),
53
58
  ],
54
59
  )
55
60
 
56
61
 
57
62
  class SSHPlugin(NamespacePlugin):
58
63
  __namespace__ = "ssh"
64
+
65
+
66
+ def calculate_fingerprints(public_key_decoded: bytes, ssh_keygen_format: bool = False) -> tuple[str, str, str]:
67
+ """Calculate the MD5, SHA1 and SHA256 digest of the given decoded public key.
68
+
69
+ Adheres as much as possible to the output provided by ssh-keygen when ``ssh_keygen_format``
70
+ parameter is set to ``True``. When set to ``False`` (default) hexdigests are calculated
71
+ instead for ``sha1``and ``sha256``.
72
+
73
+ Resources:
74
+ - https://en.wikipedia.org/wiki/Public_key_fingerprint
75
+ - https://man7.org/linux/man-pages/man1/ssh-keygen.1.html
76
+ - ``ssh-keygen -l -E <alg> -f key.pub``
77
+ """
78
+ if not public_key_decoded:
79
+ raise ValueError("No decoded public key provided")
80
+
81
+ if not isinstance(public_key_decoded, bytes):
82
+ raise ValueError("Provided public key should be bytes")
83
+
84
+ if public_key_decoded[0:3] != b"\x00\x00\x00":
85
+ raise ValueError("Provided value does not look like a public key")
86
+
87
+ digest_md5 = md5(public_key_decoded).digest()
88
+ digest_sha1 = sha1(public_key_decoded).digest()
89
+ digest_sha256 = sha256(public_key_decoded).digest()
90
+
91
+ if ssh_keygen_format:
92
+ fingerprint_sha1 = base64.b64encode(digest_sha1).rstrip(b"=").decode()
93
+ fingerprint_sha256 = base64.b64encode(digest_sha256).rstrip(b"=").decode()
94
+ else:
95
+ fingerprint_sha1 = digest_sha1.hex()
96
+ fingerprint_sha256 = digest_sha256.hex()
97
+
98
+ return digest_md5.hex(), fingerprint_sha1, fingerprint_sha256
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.17.dev25
3
+ Version: 3.17.dev26
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
@@ -133,10 +133,10 @@ dissect/target/plugins/apps/remoteaccess/teamviewer.py,sha256=SiEH36HM2NvdPuCjfL
133
133
  dissect/target/plugins/apps/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
134
  dissect/target/plugins/apps/shell/powershell.py,sha256=biPSMRWxPI6kRqP0-75yMtrw0Ti2Bzfl_xI3xbmmF48,2641
135
135
  dissect/target/plugins/apps/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- dissect/target/plugins/apps/ssh/openssh.py,sha256=jDNP8aq9JHivosexPlxWRUgeJo1MHclb336dzO1zRJc,7086
136
+ dissect/target/plugins/apps/ssh/openssh.py,sha256=yt3bX93Q9wfF25_vG9APMwfZWUUqCPyLlVJdhu20syI,7250
137
137
  dissect/target/plugins/apps/ssh/opensshd.py,sha256=DaXKdgGF3GYHHA4buEvphcm6FF4C8YFjgD96Dv6rRnM,5510
138
- dissect/target/plugins/apps/ssh/putty.py,sha256=N8ssjutUVN50JNA5fEIVISbP5sJ7bGTFidRbX3uNG5Y,9404
139
- dissect/target/plugins/apps/ssh/ssh.py,sha256=uCaoWlT2bgKLUHA1aL6XymJDWJ8JmLsN8PB1C66eidY,1409
138
+ dissect/target/plugins/apps/ssh/putty.py,sha256=bTX6ZU6zsc78zBdsBGUotc_ek_E1a7HSowoqD1y4PzA,9927
139
+ dissect/target/plugins/apps/ssh/ssh.py,sha256=tTA87u0B8yY1yVCPV0VJdRUct6ggkir_pIziP-eKnVo,3009
140
140
  dissect/target/plugins/apps/vpn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
141
141
  dissect/target/plugins/apps/vpn/openvpn.py,sha256=d-DGINTIHP_bvv3T09ZwbezHXGctvCyAhJ482m2_-a0,7654
142
142
  dissect/target/plugins/apps/vpn/wireguard.py,sha256=SoAMED_bwWJQ3nci5qEY-qV4wJKSSDZQ8K7DoJRYq0k,6521
@@ -336,10 +336,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
336
336
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
337
337
  dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
338
338
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
339
- dissect.target-3.17.dev25.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
340
- dissect.target-3.17.dev25.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
341
- dissect.target-3.17.dev25.dist-info/METADATA,sha256=9gF0AAh1PZsU75RQtErozfTPL0q2jyWQo1i76L34lR0,11300
342
- dissect.target-3.17.dev25.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
343
- dissect.target-3.17.dev25.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
344
- dissect.target-3.17.dev25.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
345
- dissect.target-3.17.dev25.dist-info/RECORD,,
339
+ dissect.target-3.17.dev26.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
340
+ dissect.target-3.17.dev26.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
341
+ dissect.target-3.17.dev26.dist-info/METADATA,sha256=fyuJSNpaOXUDx5rJFQYpsaxFKwa7VqFttG1XIvZxXco,11300
342
+ dissect.target-3.17.dev26.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
343
+ dissect.target-3.17.dev26.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
344
+ dissect.target-3.17.dev26.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
345
+ dissect.target-3.17.dev26.dist-info/RECORD,,