CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/util/windows_registry/remote_registry.rb
Views: 11784
1
module Msf
2
module Util
3
module WindowsRegistry
4
5
class RemoteRegistry
6
# Constants
7
ROOT_KEY = 0x2c
8
REG_NONE = 0x00
9
REG_SZ = 0x01
10
REG_EXPAND_SZ = 0x02
11
REG_BINARY = 0x03
12
REG_DWORD = 0x04
13
REG_MULTISZ = 0x07
14
REG_QWORD = 0x0b
15
16
def initialize(winreg, name: nil, inline: false)
17
@winreg = winreg
18
@inline = inline
19
case name
20
when :sam
21
require_relative 'sam'
22
extend Sam
23
when :security
24
require_relative 'security'
25
extend Security
26
else
27
wlog("[Msf::Util::WindowsRegistry::RemoteRegistry] Unknown :name argument: #{name}") unless name.blank?
28
end
29
end
30
31
def create_ace(sid)
32
access_mask = RubySMB::Dcerpc::Winreg::Regsam.new({
33
write_dac: 1,
34
read_control: 1,
35
key_enumerate_sub_keys: 1,
36
key_query_value: 1
37
})
38
Rex::Proto::MsDtyp::MsDtypAce.new({
39
header: {
40
ace_type: Rex::Proto::MsDtyp::MsDtypAceType::ACCESS_ALLOWED_ACE_TYPE,
41
ace_flags: { container_inherit_ace: 1 }
42
},
43
body: {
44
access_mask: Rex::Proto::MsDtyp::MsDtypAccessMask.read(access_mask.to_binary_s),
45
sid: sid
46
}
47
})
48
end
49
50
def backup_file_path
51
return @backup_file_path if @backup_file_path
52
53
if ! File.directory?(Msf::Config.local_directory)
54
FileUtils.mkdir_p(Msf::Config.local_directory)
55
end
56
remote_host = @winreg.tree.client.dns_host_name
57
remote_host = @winreg.tree.client.dispatcher.tcp_socket.peerhost if remote_host.blank?
58
path = File.join(Msf::Config.local_directory, "remote_registry_sd_backup_#{remote_host}_#{Time.now.strftime("%Y%m%d%H%M%S")}.#{Rex::Text.rand_text_alpha(6)}.yml")
59
@backup_file_path = File.expand_path(path)
60
end
61
62
def save_to_file(key, security_descriptor, security_information, path = backup_file_path)
63
sd_info = {
64
'key' => key,
65
'security_info' => security_information,
66
'sd' => security_descriptor.b.bytes.map { |c| '%02x' % c.ord }.join
67
}
68
File.open(path, 'w') do |fd|
69
fd.write(sd_info.to_yaml)
70
end
71
end
72
73
def read_from_file(filepath)
74
sd_info = YAML.safe_load_file(filepath)
75
sd_info['security_info'] = sd_info['security_info'].to_i
76
sd_info
77
end
78
79
def delete_backup_file(path = backup_file_path)
80
File.delete(path) if File.file?(path)
81
end
82
83
def change_dacl(key, sid)
84
security_information =
85
RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION |
86
RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION |
87
RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION
88
89
security_descriptor = @winreg.get_key_security_descriptor(key, security_information, bind: false)
90
dlog("[Msf::Util::WindowsRegistry::RemoteRegistry] Security descriptor for #{key}: #{security_descriptor.b.bytes.map { |c| '%02x' % c.ord }.join}")
91
save_to_file(key, security_descriptor, RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION)
92
93
parsed_sd = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.read(security_descriptor)
94
ace = create_ace(sid)
95
parsed_sd.dacl.aces << ace
96
parsed_sd.dacl.acl_count += 1
97
parsed_sd.dacl.acl_size += ace.num_bytes
98
dlog("[Msf::Util::WindowsRegistry::RemoteRegistry] New security descriptor for #{key}: #{parsed_sd.to_binary_s.b.bytes.map { |c| '%02x' % c.ord }.join}")
99
100
@winreg.set_key_security_descriptor(key, parsed_sd.to_binary_s, RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION, bind: false)
101
102
security_descriptor
103
rescue RubySMB::Dcerpc::Error::WinregError => e
104
elog("[Msf::Util::WindowsRegistry::RemoteRegistry] Error while changing DACL on key `#{key}`: #{e}")
105
end
106
107
def restore_dacl(key, security_descriptor)
108
begin
109
dlog("[Msf::Util::WindowsRegistry::RemoteRegistry] Restoring DACL on key `#{key}`")
110
@winreg.set_key_security_descriptor(key, security_descriptor, RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION, bind: false)
111
rescue StandardError => e
112
elog(
113
"[Msf::Util::WindowsRegistry::RemoteRegistry] Error while restoring DACL on key `#{key}`: #{e}\n"\
114
"The original security descriptor has been saved in `#{backup_file_path}`. "\
115
"The auxiliary module `admin/registry_security_descriptor` can be used to "\
116
"restore the security descriptor from this file."
117
)
118
# Reset the `backup_file_path` instance variable to make sure a new
119
# backup filename will be generated. This way, this backup file won't
120
# be deleted the next time `#restore_dacl` is called.
121
@backup_file_path = nil
122
return
123
end
124
delete_backup_file
125
end
126
127
def enum_values(key)
128
sd_backup = change_dacl(key, Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ADMINS) if @inline
129
@winreg.enum_registry_values(key, bind: false).map do |value|
130
value.to_s.encode(::Encoding::ASCII_8BIT)
131
end
132
ensure
133
restore_dacl(key, sd_backup) if @inline && sd_backup
134
end
135
136
def enum_key(key)
137
sd_backup = change_dacl(key, Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ADMINS) if @inline
138
@winreg.enum_registry_key(key, bind: false).map do |key|
139
key.to_s.encode(::Encoding::ASCII_8BIT)
140
end
141
ensure
142
restore_dacl(key, sd_backup) if @inline && sd_backup
143
end
144
145
def get_value(key, value_name = nil)
146
sd_backup = change_dacl(key, Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ADMINS) if @inline
147
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
148
root_key_handle = @winreg.open_root_key(root_key)
149
subkey_handle = @winreg.open_key(root_key_handle, sub_key)
150
begin
151
reg_value = @winreg.query_value(subkey_handle, value_name.nil? ? '' : value_name)
152
[reg_value.type.to_i, reg_value.data.to_s.b]
153
rescue RubySMB::Dcerpc::Error::WinregError
154
nil
155
end
156
ensure
157
@winreg.close_key(subkey_handle) if subkey_handle
158
@winreg.close_key(root_key_handle) if root_key_handle
159
restore_dacl(key, sd_backup) if @inline && sd_backup
160
end
161
162
end
163
end
164
end
165
end
166
167
168
169