cakeboss893 / volatility

Automatically exported from code.google.com/p/volatility
GNU General Public License v2.0
0 stars 0 forks source link

DTB search is suboptimal #140

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
So currently the DTB is searched like this (basic.py):
1. Each profile has a magic signature which seems to be different for different 
releases, but ends up pointing at the start of an _EPROCESS.
2. We instantiate an _EPROCESS on each offset and check that ImageFileName is 
"Idle".
3. If it is we return the _EPROCESS.Pcb.DirectoryTableBase

This unnecessarily increases the maintainance between profiles and does not 
lend itself well to autoguessing the profiles we should be using, because we 
need to effectively scan the entire image for each profile.

The way it should work is this:
1. Search the image for Idle, System or a number of other system level 
processes. The actual ImageFileName field is 16 bytes and null padded so pad 
with nulls for the search string.
2. Check for validity of _EPROCESS given the profile. This will allow us to 
iterate through all the profiles quickly on the same candidate site.

We should also consider a reporting mode where we report several potential 
candidates or allow the user to search for a non Idle system level process. 
Otherwise we open ourselves to a rather trivial antiforensic attack.

Original issue reported on code.google.com by scude...@google.com on 22 Sep 2011 at 1:21

GoogleCodeExporter commented 8 years ago
Mmmm, I wouldn't want to rely on Idle, even when followed by nulls, just 
because I think that'd be too easy for a program to accidentally duplicate and 
throw us off the scent.

I'm also happy to have a DTBscan plugin that offers different suggestions, but 
I think autochoosing should still be the default.  People can always use --dtb 
as they've always been able to.  Since *everything* else depends on it, I think 
we should try to do the best thing by default and let people get on with the 
real work, rather than offering them a choice each time.  Perhaps that's what 
you were suggesting?  VolatilityMagic's lend themselves well to offering 
multiple suggestions, so that shouldn't be an issue...

Original comment by mike.auty@gmail.com on 22 Sep 2011 at 10:21

GoogleCodeExporter commented 8 years ago
There are other problems with the current DTB searching algorithm in trunk. In 
searching through the address spaces in utils.load_as() we guess the dtb as 
described above. But in order to distinguish between a PAE and a non PAE 
address space we have these two tests:

        # This constraint looks for self referential values within                                                                                                                            
        # the paging tables                                                                                                                                                                   
        try:                                                                                                                                                                                  
            if self.obj_vm.pae:                                                                                                                                                               
                pde_base = 0xc0600000                                                                                                                                                         
                pd = self.obj_vm.get_pdpte(0) & 0xffffffffff000                                                                                                                               
            else:                                                                                                                                                                             
                pde_base = 0xc0300000                                                                                                                                                         
                pd = self.obj_vm.dtb                                                                                                                                                          
            if (self.obj_vm.vtop(pde_base) == pd):                                                                                                                                            
                yield True                                                                                                                                                                    
                raise StopIteration                                                                                                                                                           

        except addrspace.ASAssertionError, _e:                                                                                                                                                
            pass                                                                                                                                                                              
        debug.debug("Failed to pass the Moyix Valid IA32 AS test", 3)                                                                                                                         

        # This constraint verifies that _KUSER_ SHARED_DATA is shared                                                                                                                         
        # between user and kernel address spaces.                                                                                                                                             
        if (self.obj_vm.vtop(0xffdf0000)) == (self.obj_vm.vtop(0x7ffe0000)):                                                                                                                  
            if self.obj_vm.vtop(0xffdf0000) != None:                                                                                                                                          
                yield True                                                                                                                                                                    
                raise StopIteration                                                                                                                                                           
        debug.debug("Failed to pass the labarum_x Valid IA32 AS test", 3)        

These numbers seem to be chosen specifically for some versions of windows. I am 
not confident this check will pass on other operating systems at all. We would 
need to constantly test these numbers between profiles which is a maintenance 
headache.

For windows a more reliable way of verifying the sanity of the AS is to reflect 
through it using the well known list reflection method. (We use this in many 
places already). If the AS is incorrect we will be unable to reflect correctly. 
 So in reality the check is more than just for a constant string "Idle\x00...", 
because those hits are further filtered by DTB verification.  This 
implementation can also look for another process name other than Idle (but it 
must be a kernel process).

http://code.google.com/p/volatility/source/browse/branches/scudette/volatility/p
lugins/windows/common.py#63

Original comment by scude...@gmail.com on 4 Mar 2012 at 1:10

GoogleCodeExporter commented 8 years ago

Original comment by mike.auty@gmail.com on 4 Mar 2012 at 1:18

GoogleCodeExporter commented 8 years ago
Which operating systems does this check fail on? 

Original comment by jamie.l...@gmail.com on 4 Mar 2012 at 9:47

GoogleCodeExporter commented 8 years ago
Well this check is specifically for 32 bit operating systems. It is 
specifically designed to distinguish between the PAE and non PAE variants.

Actually the 64 bit AS specifies a check of AMD64ValidAS but I dont think this 
is actually defined or implemented - so there is little checking of validity in 
64 bits.

I am just suggesting this alternate check because IMHO its more intuitive and 
clear to understand, and is also implemented equally on 64 bit systems.

 I guess the current method is good enough if slightly magical, providing we are confident the 64 bit address spaces do not need checking.

Original comment by scude...@gmail.com on 4 Mar 2012 at 9:58

GoogleCodeExporter commented 8 years ago

Original comment by mike.auty@gmail.com on 10 Mar 2012 at 10:54

GoogleCodeExporter commented 8 years ago
Analysis of the DTB detection is going to be required for auto-selection of 
profiles, so I'm just adding this issue to the 2.2.x milestone. 

Original comment by michael.hale@gmail.com on 13 Jun 2012 at 2:41

GoogleCodeExporter commented 8 years ago

Original comment by michael.hale@gmail.com on 26 Aug 2012 at 5:35

GoogleCodeExporter commented 8 years ago

Original comment by michael.hale@gmail.com on 1 Feb 2013 at 4:37

GoogleCodeExporter commented 8 years ago

Original comment by jamie.l...@gmail.com on 6 Jan 2014 at 7:09

GoogleCodeExporter commented 8 years ago
Given that AMD64ValidAS is now implemented, and working models exist for PAE vs 
non-PAE for other OS besides windows, this isn't a required change. Also since 
we have psscan to find all processes regardless of their name, we don't need a 
DTBScan plugin that lets users specify a name. For antiforensics attacks that 
manipulate the "Idle" or "System" strings, we can always fall back to the --dtb 
option, since that's what its there for. 

Original comment by michael.hale@gmail.com on 7 Mar 2014 at 6:39