forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land rapid7#19115, read/write registry key SD
Module to read/write registry key security descriptor remotely
- Loading branch information
Showing
3 changed files
with
255 additions
and
6 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
documentation/modules/auxiliary/admin/registry_security_descriptor.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
## Vulnerable Application | ||
|
||
This module reads or writes 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. | ||
|
||
## Verification Steps | ||
|
||
1. Start msfconsole | ||
1. Do: `use auxiliary/admin/registry_security_descriptor` | ||
1. Do: `run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key>` | ||
1. **Verify** the registry key security descriptor is displayed | ||
1. Do: `run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key> file=<file path>` | ||
1. **Verify** the registry key security descriptor is saved to the file | ||
1. Do: `run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key> action=write sd=<security descriptor as a hex string>` | ||
1. **Verify** the security descriptor is correctly set on the given registry key | ||
1. Do: `run verbose=true rhost=<host> smbuser=<username> smbpass=<password> file=<file path>` | ||
1. **Verify** the security descriptor taken from the file is correctly set on the given registry key | ||
|
||
## Options | ||
|
||
### KEY | ||
Registry key to read or write. | ||
|
||
### SD | ||
Security Descriptor to write as a hex string. | ||
|
||
### SECURITY_INFORMATION | ||
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). | ||
|
||
### FILE | ||
File path to store the security descriptor when reading or source file path used to write the security descriptor when writing | ||
|
||
|
||
## Scenarios | ||
|
||
### Read against Windows Server 2019 | ||
|
||
``` | ||
msf6 auxiliary(admin/registry_security_descriptor) > run verbose=true rhost=192.168.101.124 smbuser=Administrator smbpass=123456 action=READ key='HKLM\SECURITY\Policy\PolEKList' | ||
[*] Running module against 192.168.101.124 | ||
[+] 192.168.101.124:445 - Raw security descriptor for HKLM\SECURITY\Policy\PolEKList: 01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000 | ||
[*] Auxiliary module execution completed | ||
``` | ||
|
||
### Write against Windows Server 2019 | ||
Note that the information security has been set to 4 (DACL_SECURITY_INFORMATION) to avoid an access denied error. | ||
|
||
``` | ||
msf6 auxiliary(admin/registry_security_descriptor) > run verbose=true rhost=192.168.101.124 smbuser=Administrator smbpass=123456 key='HKLM\SECURITY\Policy\PolEKList' action=WRITE sd=01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000 security_information=4 | ||
[*] Running module against 192.168.101.124 | ||
[+] 192.168.101.124:445 - Security descriptor set for HKLM\SECURITY\Policy\PolEKList | ||
[*] Auxiliary module execution completed | ||
``` | ||
|
||
### Write against Windows Server 2019 (from file) | ||
|
||
``` | ||
msf6 auxiliary(admin/registry_security_descriptor) > run verbose=true rhost=192.168.101.124 smbuser=Administrator smbpass=123456 action=WRITE file=/tmp/remote_registry_sd_backup.yml | ||
[*] Running module against 192.168.101.124 | ||
[*] 192.168.101.124:445 - Getting security descriptor info from file /tmp/remote_registry_sd_backup.yml | ||
key: HKLM\SECURITY\Policy\PolEKList | ||
security information: 4 | ||
security descriptor: 01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000 | ||
[+] 192.168.101.124:445 - Security descriptor set for HKLM\SECURITY\Policy\PolEKList | ||
[*] Auxiliary module execution completed | ||
``` |
168 changes: 168 additions & 0 deletions
168
modules/auxiliary/admin/registry_security_descriptor.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
## | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters