Package rekall :: Package plugins :: Package windows :: Package registry :: Module hashdump
[frames] | no frames]

Source Code for Module rekall.plugins.windows.registry.hashdump

  1  # Rekall Memory Forensics 
  2  # Copyright (c) 2008 Volatile Systems 
  3  # Copyright (c) 2008 Brendan Dolan-Gavitt <bdolangavitt@wesleyan.edu> 
  4  # Copyright 2013 Google Inc. All Rights Reserved. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or (at 
  9  # your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 19  # 
 20   
 21  """ 
 22  @author:       Brendan Dolan-Gavitt 
 23  @license:      GNU General Public License 2.0 or later 
 24  @contact:      bdolangavitt@wesleyan.edu 
 25   
 26  http://moyix.blogspot.com/2008/02/decrypting-lsa-secrets.html 
 27   
 28  Code seems to be inspired by eyas_at_xfocus.org 
 29  http://www.xfocus.net/articles/200411/749.html 
 30  """ 
 31  import struct 
 32   
 33  from rekall import obj 
 34  from Crypto.Hash import MD5 
 35  from Crypto.Hash import MD4 
 36  from Crypto.Cipher import DES 
 37  from Crypto.Cipher import ARC4 
 38   
 39   
 40  odd_parity = [ 
 41    1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, 
 42    16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 
 43    32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 
 44    49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 
 45    64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, 
 46    81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, 
 47    97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110, 
 48    112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127, 
 49    128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143, 
 50    145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 
 51    161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174, 
 52    176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191, 
 53    193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206, 
 54    208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223, 
 55    224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239, 
 56    241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254 
 57  ] 
 58   
 59  # Permutation matrix for boot key 
 60  p = [ 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 
 61        0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 ] 
 62   
 63  # Constants for SAM decrypt algorithm 
 64  aqwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" 
 65  anum = "0123456789012345678901234567890123456789\0" 
 66  antpassword = "NTPASSWORD\0" 
 67  almpassword = "LMPASSWORD\0" 
 68  lmkey = "KGS!@#$%" 
 69   
 70  empty_lm = "aad3b435b51404eeaad3b435b51404ee".decode('hex') 
 71  empty_nt = "31d6cfe0d16ae931b73c59d7e0c089c0".decode('hex') 
 72   
