Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plugins for volatile Linux artefacts #241

Merged
merged 30 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
384f083
Add volatile Linux plugins
Horofic Apr 25, 2023
1bd9f1f
Merge fixed user_details function
Horofic Jun 8, 2023
4f85ab2
Impement review comments
Horofic Jun 8, 2023
643f526
Fix linting errors
Horofic Jun 8, 2023
0f4b77f
Fix black formatting
Horofic Jun 8, 2023
5768c8b
Make acquires of just /proc or /sys detectable
Horofic Jun 8, 2023
68a1b6a
Update dissect/target/plugins/os/unix/netstat.py
Horofic Jul 5, 2023
3c945a3
Update dissect/target/plugins/os/unix/netstat.py
Horofic Jul 5, 2023
f3a432c
Update dissect/target/plugins/os/unix/netstat.py
Horofic Jul 5, 2023
30e8663
Add review remarks
Horofic Jul 5, 2023
8ca747a
Merge branch 'DIS-1443_add-volatile-linux-plugins' of github.com:fox-…
Horofic Jul 5, 2023
cf709f8
Linting fixes
Horofic Jul 6, 2023
9b0799b
Merge branch 'main' into DIS-1443_add-volatile-linux-plugins
Horofic Jul 7, 2023
a548d70
Add review remarks
Horofic Aug 21, 2023
1fd518c
Misc bugfixes
Horofic Aug 21, 2023
0c3bbdd
Add review comments
Horofic Sep 6, 2023
14068e3
Modify tests
Horofic Sep 8, 2023
394c461
Add review remarks
Horofic Sep 8, 2023
7e61c3a
Add review remarks
Horofic Sep 13, 2023
6c3a0f5
Add review remarks
Horofic Sep 13, 2023
37e12dc
Merge branch 'main' into DIS-1443_add-volatile-linux-plugins
Schamper Sep 13, 2023
34347f6
Change tests
Horofic Sep 13, 2023
b4d4431
Add typehints
Horofic Sep 13, 2023
eb75d3e
Black fixes
Horofic Sep 13, 2023
95d8102
Black fixes
Horofic Sep 13, 2023
0a4c602
Merge branch 'DIS-1443_add-volatile-linux-plugins' of github.com:fox-…
Horofic Sep 13, 2023
1b4d7c8
Improve test
Horofic Sep 13, 2023
2cfd9e6
Merge branch 'main' into DIS-1443_add-volatile-linux-plugins
Schamper Sep 14, 2023
8387933
Add simple tests for plugins
Horofic Sep 14, 2023
aeb92ea
Add additional test and review remarks
Horofic Sep 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion dissect/target/plugins/os/unix/linux/_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ def __init__(self, target: Target):
@classmethod
def detect(cls, target: Target) -> Optional[Filesystem]:
for fs in target.filesystems:
if fs.exists("/var") and fs.exists("/etc") and fs.exists("/opt") and not fs.exists("/Library"):
if (
fs.exists("/var")
and fs.exists("/etc")
and fs.exists("/opt")
or (fs.exists("/sys") or fs.exists("/proc"))
and not fs.exists("/Library")
):
return fs
return None

Expand Down
48 changes: 48 additions & 0 deletions dissect/target/plugins/os/unix/linux/cmdline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import Iterator

from dissect.target.helpers.record import TargetRecordDescriptor
from dissect.target.plugin import Plugin, export

CmdlineRecord = TargetRecordDescriptor(
"linux/proc/cmdline",
[
("datetime", "ts"),
("string", "name"),
("varint", "pid"),
("string", "state"),
("string", "cmdline"),
],
)


class CmdlinePlugin(Plugin):
def check_compatible(self) -> None:
self.target.proc

@export(record=CmdlineRecord)
def cmdline(self) -> Iterator[CmdlineRecord]:
"""Return the complete command line for all processes.

If, after an execve(2), the process modifies its argv strings, those changes will show up here. This is not the
same thing as modifying the argv array.

Think of this output as the command line that the process wants you to see.

Yields CmdlineRecord with the following fields:
hostname (string): The target hostname.
domain (string): The target domain.
ts (datetime): The starttime of the process.
name (string): The name of the process.
pid (int): The process ID of the process.
cmdline (string): The complete commandline of the process.
"""
Horofic marked this conversation as resolved.
Show resolved Hide resolved

for process in self.target.proc.processes():
yield CmdlineRecord(
ts=process.starttime,
name=process.name,
pid=process.pid,
state=process.state,
cmdline=process.cmdline,
_target=self.target,
)
47 changes: 47 additions & 0 deletions dissect/target/plugins/os/unix/linux/environ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import Iterator

from dissect.target.helpers.record import TargetRecordDescriptor
from dissect.target.plugin import Plugin, export

EnvironmentVariableRecord = TargetRecordDescriptor(
"linux/proc/environ",
[
("datetime", "ts"),
("string", "name"),
("varint", "pid"),
("string", "variable"),
("string", "content"),
],
)


class EnvironPlugin(Plugin):
def check_compatible(self) -> None:
self.target.proc

@export(record=EnvironmentVariableRecord)
def environ(self) -> Iterator[EnvironmentVariableRecord]:
"""Return the initial environment for all processes when they were started via execve(2).

If the process modified its environment (e.g., by calling functions such as putenv(3) or modifying
the environ(7) variable directly), this plugin will not reflect those changes.

Yields EnvironmentVariableRecord with the following fields:
hostname (string): The target hostname.
domain (string): The target domain.
ts (datetime): The modification timestamp of the processes' environ file.
name (string): The name associated to the pid.
pid (varint): The process id (pid) of the process.
variable (string): The name of the environment variable.
content (string): The contents of the environment variable.
"""
for process in self.target.proc.processes():
for environ in process.environ():
yield EnvironmentVariableRecord(
ts=process.get("environ").stat().st_mtime,
name=process.name,
pid=process.pid,
variable=environ.variable,
content=environ.contents,
_target=self.target,
)
41 changes: 41 additions & 0 deletions dissect/target/plugins/os/unix/linux/netstat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from itertools import chain
from typing import Iterator

from dissect.target.plugin import Plugin, export

NETSTAT_HEADER = f"Active Internet connections (only servers)\n{'Proto':<10}{'Recv-Q':^10}{'Send-Q':^10}{'Local Address':^20}{'Foreign Address':^20}{'State':^10}{'User':^15}{'Inode':^10}{'PID/Program name':^10}{'Command':>10}" # noqa
NETSTAT_TEMPLATE = "{protocol:<12}{receive_queue:<10}{transmit_queue:<11}{local_addr:<19}{remote_addr:<20}{state:<13}{owner:<12}{inode:<8}{pid_program:<19}{cmdline}" # noqa


class NetstatPlugin(Plugin):
def check_compatible(self) -> None:
self.target.proc

@export(output="yield")
def netstat(self) -> Iterator[str]:
"""This plugin mimics the output `netstat -tunelwap` would generate on a Linux machine."""
sockets = chain(
self.target.sockets.tcp(),
self.target.sockets.udp(),
self.target.sockets.raw(),
)

yield NETSTAT_HEADER

for record in sockets:
local_addr = f"{record.local_ip}:{record.local_port}"
remote_addr = f"{record.remote_ip}:{record.remote_port}"
pid_program = f"{record.pid}/{record.name}"

yield NETSTAT_TEMPLATE.format(
protocol=record.protocol,
receive_queue=record.rx_queue,
transmit_queue=record.tx_queue,
local_addr=local_addr,
remote_addr=remote_addr,
state=record.state,
owner=record.owner,
inode=record.inode,
pid_program=pid_program,
cmdline=record.cmdline,
)
Loading
Loading