dissect.target 3.11.dev4__py3-none-any.whl → 3.11.dev6__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.
- dissect/target/loaders/dir.py +11 -2
- dissect/target/plugins/os/windows/task_helpers/tasks_xml.py +62 -13
- dissect/target/plugins/os/windows/tasks.py +27 -16
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/METADATA +1 -1
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/RECORD +10 -10
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/LICENSE +0 -0
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/WHEEL +0 -0
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.11.dev4.dist-info → dissect.target-3.11.dev6.dist-info}/top_level.txt +0 -0
dissect/target/loaders/dir.py
CHANGED
@@ -11,18 +11,27 @@ from dissect.target.plugin import OperatingSystem
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from dissect.target import Target
|
13
13
|
|
14
|
+
PREFIXES = ["", "fs"]
|
15
|
+
|
14
16
|
|
15
17
|
class DirLoader(Loader):
|
16
18
|
"""Load a directory as a filesystem."""
|
17
19
|
|
18
20
|
@staticmethod
|
19
21
|
def detect(path: Path) -> bool:
|
20
|
-
return
|
22
|
+
return find_entry_path(path) is not None
|
21
23
|
|
22
24
|
def map(self, target: Target) -> None:
|
25
|
+
self.path /= find_entry_path(self.path)
|
23
26
|
find_and_map_dirs(target, self.path)
|
24
27
|
|
25
28
|
|
29
|
+
def find_entry_path(path: Path) -> str | None:
|
30
|
+
for prefix in PREFIXES:
|
31
|
+
if find_dirs(path / prefix)[0] is not None:
|
32
|
+
return prefix
|
33
|
+
|
34
|
+
|
26
35
|
def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None:
|
27
36
|
"""Map directories as filesystems into the given target.
|
28
37
|
|
@@ -81,7 +90,7 @@ def find_dirs(path: Path) -> tuple[str, list[Path]]:
|
|
81
90
|
if path.is_dir():
|
82
91
|
for p in path.iterdir():
|
83
92
|
# Look for directories like C or C:
|
84
|
-
if p.is_dir() and is_drive_letter_path(p):
|
93
|
+
if p.is_dir() and (is_drive_letter_path(p) or p.name in ("sysvol", "$rootfs$")):
|
85
94
|
dirs.append(p)
|
86
95
|
|
87
96
|
if not os_type:
|
@@ -19,11 +19,50 @@ from dissect.target.plugins.os.windows.task_helpers.tasks_records import (
|
|
19
19
|
TimeTriggerRecord,
|
20
20
|
TriggerRecord,
|
21
21
|
)
|
22
|
-
from dissect.target.target import Target
|
23
22
|
|
24
23
|
warnings.simplefilter(action="ignore", category=FutureWarning)
|
25
24
|
|
26
25
|
|
26
|
+
class ScheduledTasks:
|
27
|
+
def __init__(self, xml_file: TargetPath):
|
28
|
+
try:
|
29
|
+
self.xml_data = self.strip_namespace(ElementTree.fromstring(xml_file.open().read(), forbid_dtd=True))
|
30
|
+
except Exception as e:
|
31
|
+
raise InvalidTaskError(e)
|
32
|
+
|
33
|
+
self.task_path = xml_file
|
34
|
+
self.tasks = self.get_tasks()
|
35
|
+
|
36
|
+
def strip_namespace(self, data: Element) -> Element:
|
37
|
+
"""Strip namespace from XML data.
|
38
|
+
|
39
|
+
If the data has a namespace, it will be removed from all the XML tags.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
data: The XML data as an Element object.
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
The XML data with the stripped namespace.
|
46
|
+
"""
|
47
|
+
if data.tag.startswith("{"):
|
48
|
+
ns_length = data.tag.find("}")
|
49
|
+
ns = data.tag[0 : ns_length + 1]
|
50
|
+
for element in data.iter():
|
51
|
+
if element.tag.startswith(ns):
|
52
|
+
element.tag = element.tag[len(ns) :]
|
53
|
+
return data
|
54
|
+
|
55
|
+
def get_tasks(self):
|
56
|
+
tasks = []
|
57
|
+
if self.xml_data.tag == "Task":
|
58
|
+
tasks.append(XmlTask(self.xml_data, self.task_path))
|
59
|
+
else:
|
60
|
+
for task_element in self.xml_data.findall(".//{*}Task"):
|
61
|
+
tasks.append(XmlTask(task_element, self.task_path))
|
62
|
+
|
63
|
+
return tasks
|
64
|
+
|
65
|
+
|
27
66
|
class XmlTask:
|
28
67
|
"""Initialize the XmlTask class for open XML-based task files.
|
29
68
|
|
@@ -32,13 +71,21 @@ class XmlTask:
|
|
32
71
|
target: the target system.
|
33
72
|
"""
|
34
73
|
|
35
|
-
def __init__(self,
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
74
|
+
def __init__(self, task_element: Element, task_path: TargetPath):
|
75
|
+
self.task_path = task_path
|
76
|
+
self.task_element = task_element
|
77
|
+
|
78
|
+
# Properties
|
79
|
+
self.task_name = self.get_element("Properties", attribute="name")
|
80
|
+
self.app_name = self.get_element("Properties", attribute="appName")
|
81
|
+
self.args = self.get_element("Properties", attribute="args")
|
82
|
+
self.start_in = self.get_element("Properties", attribute="startIn")
|
83
|
+
self.comment = self.get_element("Properties", attribute="comment")
|
84
|
+
self.run_as = self.get_element("Properties", attribute="runAs")
|
85
|
+
self.cpassword = self.get_element("Properties", attribute="cpassword")
|
86
|
+
self.enabled = self.get_element("Properties", attribute="enabled")
|
87
|
+
self.action = self.get_element("Properties", attribute="action")
|
40
88
|
|
41
|
-
self.task_path = xml_file
|
42
89
|
self.uri = self.get_element("RegistrationInfo/URI")
|
43
90
|
self.security_descriptor = self.get_element("RegistrationInfo/SecurityDescriptor")
|
44
91
|
self.source = self.get_element("RegistrationInfo/Source")
|
@@ -88,6 +135,8 @@ class XmlTask:
|
|
88
135
|
# Data
|
89
136
|
self.data = self.get_raw("Data")
|
90
137
|
|
138
|
+
self.raw_data = self.get_raw()
|
139
|
+
|
91
140
|
def strip_namespace(self, data: Element) -> Element:
|
92
141
|
"""Strip namespace from XML data.
|
93
142
|
|
@@ -120,7 +169,7 @@ class XmlTask:
|
|
120
169
|
Returns:
|
121
170
|
str: The value of the XML element if found, otherwise None.
|
122
171
|
"""
|
123
|
-
xml_data = xml_data or self.
|
172
|
+
xml_data = xml_data or self.task_element
|
124
173
|
data = xml_data.find(xml_path)
|
125
174
|
|
126
175
|
if data is None:
|
@@ -130,7 +179,7 @@ class XmlTask:
|
|
130
179
|
|
131
180
|
return data.text
|
132
181
|
|
133
|
-
def get_raw(self, xml_path: str) -> str:
|
182
|
+
def get_raw(self, xml_path: Optional[str] = None) -> str:
|
134
183
|
"""Get the raw XML data of the specified element.
|
135
184
|
|
136
185
|
Args:
|
@@ -139,9 +188,9 @@ class XmlTask:
|
|
139
188
|
Returns:
|
140
189
|
bytes: The raw XML data as string of the element if found, otherwise None.
|
141
190
|
"""
|
142
|
-
data = self.
|
191
|
+
data = self.task_element.find(xml_path) if xml_path else self.task_element
|
143
192
|
if data:
|
144
|
-
return ElementTree.tostring(data, encoding="utf-8")
|
193
|
+
return ElementTree.tostring(data, encoding="utf-8").strip()
|
145
194
|
|
146
195
|
def get_triggers(self) -> Iterator[GroupedRecord]:
|
147
196
|
"""Get the triggers from the XML task data.
|
@@ -149,7 +198,7 @@ class XmlTask:
|
|
149
198
|
Yields:
|
150
199
|
GroupedRecord: The grouped record representing a trigger.
|
151
200
|
"""
|
152
|
-
for trigger in self.
|
201
|
+
for trigger in self.task_element.findall("Triggers/*"):
|
153
202
|
trigger_type = trigger.tag
|
154
203
|
enabled = self.get_element("Enabled", trigger)
|
155
204
|
start_boundary = self.get_element("StartBoundary", trigger)
|
@@ -233,7 +282,7 @@ class XmlTask:
|
|
233
282
|
Yields:
|
234
283
|
ActionRecord: The action record representing an action.
|
235
284
|
"""
|
236
|
-
for action in self.
|
285
|
+
for action in self.task_element.findall("Actions/*"):
|
237
286
|
action_type = action.tag
|
238
287
|
if action_type == "Exec":
|
239
288
|
command = self.get_element("Actions/Exec/Command")
|
@@ -7,7 +7,7 @@ from dissect.target.exceptions import UnsupportedPluginError
|
|
7
7
|
from dissect.target.helpers.record import DynamicDescriptor, TargetRecordDescriptor
|
8
8
|
from dissect.target.plugin import Plugin, export
|
9
9
|
from dissect.target.plugins.os.windows.task_helpers.tasks_job import AtTask
|
10
|
-
from dissect.target.plugins.os.windows.task_helpers.tasks_xml import
|
10
|
+
from dissect.target.plugins.os.windows.task_helpers.tasks_xml import ScheduledTasks
|
11
11
|
from dissect.target.target import Target
|
12
12
|
|
13
13
|
warnings.simplefilter(action="ignore", category=FutureWarning)
|
@@ -25,6 +25,15 @@ TaskRecord = TargetRecordDescriptor(
|
|
25
25
|
("string", "version"),
|
26
26
|
("string", "description"),
|
27
27
|
("string", "documentation"),
|
28
|
+
("string", "task_name"),
|
29
|
+
("string", "app_name"),
|
30
|
+
("string", "args"),
|
31
|
+
("string", "start_in"),
|
32
|
+
("string", "comment"),
|
33
|
+
("string", "run_as"),
|
34
|
+
("string", "cpassword"),
|
35
|
+
("string", "enabled"),
|
36
|
+
("string", "action"),
|
28
37
|
("string", "principal_id"),
|
29
38
|
("string", "user_id"),
|
30
39
|
("string", "logon_type"),
|
@@ -59,6 +68,7 @@ TaskRecord = TargetRecordDescriptor(
|
|
59
68
|
("string", "unified_scheduling_engine"),
|
60
69
|
("string", "disallow_start_on_remote_app_session"),
|
61
70
|
("string", "data"),
|
71
|
+
("string", "raw_data"),
|
62
72
|
],
|
63
73
|
)
|
64
74
|
|
@@ -119,23 +129,24 @@ class TasksPlugin(Plugin):
|
|
119
129
|
"""
|
120
130
|
for task_file in self.task_files:
|
121
131
|
if not task_file.suffix or task_file.suffix == ".xml":
|
122
|
-
|
132
|
+
task_objects = ScheduledTasks(task_file).tasks
|
123
133
|
else:
|
124
|
-
|
134
|
+
task_objects = [AtTask(task_file, self.target)]
|
125
135
|
|
126
|
-
|
127
|
-
|
128
|
-
|
136
|
+
for task_object in task_objects:
|
137
|
+
record_kwargs = {}
|
138
|
+
for attr in TaskRecord.fields.keys():
|
139
|
+
record_kwargs[attr] = getattr(task_object, attr, None)
|
129
140
|
|
130
|
-
|
131
|
-
|
141
|
+
record = TaskRecord(**record_kwargs, _target=self.target)
|
142
|
+
yield record
|
132
143
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
144
|
+
# Actions
|
145
|
+
for action in task_object.get_actions():
|
146
|
+
grouped = GroupedRecord("filesystem/windows/task/grouped", [record, action])
|
147
|
+
yield grouped
|
137
148
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
149
|
+
# Triggers
|
150
|
+
for trigger in task_object.get_triggers():
|
151
|
+
grouped = GroupedRecord("filesystem/windows/task/grouped", [record, trigger])
|
152
|
+
yield grouped
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.11.
|
3
|
+
Version: 3.11.dev6
|
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
|
@@ -57,7 +57,7 @@ dissect/target/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
57
57
|
dissect/target/loaders/ad1.py,sha256=k0bkY0L6NKuQBboua-jM_KgeyIcXAo59NjExDZHMy0o,572
|
58
58
|
dissect/target/loaders/asdf.py,sha256=oNmfsMpQw143FW3eeYDGCn4V-t2PC-4oBKs7U5d-DEQ,941
|
59
59
|
dissect/target/loaders/cb.py,sha256=pNFk185tfC-PDJjSrTEsdFgnH5DhY-xPXZkwrFMyJ30,3962
|
60
|
-
dissect/target/loaders/dir.py,sha256=
|
60
|
+
dissect/target/loaders/dir.py,sha256=44eQZsCG0WBm0heZV4uNfOc0EHmudEQFG5q3PJ5IWMQ,4720
|
61
61
|
dissect/target/loaders/ewf.py,sha256=6v0ROnXBHp9JiuGjJTBeG_qQQ1rYEUueiILuUcl_PYc,505
|
62
62
|
dissect/target/loaders/hyperv.py,sha256=_IOUJEO0BXaCBZ6sjIX0DZTkG9UNW5Vs9VcNHYv073w,5928
|
63
63
|
dissect/target/loaders/itunes.py,sha256=69aMTQiiGYpmD_EYSmf9mO1re8C3jAZIEStmwlMxdAk,13146
|
@@ -215,7 +215,7 @@ dissect/target/plugins/os/windows/services.py,sha256=p2v4z4YM-K3G2cnWIHVyPgsJgfr
|
|
215
215
|
dissect/target/plugins/os/windows/sru.py,sha256=4Vybz3_RJYNbLZXKYGOouUKZNWyOUSgSTf4JAGN2O7w,16808
|
216
216
|
dissect/target/plugins/os/windows/startupinfo.py,sha256=foGO8NLLjMCDEUu0x3f_2GX-1dNN-D67WFX_3ykbL_8,3407
|
217
217
|
dissect/target/plugins/os/windows/syscache.py,sha256=G3nB3TZpDKNUWXUozlPijkgRWfUmYNXf6IVYj72wAJw,3457
|
218
|
-
dissect/target/plugins/os/windows/tasks.py,sha256=
|
218
|
+
dissect/target/plugins/os/windows/tasks.py,sha256=YIFkco-zrUbNukKBQC66jdIYu3r1-J3ZRb_9gnWeQFA,5676
|
219
219
|
dissect/target/plugins/os/windows/thumbcache.py,sha256=noIpYTcqPk_zRV-DspSUjkhKoHkqiz0OJGOXPRRt6QQ,4141
|
220
220
|
dissect/target/plugins/os/windows/ual.py,sha256=vVGt5eW6axgIupYmJ_j0mAfBSoGmMqjDheLCFR5eGks,9779
|
221
221
|
dissect/target/plugins/os/windows/wer.py,sha256=vQBbUfZtgYeKg46hK_-R95aMHkm-AI2QUz3UMzQPwD4,7574
|
@@ -249,7 +249,7 @@ dissect/target/plugins/os/windows/regf/userassist.py,sha256=u0vOLZiLhGZLCy6L-EoZ
|
|
249
249
|
dissect/target/plugins/os/windows/task_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
250
250
|
dissect/target/plugins/os/windows/task_helpers/tasks_job.py,sha256=-dCkJnyEiWG9nCK378-GswM5EXelrA_g3zDHLhSQMu0,21199
|
251
251
|
dissect/target/plugins/os/windows/task_helpers/tasks_records.py,sha256=vpCyKqLQSzI5ymD1h5P6RncLEE47YtmjDFwKA16dVZ4,4046
|
252
|
-
dissect/target/plugins/os/windows/task_helpers/tasks_xml.py,sha256=
|
252
|
+
dissect/target/plugins/os/windows/task_helpers/tasks_xml.py,sha256=Xyt69OvUteov7rIEYK6b0AhFvN8kUun0k1uIAanCx6A,15250
|
253
253
|
dissect/target/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
254
254
|
dissect/target/tools/build_pluginlist.py,sha256=5fomcuMwsVzcnYx5Htf5f9lSwsLeUUvomLUXNA4t7m4,849
|
255
255
|
dissect/target/tools/dd.py,sha256=Nlh2CFOCV0ksxyedFp7BuyoQ3tBFi6rK6UO0_k5GR_8,1758
|
@@ -270,10 +270,10 @@ dissect/target/volumes/bde.py,sha256=gYGg5yF9MNARwNzEkrEfZmKkxyZW4rhLkpdnPJCbhGk
|
|
270
270
|
dissect/target/volumes/disk.py,sha256=95grSsPt1BLVpKwTclwQYzPFGKTkFFqapIk0RoGWf38,968
|
271
271
|
dissect/target/volumes/lvm.py,sha256=_kIB1mdRs1OFhRgoT4VEP5Fv8imQnI7oQ_ie4x710tQ,1814
|
272
272
|
dissect/target/volumes/vmfs.py,sha256=mlAJ8278tYaoRjk1u6tFFlCaDQUrVu5ZZE4ikiFvxi8,1707
|
273
|
-
dissect.target-3.11.
|
274
|
-
dissect.target-3.11.
|
275
|
-
dissect.target-3.11.
|
276
|
-
dissect.target-3.11.
|
277
|
-
dissect.target-3.11.
|
278
|
-
dissect.target-3.11.
|
279
|
-
dissect.target-3.11.
|
273
|
+
dissect.target-3.11.dev6.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
274
|
+
dissect.target-3.11.dev6.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
275
|
+
dissect.target-3.11.dev6.dist-info/METADATA,sha256=sR-MwTH-UuIh5xHWbx51ZFeANVcbNo4AC-8289muhXk,10683
|
276
|
+
dissect.target-3.11.dev6.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
277
|
+
dissect.target-3.11.dev6.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
|
278
|
+
dissect.target-3.11.dev6.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
279
|
+
dissect.target-3.11.dev6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|