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

Linux: add member presence checks to linux.checks_afinfo #1038

Merged
Merged
Changes from all commits
Commits
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
50 changes: 40 additions & 10 deletions volatility3/framework/plugins/linux/check_afinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,22 @@ def _check_members(self, var_ops, var_name, members):
yield check, addr

def _check_afinfo(self, var_name, var, op_members, seq_members):
for hooked_member, hook_address in self._check_members(
var.seq_fops, var_name, op_members
):
yield var_name, hooked_member, hook_address
# check if object has a least one of the members used for analysis by this function
required_members = ["seq_fops", "seq_ops", "seq_show"]
has_required_member = any(
[var.has_member(member) for member in required_members]
)
if not has_required_member:
vollog.debug(
f"{var_name} object at {hex(var.vol.offset)} had none of the required members: {', '.join([member for member in required_members])}"
)
raise exceptions.PluginRequirementException

if var.has_member("seq_fops"):
for hooked_member, hook_address in self._check_members(
var.seq_fops, var_name, op_members
):
yield var_name, hooked_member, hook_address

# newer kernels
if var.has_member("seq_ops"):
Expand All @@ -64,8 +76,10 @@ def _check_afinfo(self, var_name, var, op_members, seq_members):
yield var_name, hooked_member, hook_address

# this is the most commonly hooked member by rootkits, so a force a check on it
elif not self._is_known_address(var.seq_show):
yield var_name, "show", var.seq_show
else:
if var.has_member("seq_show"):
if not self._is_known_address(var.seq_show):
yield var_name, "show", var.seq_show

def _generator(self):
vmlinux = self.context.modules[self.config["kernel"]]
Expand All @@ -85,6 +99,12 @@ def _generator(self):
)
protocols = [tcp, udp]

# used to track the calls to _check_afinfo and the
# number of errors produced due to missing members
symbols_checked = set()
symbols_with_errors = set()

# loop through all symbols
for struct_type, global_vars in protocols:
for global_var_name in global_vars:
# this will lookup fail for the IPv6 protocols on kernels without IPv6 support
Expand All @@ -97,10 +117,20 @@ def _generator(self):
object_type=struct_type, offset=global_var.address
)

for name, member, address in self._check_afinfo(
global_var_name, global_var, op_members, seq_members
):
yield 0, (name, member, format_hints.Hex(address))
symbols_checked.add(global_var_name)
try:
for name, member, address in self._check_afinfo(
global_var_name, global_var, op_members, seq_members
):
yield 0, (name, member, format_hints.Hex(address))
except exceptions.PluginRequirementException:
symbols_with_errors.add(global_var_name)

# if every call to _check_afinfo failed show a warning
if symbols_checked == symbols_with_errors:
vollog.warning(
"This plugin was not able to check for hooks. This means you are either analyzing an unsupported kernel version or that your symbol table is corrupt."
)

def run(self):
return renderers.TreeGrid(
Expand Down