Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module to read/write registry key security descriptor remotely #19115

Merged

Conversation

cdelafuente-r7
Copy link
Contributor

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.

⚠️ Important ⚠️
DO NOT MERGE YET.
This module is based on this branch will need this PR landed first. This PR only adds two files:

  • modules/auxiliary/admin/registry_security_descriptor.rb
  • documentation/modules/auxiliary/admin/registry_security_descriptor.md

Verification Steps

  1. Start msfconsole
  2. Do: use auxiliary/admin/registry_security_descriptor
  3. Do: run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key>
  4. Verify the registry key security descriptor is displayed
  5. Do: run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key> file=<file path>
  6. Verify the registry key security descriptor is saved to the file
  7. Do: run verbose=true rhost=<host> smbuser=<username> smbpass=<password> key=<registry key> action=write sd=<security descriptor as a hex string>
  8. Verify the security descriptor is correctly set on the given registry key
  9. Do: run verbose=true rhost=<host> smbuser=<username> smbpass=<password> file=<file path>
  10. Verify the security descriptor taken from the file is correctly set on the given registry key

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

@cdelafuente-r7 cdelafuente-r7 added module docs blocked Blocked by one or more additional tasks labels Apr 19, 2024
@smcintyre-r7 smcintyre-r7 self-assigned this Apr 19, 2024
Comment on lines 126 to 131
def auxiliary_commands
{
'read' => 'Read a Windows registry security descriptor',
'write' => 'Write a Windows registry security descriptor'
}
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, absolutely, these are not necessary anymore. I also removed it from the template. Thank you!

@cdelafuente-r7 cdelafuente-r7 force-pushed the feat/mod/dcerpc/reg_security_descriptor branch from 83d19b4 to 3e351e8 Compare April 26, 2024 16:57
- This will bring in the GetKeySecurity and SetKeySecurity MS-RRP structures
- remove `#auxiliary_commands`, it is not necessary anymore
- move the connection logic to a separate method
- make sure the connection to Winreg is setup when using direct `read`
  and `write` commands
- fix wrong method call to `save_to_file`
@cdelafuente-r7 cdelafuente-r7 force-pushed the feat/mod/dcerpc/reg_security_descriptor branch from 3e351e8 to 6849e90 Compare April 30, 2024 18:59
@smcintyre-r7 smcintyre-r7 removed the blocked Blocked by one or more additional tasks label May 3, 2024
Comment on lines 112 to 117
case action.name
when 'READ'
cmd_read
when 'WRITE'
cmd_write
else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So prefixing these methods with cmd_ means they will be exposed as custom commands. Now when testing them without arguments, they seem to be working just fine, however they should also accept inline datastore options.

See:

metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) > write

[+] Security descriptor set for HKLM\SECURITY\Policy\PolEKList
metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) > write SECURITY_INFORMAITON=4
[-] Error while running command write: wrong number of arguments (given 1, expected 0)

Call stack:
/home/smcintyre/Repositories/metasploit-framework.pr/modules/auxiliary/admin/registry_security_descriptor.rb:145:in `cmd_write'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/msf/ui/console/module_action_commands.rb:40:in `method_missing'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/dispatcher_shell.rb:582:in `run_command'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/dispatcher_shell.rb:531:in `block in run_single'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/dispatcher_shell.rb:525:in `each'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/dispatcher_shell.rb:525:in `run_single'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/shell.rb:165:in `block in run'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/shell.rb:309:in `block in with_history_manager_context'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/shell/history_manager.rb:33:in `with_context'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/shell.rb:306:in `with_history_manager_context'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/rex/ui/text/shell.rb:133:in `run'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/metasploit/framework/command/console.rb:54:in `start'
/home/smcintyre/Repositories/metasploit-framework.pr/lib/metasploit/framework/command/base.rb:82:in `start'
./msfconsole:23:in `<main>'
metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) >

To fix this, a different prefix should be used. I recommend replacing cmd_ with action_. With that change in place, this work as expected:

metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) > read KEY=HKLM\\Security\\Policy

[*] Using existing session 1
[+] Raw security descriptor for HKLM\Security\Policy: 01000480000000000000000000000000140000000200340002000000000214003f000f00010100000000000512000000000218000000060001020000000000052000000020020000
[*] Auxiliary module execution completed
metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) > read KEY=HKLM\\Security\\Policy\\PolEKList

