Package rekall :: Package plugins :: Package linux :: Module keepassx
[frames] | no frames]

Source Code for Module rekall.plugins.linux.keepassx

  1  #  Gathers information about password entries for keepassx 
  2  # 
  3  #    Copyright (c) 2017, Frank Block, ERNW GmbH <fblock@ernw.de> 
  4  # 
  5  #       All rights reserved. 
  6  # 
  7  #       Redistribution and use in source and binary forms, with or without modification, 
  8  #       are permitted provided that the following conditions are met: 
  9  # 
 10  #       * Redistributions of source code must retain the above copyright notice, this 
 11  #         list of conditions and the following disclaimer. 
 12  #       * Redistributions in binary form must reproduce the above copyright notice, 
 13  #         this list of conditions and the following disclaimer in the documentation 
 14  #         and/or other materials provided with the distribution. 
 15  #       * The names of the contributors may not be used to endorse or promote products 
 16  #         derived from this software without specific prior written permission. 
 17  # 
 18  #       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 19  #       AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 20  #       IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 21  #       ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
 22  #       LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 23  #       DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 24  #       SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 25  #       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 26  #       OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 27  #       OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 28   
 29  """Gathers information about password entries for keepassx. 
 30     The retrieved content of those entries comprises the username, title, URL 
 31     and Comment. 
 32  """ 
 33   
 34  import struct 
 35  from rekall.plugins.linux import heap_analysis 
 36   
 37   
38 -class Keepassx(heap_analysis.HeapAnalysis):
39 """Gathers password entries for keepassx. 40 The retrieved content of those entries comprises the username, title, URL 41 and Comment.""" 42 43 __name = "keepassx" 44 45 table_header = [ 46 dict(name="divider", type="Divider"), 47 dict(name="task", hidden=True), 48 dict(name="entry", width=6), 49 dict(name="title", width=26), 50 dict(name="url", width=28), 51 dict(name="username", width=28), 52 dict(name="comment", width=44) 53 ] 54 55
56 - def collect(self):
57 for task in self.filter_processes(): 58 if self.init_for_task(task): 59 60 yield dict(divider="Task: %s (%s)" % (task.name, 61 task.pid)) 62 63 chunks_dict = dict() 64 65 data_offset = self.profile.get_obj_offset("malloc_chunk", "fd") 66 67 for chunk in self.get_all_allocated_chunks(): 68 chunks_dict[chunk.v() + data_offset] = chunk 69 70 if self.session.profile.metadata("arch") == 'AMD64': 71 string_offset = 26 72 relevant_chunk_size = 192 73 pointer_offsets = [16, 24, 32, 64] 74 75 else: 76 string_offset = 18 77 relevant_chunk_size = 96 78 pointer_offsets = [12, 16, 20, 36] 79 80 entry_number = 1 81 82 for chunk in chunks_dict.values(): 83 84 try: 85 # chunks containing refs to password entries typically 86 # have a size of 96 in the tested 32 bit environment 87 if not chunk.chunksize() == relevant_chunk_size: 88 continue 89 90 p_entry_data = chunk.to_string() 91 92 field_strings = [] 93 94 # the pointers to title, username and so on are at 95 # these offsets 96 for i in pointer_offsets: 97 if self.session.profile.metadata("arch") == 'I386': 98 pointer = struct.unpack('I', 99 p_entry_data[i:i+4])[0] 100 else: 101 pointer = struct.unpack('Q', 102 p_entry_data[i:i+8])[0] 103 104 # if there is no chunk for the given pointer, we 105 # most probably have a wrong chunk. this will 106 # throw a KeyError exception and we proceed with 107 # the next chunk 108 curr_chunk_data = chunks_dict[pointer].to_string() 109 110 string_size = struct.unpack( 111 'I', curr_chunk_data[8:12])[0] 112 113 string_size *= 2 114 115 curr_string = curr_chunk_data[ 116 string_offset:string_offset+string_size] 117 118 curr_string = curr_string.decode('utf-16-le') 119 120 field_strings.append(repr(curr_string)) 121 122 123 yield dict(task=task, entry=entry_number, 124 title=field_strings[0], 125 url=field_strings[1], 126 username=field_strings[2], 127 comment=field_strings[3]) 128 129 entry_number += 1 130 131 except (KeyError, UnicodeDecodeError): 132 # a password entry struct not containing a pointer to 133 # a chunk => out of scope 134 pass
135