CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/util/windows_registry/sam.rb
Views: 1904
1
module Msf
2
module Util
3
module WindowsRegistry
4
5
#
6
# This module include helpers for the SAM hive
7
#
8
module Sam
9
10
def normalize_key(key)
11
@root.blank? ? key : key.delete_prefix(@root)
12
end
13
14
# Returns the HashedBootKey from a given BootKey.
15
#
16
# @param boot_key [String] The BootKey
17
# @return [String] The HashedBootKey or an empty string if the revision
18
# number is unknown
19
def get_hboot_key(boot_key)
20
qwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0"
21
digits = "0123456789012345678901234567890123456789\0"
22
23
_value_type, value_data = get_value(normalize_key('HKLM\\SAM\\SAM\\Domains\\Account'), 'F')
24
revision = value_data[0x68, 4].unpack('V')[0]
25
case revision
26
when 1
27
hash = Digest::MD5.new
28
hash.update(value_data[0x70, 16] + qwerty + boot_key + digits)
29
rc4 = OpenSSL::Cipher.new('rc4')
30
rc4.decrypt
31
rc4.key = hash.digest
32
hboot_key = rc4.update(value_data[0x80, 32])
33
hboot_key << rc4.final
34
hboot_key
35
when 2
36
aes = OpenSSL::Cipher.new('aes-128-cbc')
37
aes.decrypt
38
aes.key = boot_key
39
aes.padding = 0
40
aes.iv = value_data[0x78, 16]
41
aes.update(value_data[0x88, 16]) # we need only 16 bytes
42
else
43
elog("[Msf::Util::WindowsRegistry::Sam::get_hboot_key] Unknown hbootKey revision: #{revision}")
44
''.b
45
end
46
end
47
48
# Returns the `Users` key information under HKLM\SAM\Domains\Account\Users.
49
# This includes the RID, name and `V` value for each user.
50
#
51
# @return [Hash] A hash with the following structure:
52
# {
53
# <User RID>: { V: <V value>, Name: <User name> },
54
# ...
55
# }
56
def get_user_keys(&block)
57
users = {}
58
users_key = normalize_key('HKLM\\SAM\\SAM\\Domains\\Account\\Users')
59
rids = enum_key(users_key)
60
if rids
61
rids.delete('Names')
62
63
rids.each do |rid|
64
rid = rid.to_s
65
rid.encode!(::Encoding::UTF_8) unless rid.encoding == ::Encoding::UTF_8
66
key = "#{users_key}\\#{rid}"
67
yield key if block
68
_value_type, value_data = get_value(key, 'V')
69
next unless value_data
70
users[rid.to_i(16)] ||= {}
71
users[rid.to_i(16)][:V] = value_data
72
73
# Attempt to get Hints
74
_value_type, value_data = get_value("#{users_key}\\#{rid}", 'UserPasswordHint')
75
next unless value_data
76
77
users[rid.to_i(16)][:UserPasswordHint] =
78
value_data.dup.force_encoding(::Encoding::UTF_16LE).encode(::Encoding::UTF_8).strip
79
end
80
end
81
82
# Retrieve the user names for each RID
83
# TODO: use a proper structure to do this, since the user names are included in V data
84
names = enum_key("#{users_key}\\Names")
85
if names
86
names.each do |name|
87
name = name.to_s
88
name.encode!(::Encoding::UTF_8) unless name.encoding == ::Encoding::UTF_8
89
key = "#{users_key}\\Names\\#{name}"
90
yield key if block
91
value_type, _value_data = get_value(key, '')
92
users[value_type] ||= {}
93
# Apparently, key names are ISO-8859-1 encoded
94
users[value_type][:Name] = name.dup.force_encoding(::Encoding::ISO_8859_1).encode(::Encoding::UTF_8)
95
end
96
end
97
98
users
99
end
100
end
101
102
end
103
end
104
end
105
106
107