volatilityfoundation / volatility3

Volatility 3.0 development
http://volatilityfoundation.org/
Other
2.72k stars 461 forks source link

New linux plugin: modxview #1330

Open Abyss-W4tcher opened 3 weeks ago

Abyss-W4tcher commented 3 weeks ago

Hello,

This new plugin centralizes the module detection capabilities, and allows to quickly spot and list all the modules. This way, it is easier to detect copycat malicious modules, trying to mimic kernel modules names (ex: https://attack.mitre.org/techniques/T1036/006/). To keep the name familiar for long-term users, it follows the psxview naming convention.

In addition, this PR introduces the capability to parse taint flags, which embeds additional data to help debug a kernel or a module (as it is in the end, quite similar).

Here are some sample (stripped) outputs :

"/proc/modules" hidden module :

$ python3 vol.py -f sample1.bin linux.modxview
  |                Name |        Address | In /proc/modules | In /sys/module/ | Hidden |                      Taints
* |                lime | 0xffffc0bd2040 |             True |            True |  False | OOT_MODULE,UNSIGNED_MODULE
* |       rootkit_ports | 0xffffc0a9b180 |             True |            True |  False | OOT_MODULE,UNSIGNED_MODULE
* |        rootkit_char | 0xffffc0a8f2c0 |             True |            True |  False | OOT_MODULE,UNSIGNED_MODULE
* |              vboxsf | 0xffffc0bf8800 |             True |            True |  False | OOT_MODULE,UNSIGNED_MODULE
* |      rootkit_sysfsh | 0xffffc0aa0180 |            False |            True |  False | OOT_MODULE,UNSIGNED_MODULE

"/proc/modules" hidden module (plain taints string) :

$ python3 vol.py -f sample1.bin linux.modxview --plain-taints
  |                Name |        Address | In /proc/modules | In /sys/module/ | Hidden | Taints
* |                lime | 0xffffc0bd2040 |             True |            True |  False |   GOE
* |       rootkit_ports | 0xffffc0a9b180 |             True |            True |  False |   GOE
* |        rootkit_char | 0xffffc0a8f2c0 |             True |            True |  False |   GOE
* |              vboxsf | 0xffffc0bf8800 |             True |            True |  False |   GOE
* |      rootkit_sysfsh | 0xffffc0aa0180 |            False |            True |  False |   GOE

Hidden module :

$ python3 vol.py -f sample2.bin linux.modxview
  |                Name |        Address | In /proc/modules | In /sys/module/ | Hidden |                      Taints
* |                 drm | 0xffffc03809c0 |             True |            True |  False |                          -
* |               kovid | 0xffffc09ed4c0 |            False |           False |   True |            UNSIGNED_MODULE

Note: kovid cleans out the taints attributes, but the UNSIGNED_MODULE one will be there nonetheless. This is still a great piece of information to spot LKM modules.

Happy to read your reviews about this !

gcmoreira commented 2 weeks ago

@Abyss-W4tcher it looks good to me. There are some potential improvements that could be included in this or a future PR, but they would impact the current design.

Abyss-W4tcher commented 2 weeks ago

@Abyss-W4tcher it looks good to me. There are some potential improvements that could be included in this or a future PR, but they would impact the current design.

  • It would be amazing to also have a Linux Kernel Tainted flags plugin that checks the (tainted_mask) flags when TaintFlags.module == False. That's what you get when read /proc/sys/kernel/tainted and it's implemented here. This indicates that the tainted flags parsing code should be relocated to a shared/common location. How about consolidating to a single function, i.e. parse_tainted_mask(tainted_mask, is_module), that can be used for both the module tainted mask and the kernel tainted mask?
  • It would be ideal if the module tainted flags were reported consistently across the three other plugins you are using here, and not just in this one.

Alright, I thought about a linux.kernel_taints plugin, but wasn't sure about the relevance of such a small plugin, thinking it would be better integrated in a windows.info equivalent for Linux ? However, I'm definitely ok for parsing the tainted_mask.

Anyway, the code can indeed be shared somewhere (maybe LinuxUtilities), while keeping the convenient and self-contained APIs inside the extensions.module as a wrapper for them ?

Putting the taint flags in other plugins outputs should be en easy task, maybe in a 3-for-1 PR if that's ok for ikelos.

gcmoreira commented 2 weeks ago

Alright, I thought about a linux.kernel_taints plugin, but wasn't sure about the relevance of such a small plugin, thinking it would be better integrated in a windows.info equivalent for Linux ? However, I'm definitely ok for parsing the tainted_mask.

Sure, this is ultimately up to @ikelos, but I personally lean toward the Unix philosophy: small, specialized tools, each dedicated to a single purpose. This approach doesn't mean each plugin must detect malicious behavior on its own. Then, we can have let's say 'macro' plugins, like the one in this PR, that aggregates various indicators to help identify anomalies. This way, the small plugins can be reused in other "macro" plugins.

The kernel tainted flags plugin code will be minimal since we will reuse the code you have already written for modules, but the insights it could provide would be highly valuable and unique. For instance:

The output could be just in a single line, or we could opt for a more detailed, explanatory format such as:

Flag  Description
----- -----------
A     desc A
B     desc B
C     desc C
gcmoreira commented 2 weeks ago

Anyway, the code can indeed be shared somewhere (maybe LinuxUtilities)

Yeah, this is one is for @ikelos. IMO if it's just one function it could be in LinuxUtilities. Alternatively, if there are more related functions, I think it could be more convenient to have a separated class containing that subsystem API .. like https://github.com/volatilityfoundation/volatility3/pull/1332/files#diff-8456da6d20fc84f0d63dedc5bc816ffde418ff41c83b1828da7c614252bda150R840 with its own version, but let's see if ikelos agrees with this idea, since that PR is still pending review.

On a related note, I think it would be a good idea to reorganize LinuxUtilities in the future, grouping functions by subsystems such as mount, modules, etc. and only keep in LinuxUtilities the general or framework helpers like container_of(), get_module_from_volobj_type(), etc. So, if everyone agree with this, it may be a good opportunity to start differentiating components from LinuxUtilities. This will also help minimize the impact of modifying a specific subsystem API and reduce the scope of its corresponding testing.

while keeping the convenient and self-contained APIs inside the extensions.module as a wrapper for them ?

Correct, and call the LinuxUtilities or modules API function with parse_tainted_mask(self.taints_value, is_module=True) and from the the Linux kernel tainted plugin parse_tainted_mask(tainted_mask_value, is_module=False).

Abyss-W4tcher commented 2 weeks ago

Alright, let's wait for ikelos to give its point of view on all these comments, then I'll unify the API depending on where we want to put it.

The kernel_taints plugin might end up calling modxview and then check for a LKM flag etc., so it might be worth opening a dedicated issue to centralize what this plugin should check and get a clear picture of what it leverages and gives insights about.

Globally, it sounds really good to me :)

gcmoreira commented 2 weeks ago

Hey @ikelos any chance you could take a look at this PR? We need it sorted before moving on to https://github.com/volatilityfoundation/volatility3/issues/1286. Thanks

Abyss-W4tcher commented 1 week ago

Hi, this is currently stale, we are waiting for a review regarding the LinuxUtilities stuff. Do we try moving and re-thinking this bit now, or do I just unify the taints function there as discussed ?

gcmoreira commented 5 days ago

Hi, this is currently stale, we are waiting for a review regarding the LinuxUtilities stuff. Do we try moving and re-thinking this bit now, or do I just unify the taints function there as discussed ?

@ikelos: In LinuxUtilities or as a separate/versioned class?

I think using a separate class is a better approach, as adding more functionality to LinuxUtilities can lead to issues. Any version change in LinuxUtilities would require version updates in all dependent plugins and APIs. To improve maintainability, we should move to versioned classes dedicated to each subsystem or API. For reference, see the approach taken in this PR.