73 -def str_to_key(s):
74 key = [] 75 key.append(ord(s[0]) >> 1) 76 key.append(((ord(s[0]) & 0x01) << 6) | (ord(s[1]) >> 2)) 77 key.append(((ord(s[1]) & 0x03) << 5) | (ord(s[2]) >> 3)) 78 key.append(((ord(s[2]) & 0x07) << 4) | (ord(s[3]) >> 4)) 79 key.append(((ord(s[3]) & 0x0F) << 3) | (ord(s[4]) >> 5)) 80 key.append(((ord(s[4]) & 0x1F) << 2) | (ord(s[5]) >> 6)) 81 key.append(((ord(s[5]) & 0x3F) << 1) | (ord(s[6]) >> 7)) 82 key.append(ord(s[6]) & 0x7F) 83 for i in range(8): 84 key[i] = (key[i] << 1) 85 key[i] = odd_parity[key[i]] 86 return "".join(chr(k) for k in key)
87
88 -def sid_to_key(sid):
89 s1 = "" 90 s1 += chr(sid & 0xFF) 91 s1 += chr((sid >> 8) & 0xFF) 92 s1 += chr((sid >> 16) & 0xFF) 93 s1 += chr((sid >> 24) & 0xFF) 94 s1 += s1[0] 95 s1 += s1[1] 96 s1 += s1[2] 97 s2 = s1[3] + s1[0] + s1[1] + s1[2] 98 s2 += s2[0] + s2[1] + s2[2] 99 100 return str_to_key(s1), str_to_key(s2)
101
102 -def hash_lm(pw):
103 pw = pw[:14].upper() 104 pw = pw + ('\0' * (14 - len(pw))) 105 d1 = DES.new(str_to_key(pw[:7]), DES.MODE_ECB) 106 d2 = DES.new(str_to_key(pw[7:]), DES.MODE_ECB) 107 return d1.encrypt(lmkey) + d2.encrypt(lmkey)
108
109 -def hash_nt(pw):
110 return MD4.new(pw.encode('utf-16-le')).digest()
111
112 -def find_control_set(sys_registry):
113 """Determine which control set we are currently running with.""" 114 csselect = sys_registry.open_key("Select") 115 if not csselect: 116 return 1 117 118 value = csselect.open_value("Current") 119 return value.DecodedData
120
121 -def get_bootkey(sys_registry):
122 """Derive the boot key by unscrambling the LSA.""" 123 cs = find_control_set(sys_registry) 124 bootkey = "" 125 lsa_base = ["ControlSet{0:03}".format(cs), "Control", "Lsa"] 126 lsa_keys = ["JD", "Skew1", "GBG", "Data"] 127 128 lsa = sys_registry.open_key(lsa_base) 129 130 for lk in lsa_keys: 131 subkey = lsa.open_subkey(lk) 132 bootkey_data = subkey.Class.dereference_as("UnicodeString", 133 length=subkey.ClassLength) 134 135 bootkey += bootkey_data.v().decode('hex') 136 137 bootkey_scrambled = "" 138 for i in range(len(bootkey)): 139 bootkey_scrambled += bootkey[p[i]] 140 141 return bootkey_scrambled
142
143 -def get_hbootkey(sam_registry, bootkey):
144 sam_account_path = ["SAM", "Domains", "Account"] 145 146 sam_account_key = sam_registry.open_key(sam_account_path) 147 148 # Get the F value 149 F = sam_account_key.open_value("F").DecodedData 150 if not F: 151 return F 152 153 md5 = MD5.new() 154 md5.update(F[0x70:0x80] + aqwerty + bootkey + anum) 155 rc4_key = md5.digest() 156 157 rc4 = ARC4.new(rc4_key) 158 hbootkey = rc4.encrypt(F[0x80:0xA0]) 159 160 return hbootkey
161
162 -def get_user_keys(sam_registry):
163 user_key_path = ["SAM", "Domains", "Account", "Users"] 164 165 user_key = sam_registry.open_key(user_key_path) 166 167 for k in user_key.subkeys(): 168 if k.Name != "Names": 169 yield k
170
171 -def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr):
172 (des_k1, des_k2) = sid_to_key(rid) 173 d1 = DES.new(des_k1, DES.MODE_ECB) 174 d2 = DES.new(des_k2, DES.MODE_ECB) 175 176 md5 = MD5.new() 177 md5.update(hbootkey[:0x10] + struct.pack("<L", rid) + lmntstr) 178 rc4_key = md5.digest() 179 rc4 = ARC4.new(rc4_key) 180 obfkey = rc4.encrypt(enc_hash) 181 hash = d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:]) 182 183 return hash
184
185 -def decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey):
186 # LM Hash 187 if enc_lm_hash: 188 lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword) 189 else: 190 lmhash = "" 191 192 # NT Hash 193 if enc_nt_hash: 194 nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword) 195 else: 196 nthash = "" 197 198 return lmhash, nthash
199
200 -def encrypt_single_hash(rid, hbootkey, hash, lmntstr):
201 (des_k1, des_k2) = sid_to_key(rid) 202 d1 = DES.new(des_k1, DES.MODE_ECB) 203 d2 = DES.new(des_k2, DES.MODE_ECB) 204 205 enc_hash = d1.encrypt(hash[:8]) + d2.encrypt(hash[8:]) 206 207 md5 = MD5.new() 208 md5.update(hbootkey[:0x10] + struct.pack("<L", rid) + lmntstr) 209 rc4_key = md5.digest() 210 rc4 = ARC4.new(rc4_key) 211 obfkey = rc4.encrypt(enc_hash) 212 213 return obfkey
214
215 -def encrypt_hashes(rid, lm_hash, nt_hash, hbootkey):
216 # LM Hash 217 if lm_hash: 218 enc_lmhash = encrypt_single_hash(rid, hbootkey, lm_hash, almpassword) 219 else: 220 enc_lmhash = "" 221 222 # NT Hash 223 if nt_hash: 224 enc_nthash = encrypt_single_hash(rid, hbootkey, nt_hash, antpassword) 225 else: 226 enc_nthash = "" 227 228 return enc_lmhash, enc_nthash
229
230 -def get_user_hashes(user_key, hbootkey):
231 rid = int(str(user_key.Name), 16) 232 233 V = user_key.open_value("V").DecodedData 234 235 lm_offset = struct.unpack("<L", V[0x9c:0xa0])[0] + 0xCC + 4 236 lm_len = struct.unpack("<L", V[0xa0:0xa4])[0] - 4 237 nt_offset = struct.unpack("<L", V[0xa8:0xac])[0] + 0xCC + 4 238 nt_len = struct.unpack("<L", V[0xac:0xb0])[0] - 4 239 240 if lm_len: 241 enc_lm_hash = V[lm_offset:lm_offset + 0x10] 242 else: 243 enc_lm_hash = "" 244 245 if nt_len: 246 enc_nt_hash = V[nt_offset:nt_offset + 0x10] 247 else: 248 enc_nt_hash = "" 249 250 return decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey)
251
252 -def get_user_name(user_key):
253 V = user_key.open_value("V").DecodedData 254 255 name_offset = struct.unpack("<L", V[0x0c:0x10])[0] + 0xCC 256 name_length = struct.unpack("<L", V[0x10:0x14])[0] 257 258 username = V[name_offset:name_offset + name_length].decode('utf-16-le') 259 260 return username
261
262 -def get_user_desc(user_key):
263 V = user_key.open_value("V").DecodedData 264 265 desc_offset = struct.unpack("<L", V[0x24:0x28])[0] + 0xCC 266 desc_length = struct.unpack("<L", V[0x28:0x2c])[0] 267 268 desc = V[desc_offset:desc_offset + desc_length].decode('utf-16-le') 269 270 return desc
271
272 -def dump_hashes(sys_registry, sam_registry):
273 bootkey = get_bootkey(sys_registry) 274 hbootkey = get_hbootkey(sam_registry, bootkey) 275 276 if hbootkey: 277 for user in get_user_keys(sam_registry): 278 lmhash, nthash = get_user_hashes(user, hbootkey) 279 if not lmhash: 280 lmhash = empty_lm 281 if not nthash: 282 nthash = empty_nt 283 yield "{0}:{1}:{2}:{3}:::".format(get_user_name(user), int(str(user.Name), 16), 284 lmhash.encode('hex'), nthash.encode('hex')) 285 else: 286 yield obj.NoneObject("Hbootkey is not valid")
287