Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/registry_security_descriptor.rb
19778 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::SMB::Client::Authenticated
8
include Msf::OptionalSession::SMB
9
include Msf::Util::WindowsRegistry
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Windows Registry Security Descriptor Utility',
16
'Description' => %q{
17
Read or write a Windows registry security descriptor remotely.
18
19
In READ mode, the `FILE` option can be set to specify where the
20
security descriptor should be written to.
21
22
The following format is used:
23
```
24
key: <registry key>
25
security_info: <security information>
26
sd: <security descriptor as a hex string>
27
```
28
29
In WRITE mode, the `FILE` option can be used to specify the information
30
needed to write the security descriptor to the remote registry. The file must
31
follow the same format as described above.
32
},
33
'Author' => [
34
'Christophe De La Fuente'
35
],
36
'License' => MSF_LICENSE,
37
'Actions' => [
38
[ 'READ', { 'Description' => 'Read a Windows registry security descriptor' } ],
39
[ 'WRITE', { 'Description' => 'Write a Windows registry security descriptor' } ]
40
],
41
'Notes' => {
42
'Stability' => [CRASH_SAFE],
43
'Reliability' => [],
44
'SideEffects' => [CONFIG_CHANGES]
45
},
46
'DefaultAction' => 'READ'
47
)
48
)
49
50
register_options(
51
[
52
OptString.new('KEY', [ false, 'Registry key to read or write' ]),
53
OptString.new('SD', [ false, 'Security Descriptor to write as a hex string' ], conditions: %w[ACTION == WRITE], regex: /^([a-fA-F0-9]{2})+$/),
54
OptInt.new('SECURITY_INFORMATION', [
55
true,
56
'Security Information to read or write (see '\
57
'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343 '\
58
'(default: OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)',
59
RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION |
60
RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION |
61
RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION
62
]),
63
OptString.new('FILE', [
64
false,
65
'File path to store the security descriptor when reading or source file path used to write the security descriptor when writing'
66
])
67
]
68
)
69
end
70
71
def do_connect
72
if session
73
print_status("Using existing session #{session.sid}")
74
self.simple = session.simple_client
75
simple.connect("\\\\#{simple.address}\\IPC$")
76
else
77
connect
78
begin
79
smb_login
80
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
81
fail_with(Module::Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")
82
end
83
end
84
85
report_service(
86
host: simple.address,
87
port: simple.port,
88
host_name: simple.client.default_name,
89
proto: 'tcp',
90
name: 'smb',
91
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
92
)
93
94
begin
95
@tree = simple.client.tree_connect("\\\\#{simple.address}\\IPC$")
96
rescue RubySMB::Error::RubySMBError => e
97
fail_with(Module::Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).")
98
end
99
100
begin
101
@winreg = @tree.open_file(filename: 'winreg', write: true, read: true)
102
@winreg.bind(endpoint: RubySMB::Dcerpc::Winreg)
103
rescue RubySMB::Error::RubySMBError => e
104
fail_with(Module::Failure::Unreachable, "Error when connecting to 'winreg' interface ([#{e.class}] #{e}).")
105
end
106
end
107
108
def run
109
do_connect
110
111
case action.name
112
when 'READ'
113
action_read
114
when 'WRITE'
115
action_write
116
else
117
print_error("Unknown action #{action.name}")
118
end
119
ensure
120
@winreg.close if @winreg
121
@tree.disconnect! if @tree
122
# Don't disconnect the client if it's coming from the session so it can be reused
123
unless session
124
simple.client.disconnect! if simple&.client.is_a?(RubySMB::Client)
125
disconnect
126
end
127
end
128
129
def action_read
130
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
131
132
sd = @winreg.get_key_security_descriptor(datastore['KEY'], datastore['SECURITY_INFORMATION'], bind: false)
133
print_good("Raw security descriptor for #{datastore['KEY']}: #{sd.bytes.map { |c| '%02x' % c.ord }.join}")
134
135
unless datastore['FILE'].blank?
136
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
137
remote_reg.save_to_file(datastore['KEY'], sd, datastore['SECURITY_INFORMATION'], datastore['FILE'])
138
print_good("Saved to file #{datastore['FILE']}")
139
end
140
end
141
142
def action_write
143
if datastore['FILE'].blank?
144
fail_with(Failure::BadConfig, 'Unknown security descriptor, please set the `SD` option') if datastore['SD'].blank?
145
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
146
sd = datastore['SD']
147
key = datastore['KEY']
148
security_info = datastore['SECURITY_INFORMATION']
149
else
150
print_status("Getting security descriptor info from file #{datastore['FILE']}")
151
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
152
sd_info = remote_reg.read_from_file(datastore['FILE'])
153
sd = sd_info['sd']
154
key = sd_info['key']
155
security_info = sd_info['security_info']
156
vprint_line(" key: #{key}")
157
vprint_line(" security information: #{security_info}")
158
vprint_line(" security descriptor: #{sd}")
159
end
160
161
sd = sd.chars.each_slice(2).map { |c| c.join.to_i(16).chr }.join
162
@winreg.set_key_security_descriptor(key, sd, security_info, bind: false)
163
print_good("Security descriptor set for #{key}")
164
rescue RubySMB::Dcerpc::Error::WinregError => e
165
fail_with(Failure::Unknown, "Unable to set the security descriptor for #{key}: #{e}")
166
end
167
end
168
169