Record Descriptors¶
Most output generated by Dissect tools takes the form of records.
You can create your own records by defining a record descriptor:
from dissect.target.helpers.record import TargetRecordDescriptor
FirewallRecord = TargetRecordDescriptor(
"application/firewall",
[
("datetime", "ts"),
("net.ipaddress", "ip"),
("uint16", "port"),
("string", "protocol"),
],
)
A record is composed of various field types and their corresponding names.
The TargetRecordDescriptor()
will add basic target information to complete your record.
You can now generate records by filling the structure like this:
firewall_record = FirewallRecord(
ts=time.time(),
ip="0.0.0.0",
port=8080,
protocol="tcp",
_target=t
)
Target related information like hostname
and domain
will be automatically added if you provide your target
by setting the _target
field. There are some default record descriptors extending
TargetRecordDescriptor()
available for common scenarios:
Record Descriptor |
Additional Fields |
---|---|
ChildTargetRecord |
|
UnixUserRecord |
|
WindowsUserRecord |
|
If you create your own record descriptor, it is often practical to use existing ones as a basis.
This helps to keep the naming uniform. To extend existing record descriptors use
create_extended_descriptor()
.
For instance, to create a record descriptor for browser downloads you could use:
from dissect.target.helpers.record import create_extended_descriptor
Descriptor = create_extended_descriptor([UserRecordDescriptorExtension])
DownloadRecord = Descriptor(
"browser/download", [
("uri", "url"),
("filesize", "size"),
]
)
You can now combine data from several sources in one record:
DownloadRecord(
url="http://example.com/download.zip",
size=123,
_target=t,
_user=u
)
Note that source fields (_target
, _user
) from the extended record descriptors are provided using keywords starting with
an underscore.
It is also possible to use multiple existing record descriptor extensions as the basis of your new descriptor:
from dissect.target.helpers.record import create_extended_descriptor
UserRegistryRecordDescriptor = create_extended_descriptor(
[
RegistryRecordDescriptorExtension,
UserRecordDescriptorExtension,
]
)
The following record descriptor extensions are available:
Record Descriptor Extension |
Fields |
Source Field |
---|---|---|
RegistryRecordDescriptorExtension |
|
_key |
TargetRecordDescriptorExtension |
|
_target |
UserRecordDescriptorExtension |
|
_user |
GroupedRecord¶
A GroupedRecord
holds multiple records and offers a flat view of the records.
Suppose you wish to record an event system that contains events with triggers and
events with actions. You could use a GroupedRecord
to compose records reflecting
these combinations:
from flow.record import GroupedRecord
if action:
yield GroupedRecord("event/grouped", [event, action])
elif trigger:
yield GroupedRecord("event/grouped", [event, trigger])
If two records have the same fieldname, the first one will prevail.
Warning
Note that, this record type cannot be used to nest records. Nesting records is not possible.
DynamicDescriptor¶
The DynamicDescriptor()
function returns a plain record descriptor with the provided types.
This function can be used if your plugin creates its own record descriptor dynamically but you still
wish to provide certain field types through the export decorator.
Let’s say you create a dynamic descriptor with fields fields
:
yield TargetRecordDescriptor("sql/table", fields)(
_target=self.target,
**values,
)
In this case you might want to communicate that fields
at least contains a digest type:
@export(record=DynamicDescriptor(["digest"]))
This allows other tools that are interested in records having specific field types to check if your plugin function provides this.