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/modules/auxiliary/admin/registry_security_descriptor.rb
Views: 1904
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
client = session.client
75
self.simple = ::Rex::Proto::SMB::SimpleClient.new(client.dispatcher.tcp_socket, client: client)
76
simple.connect("\\\\#{simple.address}\\IPC$")
77
else
78
connect
79
begin
80
smb_login
81
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
82
fail_with(Module::Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")
83
end
84
end
85
86
report_service(
87
host: simple.address,
88
port: simple.port,
89
host_name: simple.client.default_name,
90
proto: 'tcp',
91
name: 'smb',
92
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
93
)
94
95
begin
96
@tree = simple.client.tree_connect("\\\\#{simple.address}\\IPC$")
97
rescue RubySMB::Error::RubySMBError => e
98
fail_with(Module::Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).")
99
end
100
101
begin
102
@winreg = @tree.open_file(filename: 'winreg', write: true, read: true)
103
@winreg.bind(endpoint: RubySMB::Dcerpc::Winreg)
104
rescue RubySMB::Error::RubySMBError => e
105
fail_with(Module::Failure::Unreachable, "Error when connecting to 'winreg' interface ([#{e.class}] #{e}).")
106
end
107
end
108
109
def run
110
do_connect
111
112
case action.name
113
when 'READ'
114
action_read
115
when 'WRITE'
116
action_write
117
else
118
print_error("Unknown action #{action.name}")
119
end
120
ensure
121
@winreg.close if @winreg
122
@tree.disconnect! if @tree
123
# Don't disconnect the client if it's coming from the session so it can be reused
124
unless session
125
simple.client.disconnect! if simple&.client.is_a?(RubySMB::Client)
126
disconnect
127
end
128
end
129
130
def action_read
131
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
132
133
sd = @winreg.get_key_security_descriptor(datastore['KEY'], datastore['SECURITY_INFORMATION'], bind: false)
134
print_good("Raw security descriptor for #{datastore['KEY']}: #{sd.bytes.map { |c| '%02x' % c.ord }.join}")
135
136
unless datastore['FILE'].blank?
137
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
138
remote_reg.save_to_file(datastore['KEY'], sd, datastore['SECURITY_INFORMATION'], datastore['FILE'])
139
print_good("Saved to file #{datastore['FILE']}")
140
end
141
end
142
143
def action_write
144
if datastore['FILE'].blank?
145
fail_with(Failure::BadConfig, 'Unknown security descriptor, please set the `SD` option') if datastore['SD'].blank?
146
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
147
sd = datastore['SD']
148
key = datastore['KEY']
149
security_info = datastore['SECURITY_INFORMATION']
150
else
151
print_status("Getting security descriptor info from file #{datastore['FILE']}")
152
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
153
sd_info = remote_reg.read_from_file(datastore['FILE'])
154
sd = sd_info['sd']
155
key = sd_info['key']
156
security_info = sd_info['security_info']
157
vprint_line(" key: #{key}")
158
vprint_line(" security information: #{security_info}")
159
vprint_line(" security descriptor: #{sd}")
160
end
161
162
sd = sd.chars.each_slice(2).map { |c| c.join.to_i(16).chr }.join
163
@winreg.set_key_security_descriptor(key, sd, security_info, bind: false)
164
print_good("Security descriptor set for #{key}")
165
rescue RubySMB::Dcerpc::Error::WinregError => e
166
fail_with(Failure::Unknown, "Unable to set the security descriptor for #{key}: #{e}")
167
end
168
end
169
170