[*] Using existing session 1
[+] Raw security descriptor for HKLM\Security\Policy\PolEKList: 01000480000000000000000000000000140000000200340002000000000214003f000f00010100000000000512000000000218000000060001020000000000052000000020020000
[*] Auxiliary module execution completed
metasploit-framework.pr (S:1 J:0) auxiliary(admin/registry_security_descriptor) > 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Good catch!

Comment on lines 130 to 133
def cmd_read
do_connect unless @winreg

fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def cmd_read
do_connect unless @winreg
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?
def action_read
fail_with(Failure::BadConfig, 'Unknown registry key, please set the `KEY` option') if datastore['KEY'].blank?

Once this is renamed, you won't need to call do_connect yourself because everything will go through the main #run method. That'll also make sure that the session is disconnected in your ensure block.

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]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OptString.new('SD', [ false, 'Security Descriptor to write as a hex string' ], conditions: %w[ACTION == WRITE]),
OptString.new('SD', [ false, 'Security Descriptor to write as a hex string' ], conditions: %w[ACTION == WRITE], regex: /^([a-fA-F0-9]{2})+$/),

Copy link
Contributor

@smcintyre-r7 smcintyre-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, everything is looking good to me now. I was able to test a few cases and everything seems to be working as intended. I'll have this landed shortly.

Testing Output
metasploit-framework (S:0 J:0) auxiliary(admin/registry_security_descriptor) > read KEY='HKLM\SECURITY\Policy\PolEKList'
[*] Running module against 3.22.14.197

[+] 3.22.14.197:445 - Raw security descriptor for HKLM\SECURITY\Policy\PolEKList: 01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000
[*] Auxiliary module execution completed
metasploit-framework (S:0 J:0) auxiliary(admin/registry_security_descriptor) > read KEY='HKLM\SECURITY\Policy\PolEKList\DoesNotExist'
[*] Running module against 3.22.14.197

[-] 3.22.14.197:445 - Auxiliary failed: RubySMB::Dcerpc::Error::WinregError Error returned when opening subkey SECURITY\Policy\PolEKList\DoesNotExist: (0x00000002) ERROR_FILE_NOT_FOUND: The system cannot find the file specified.
[-] 3.22.14.197:445 - Call stack:
[-] 3.22.14.197:445 -   /home/smcintyre/.rvm/gems/ruby-3.2.3@metasploit-framework/gems/ruby_smb-3.3.7/lib/ruby_smb/dcerpc/winreg.rb:124:in `open_key'
[-] 3.22.14.197:445 -   /home/smcintyre/.rvm/gems/ruby-3.2.3@metasploit-framework/gems/ruby_smb-3.3.7/lib/ruby_smb/dcerpc/winreg.rb:466:in `get_key_security_descriptor'
[-] 3.22.14.197:445 -   /home/smcintyre/Repositories/metasploit-framework.pr/modules/auxiliary/admin/registry_security_descriptor.rb:133:in `action_read'
[-] 3.22.14.197:445 -   /home/smcintyre/Repositories/metasploit-framework.pr/modules/auxiliary/admin/registry_security_descriptor.rb:114:in `run'
[*] Auxiliary module execution completed
metasploit-framework (S:0 J:0) auxiliary(admin/registry_security_descriptor) > write SD=01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000
[*] Running module against 3.22.14.197

[-] 3.22.14.197:445 - Auxiliary aborted due to failure: unknown: Unable to set the security descriptor for HKLM\SECURITY\Policy\PolEKList: Error returned when setting the registry key: (0x00000005) ERROR_ACCESS_DENIED: Access is denied.
[*] Auxiliary module execution completed
metasploit-framework (S:0 J:0) auxiliary(admin/registry_security_descriptor) > write SD=01000480480000005800000000000000140000000200340002000000000214003f000f0001010000000000051200000000021800000006000102000000000005200000002002000001020000000000052000000020020000010100000000000512000000 SECuRITY_INFORMATION=4
[*] Running module against 3.22.14.197

[+] 3.22.14.197:445 - Security descriptor set for HKLM\SECURITY\Policy\PolEKList
[*] Auxiliary module execution completed
metasploit-framework (S:0 J:0) auxiliary(admin/registry_security_descriptor) >

@smcintyre-r7 smcintyre-r7 closed this pull request by merging all changes into rapid7:master in 733c014 May 13, 2024
@smcintyre-r7
Copy link
Contributor

Release Notes

This adds a module to read and write the security descriptor of Windows registry keys.

@smcintyre-r7 smcintyre-r7 added the rn-modules release notes for new or majorly enhanced modules label May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

None yet

3 participants