## https://sploitus.com/exploit?id=MSF:AUXILIARY-ADMIN-REGISTRY_SECURITY_DESCRIPTOR-
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SMB::Client::Authenticated
include Msf::OptionalSession::SMB
include Msf::Util::WindowsRegistry
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Registry Security Descriptor Utility',
'Description' => %q{
Read or write a Windows registry security descriptor remotely.
In READ mode, the `FILE` option can be set to specify where the
security descriptor should be written to.
The following format is used:
```
key: <registry key>
security_info: <security information>
sd: <security descriptor as a hex string>
```
In WRITE mode, the `FILE` option can be used to specify the information
needed to write the security descriptor to the remote registry. The file must
follow the same format as described above.
},
'Author' => [
'Christophe De La Fuente'
],
'License' => MSF_LICENSE,
'Actions' => [
[ 'READ', { 'Description' => 'Read a Windows registry security descriptor' } ],
[ 'WRITE', { 'Description' => 'Write a Windows registry security descriptor' } ]
],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => [CONFIG_CHANGES]
},
'DefaultAction' => 'READ'
)
)
register_options(
[
OptString.new('KEY', [ false, 'Registry key to read or write' ]),
OptString.new('SD', [ false, 'Security Descriptor to write as a hex string' ], conditions: %w[ACTION == WRITE], regex: /^([a-fA-F0-9]{2})+$/),
OptInt.new('SECURITY_INFORMATION', [
true,
'Security Information to read or write (see '\
'https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/23e75ca3-98fd-4396-84e5-86cd9d40d343 '\
'(default: OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)',
RubySMB::Field::SecurityDescriptor::OWNER_SECURITY_INFORMATION |
RubySMB::Field::SecurityDescriptor::GROUP_SECURITY_INFORMATION |
RubySMB::Field::SecurityDescriptor::DACL_SECURITY_INFORMATION
]),
OptString.new('FILE', [
false,
'File path to store the security descriptor when reading or source file path used to write the security descriptor when writing'
])
]
)
end
def do_connect
if session
print_status("Using existing session #{session.sid}")
client = session.client
self.simple = ::Rex::Proto::SMB::SimpleClient.new(client.dispatcher.tcp_socket, client: client)
simple.connect("\\\\#{simple.address}\\IPC$")
else
connect
begin
smb_login
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
fail_with(Module::Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")
end
end
report_service(
host: simple.address,
port: simple.port,
host_name: simple.client.default_name,
proto: 'tcp',
name: 'smb',
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
)
begin
@tree = simple.client.tree_connect("\\\\#{simple.address}\\IPC$")
rescue RubySMB::Error::RubySMBError => e
fail_with(Module::Failure::Unreachable, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e}).")
end
begin
@winreg = @tree.open_file(filename: 'winreg', write: true, read: true)
@winreg.bind(endpoint: RubySMB::Dcerpc::Winreg)
rescue RubySMB::Error::RubySMBError => e
fail_with(Module::Failure::Unreachable, "Error when connecting to 'winreg' interface ([#{e.class}] #{e}).")
end
end
def run
do_connect
case action.name
when 'READ'
action_read
when 'WRITE'
action_write
else
print_error("Unknown action #{action.name}")
end
ensure
@winreg.close if @winreg
@tree.disconnect! if @tree
# Don't disconnect the client if it's coming from the session so it can be reused
unless session
simple.client.disconnect! if simple&.client.is_a?(RubySMB::Client)
disconnect
end
end
def action_read
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
sd = @winreg.get_key_security_descriptor(datastore['KEY'], datastore['SECURITY_INFORMATION'], bind: false)
print_good("Raw security descriptor for #{datastore['KEY']}: #{sd.bytes.map { |c| '%02x' % c.ord }.join}")
unless datastore['FILE'].blank?
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
remote_reg.save_to_file(datastore['KEY'], sd, datastore['SECURITY_INFORMATION'], datastore['FILE'])
print_good("Saved to file #{datastore['FILE']}")
end
end
def action_write
if datastore['FILE'].blank?
fail_with(Failure::BadConfig, 'Unknown security descriptor, please set the `SD` option') if datastore['SD'].blank?
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
sd = datastore['SD']
key = datastore['KEY']
security_info = datastore['SECURITY_INFORMATION']
else
print_status("Getting security descriptor info from file #{datastore['FILE']}")
remote_reg = Msf::Util::WindowsRegistry::RemoteRegistry.new(@winreg, name: :sam)
sd_info = remote_reg.read_from_file(datastore['FILE'])
sd = sd_info['sd']
key = sd_info['key']
security_info = sd_info['security_info']
vprint_line(" key: #{key}")
vprint_line(" security information: #{security_info}")
vprint_line(" security descriptor: #{sd}")
end
sd = sd.chars.each_slice(2).map { |c| c.join.to_i(16).chr }.join
@winreg.set_key_security_descriptor(key, sd, security_info, bind: false)
print_good("Security descriptor set for #{key}")
rescue RubySMB::Dcerpc::Error::WinregError => e
fail_with(Failure::Unknown, "Unable to set the security descriptor for #{key}: #{e}")
end
end