Implementing KASLR detection in Volatility
This is the final part of my writedown on Volatility KASLR adventures.
After figuring out my memory analysis problems with dumps from Linux systems with kernel 4.9 I wanted to implement the KASLR detection in Volatility. As stated before my Ruby is quite fluent but my Python skills are more on advanced beginner level, thus I wanted to refrain from messing up with the Linux overlay in the Volatility core too much and rather implement this as a plugin.
Preparing Volatility core infrastructure for physical KASLR shifts
However a few changes in the Linux overlay were required nonetheless, since it only supported one
shift
parameter and I needed two, one for the virtual and one for the physical shift:
Moreover if I want to enable the user to supply a physical shift to Volatility on the command line
I need to introduce a corresponding option, which is done in volatilty/plugins/linux/common.py
:
Authoring a Volatility plugin
After this has been accomplished, let’s try and write a plugin. I started out with the boilerplate code that is required for all plugins. To get an idea of what is required we should have a glance at the steps that are taken when you run Volatility:
- Volatility parses the command line arguments
- Volatility looks at the supplied profile and determines e.g. operating system
- Since we are looking at a Linux profile Volatility applies the Linux overlay
- That overlay parses the
System.map
and dwarf file of our profile - Then it sets up a runtime profile in which various properties are set, partially derived from the profile, partially some Linux inherent stuff
- Volatility tries to find the DTB
- If it found a legit DTB it will try to validate address space and profile
- The plugin supplied on the command line can now run
- That plugin needs to have a
calculate
method that gathers the relevant data and either arender_*
orunified_output
method for displaying the results
To avoid reinventing the wheel we include some Volatility classes in our plugin and inherit from AbstractLinuxIntelCommand
:
Now that we have the basic building blocks in place we need to figure out a control flow for the calculate
method.
The steps the linux_kaslr_shift
plugin will take are
- Load the profile, so that I can easily lookup symbols and do virtual to physical translation
- Find possible kernel DTB candidates
- For each candidate build the PTE tree reachable from the DTB
- Find all PAs in that tree that point to the physical location of
init_task
- Calculate the indices for the different paging levels that are traversed in order to reach the PTE that point to the PA from the previous step
- Calculate the virtual shift by subtracting the expected indices that would be used without KASLR with those that are observed in our sample
- Subtract the virtual shift from the total shift observed to determine the physical shift
- Yield each DTB, virtual shift and physical shift, so these can be consumed by
render_text
I already experienced problems during the first step, since when instantiating the profile Volatility will try to validate profile and address space which at this point fails due to physical and virtual shift being unknown. Thus I decided to monkey patch the validation code to always tell Volatility that the address space is valid:
Afterwards symbol and struct look up works fine.
Helper methods
Before delving into the core code of the plugin I want to highlight some helper functions I needed. I explained some of them in the previous post. Here is the rest:
This method searches a tree for leafs matching value
and returns the indices that were chosen in order to traverse from root to leaf. If you look at the example tree from previous post:
find_key(tree, '0x8000000000001163L')
would return [279, 91, 0, 1]
, thus in the PGD the index to reach the next hop of our desired path is 279, in the PUD the index would be 91 and so on.
Then there is the method searching for DTBs:
This is basically the original Linux overlay DTB searching code, with the slight modification that it doesn’t only return the first legit DTB but also other legit candidates that might show up in the dump. I considered alternative DTBs since the first one might not be the one matching the running system but rather an artifact before the kernel relocated itself in memory or the DTB of a Linux VM with the same kernel running on the system we acquired the memory image from. In case the plugin yields several hits it’s up to the user to determine the correct one.
As already apparent by the comment this will convert an integer to a binary string and sort out invalid candidates. For each index of the 4 translation steps we pass it to this method and generate a 36 character long binary string that is the virtual shift represented in 1’s and 0’s.
This is a helper method for the AMD64 paged memory address space that returns the index of a virtual address in the PUD. Appropriate methods for PGD, PMD and PT indices are already implemented in that address space.
More imports
For some functionality (e.g. debug output, regex matching) in the plugin I needed to include more classes and libraries. This is the final import code:
The final calculate
method
With all of this in place I could finally implement and run the calculate
method:
As you can see in the last line the calculate
yields an array comprised of 3 elements for each valid DTB/Virtual shift/physical shift combination. To display the results properly the render_text
methods needs to be adapted:
Switching to unified output
At the time I was writing the plugin I was constantly looking at Github issues and pull request in the Volatility repository. One of those [issues][unifiedbug] mentioned problems with json output for a plugin. This is when I learned about unified output and decided to also implement this for my plugin. To support this I had to include two more imports:
I replaced my render_text
method with this:
Final thoughts and future of the plugin
After completing the plugin I was pondering if I should submit the plugin to the community plugins repository and if I should wait for the next Volatility plugin contest in order to have a chance to win some Volatility swag. However since Debian Stretch will be released soon and other Linux distributions also start shipping KASLR enabled kernel > 4.8 I thought this should be a core plugin and I wanted people to be able to analyze memory images from systems that run more recent distributions, thus I submitted it as a normal pull request.
I instantly received a response by Andrew Case who seems to be in charge of Linux related stuff in Volatility. Since then some weeks have passed and he reimplemented some of this plugins functionality in the Linux overlay. He found a more elegant way to retrieve the virtual shift by looking up a the files
member in init_tasks
task_struct
. This member should - in theory - point to the virtual address of init_files
. Thus by subtracting the VA of init_files
in System.map
from that value you get the virtual shift without any PTE tree building and index comparison. However the initial version of his KASLR detection did not work with my memory samples, thus I created a second pull request to fix it.
If this gets merged in upstream my plugin almost becomes obsolete before it made it into the core plugin set. However the features it still provides are lookups of more than one possible DTBs and virtual shift determination in case the init_files
symbol is not available or the value of init_task->files
is corrupted (which however in turn undermines the credibility of the entire memory image).
You can find the complete source code for the plugin here. At the time of this writing the value for physical shift has another meaning in my feature branch than upstream. However I plan to adapt output etc. to upstream as soon as their KASLR detection code is working properly.
Thanks for reading all of this.